Compare commits
282 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f72021075 | ||
|
|
846037073b | ||
|
|
f0b55886b2 | ||
|
|
165d386436 | ||
|
|
a07e0f2a99 | ||
|
|
bc172346e0 | ||
|
|
5801ed4f15 | ||
|
|
e8c5a0c0bb | ||
|
|
94b74ee948 | ||
|
|
1bfacab88d | ||
|
|
704e7d011c | ||
|
|
3a4ae9a716 | ||
|
|
5ddc9d94d6 | ||
|
|
159708d829 | ||
|
|
5753cdab1a | ||
|
|
d4ea1261eb | ||
|
|
7e3ac0a761 | ||
|
|
76494c3e3d | ||
|
|
dfbc8acd9e | ||
|
|
158d33db5a | ||
|
|
4b11769895 | ||
|
|
4da96dd0b5 | ||
|
|
d9bfb9e200 | ||
|
|
f088e6d1bb | ||
|
|
ca665ad3d1 | ||
|
|
6ed9082e69 | ||
|
|
5332dd3482 | ||
|
|
a15f63621e | ||
|
|
e4b5f081bd | ||
|
|
5fab0bcdaa | ||
|
|
5c1b23f30e | ||
|
|
8f720e11de | ||
|
|
3c2cd5d599 | ||
|
|
8df1e70c0b | ||
|
|
3833a36693 | ||
|
|
38fd1e6dcb | ||
|
|
5fa4cd03de | ||
|
|
d6c0cdd231 | ||
|
|
c38843d9c9 | ||
|
|
a6a5df963f | ||
|
|
b60960d955 | ||
|
|
0adb80a9ed | ||
|
|
f591433118 | ||
|
|
5a897a34c2 | ||
|
|
138423de4a | ||
|
|
1d9f9c4487 | ||
|
|
82f71a6c91 | ||
|
|
0c85299efc | ||
|
|
50195aae1d | ||
|
|
586425bc2d | ||
|
|
b0bde6b652 | ||
|
|
be2369c64c | ||
|
|
c2cf68cab6 | ||
|
|
f7d1863615 | ||
|
|
0bb0aee6cb | ||
|
|
b392e019f3 | ||
|
|
8eb5fa7394 | ||
|
|
c5c04db81a | ||
|
|
4056cfaa15 | ||
|
|
ba8b226d89 | ||
|
|
88df2edb95 | ||
|
|
b856cf2141 | ||
|
|
f4a2429a13 | ||
|
|
7d1f8ad4e7 | ||
|
|
82656db49d | ||
|
|
d6dac912dd | ||
|
|
207f9398b4 | ||
|
|
7b51a82de8 | ||
|
|
66f08bf0db | ||
|
|
90384e921f | ||
|
|
1ae7c2697c | ||
|
|
536143c1d7 | ||
|
|
6025950aab | ||
|
|
4d69940b96 | ||
|
|
b1f49cae13 | ||
|
|
80e9be5343 | ||
|
|
d6d6b76fa5 | ||
|
|
d18a352a82 | ||
|
|
5fbaabb47e | ||
|
|
83cc13b817 | ||
|
|
1679cda4c5 | ||
|
|
e5f11aafc1 | ||
|
|
f262c77b17 | ||
|
|
3ef00effc5 | ||
|
|
1ce13bea91 | ||
|
|
eaab366dcb | ||
|
|
784f06c415 | ||
|
|
4b07e80a8f | ||
|
|
9f7fac407d | ||
|
|
47b6668876 | ||
|
|
951977961b | ||
|
|
f069c3a595 | ||
|
|
b84194e8c7 | ||
|
|
e06e989aa5 | ||
|
|
ab75505437 | ||
|
|
e97663b58e | ||
|
|
a92f57a30c | ||
|
|
ebb9381e46 | ||
|
|
5fb441fb81 | ||
|
|
f3a00fe8a2 | ||
|
|
573494570c | ||
|
|
92392f5c9a | ||
|
|
8a634a0d95 | ||
|
|
23c5d48b5d | ||
|
|
f000b344dd | ||
|
|
42177e1ff2 | ||
|
|
091ca483e7 | ||
|
|
42ce4f8821 | ||
|
|
9a1781765b | ||
|
|
544b8181e5 | ||
|
|
82ea37ead9 | ||
|
|
882ef93084 | ||
|
|
881469ab7f | ||
|
|
d7834650ae | ||
|
|
20bf183a10 | ||
|
|
c990ac66da | ||
|
|
0964163a35 | ||
|
|
fc980b1bc9 | ||
|
|
e76c8a3ba7 | ||
|
|
5805290369 | ||
|
|
7dd9623929 | ||
|
|
95ac07e4de | ||
|
|
92cd463b34 | ||
|
|
6832546dca | ||
|
|
049042b134 | ||
|
|
6d2f2efe31 | ||
|
|
bcce4831e3 | ||
|
|
7fb3053135 | ||
|
|
00359a0fc8 | ||
|
|
ccf3e1237c | ||
|
|
e02f00fd41 | ||
|
|
e45e640f3c | ||
|
|
75e8015c43 | ||
|
|
2c52fcc156 | ||
|
|
dc5b51a41f | ||
|
|
d12cee4690 | ||
|
|
a74c4ac148 | ||
|
|
53e50a8107 | ||
|
|
e896ba94cc | ||
|
|
87ff990c73 | ||
|
|
e406162be2 | ||
|
|
2de4120f25 | ||
|
|
d8dc58a133 | ||
|
|
8684bffe97 | ||
|
|
a08513ade0 | ||
|
|
1a57e01e07 | ||
|
|
6d4faf19b8 | ||
|
|
96e6845e16 | ||
|
|
b33adeb708 | ||
|
|
ea0e294a74 | ||
|
|
2d878c2391 | ||
|
|
6dec867cd3 | ||
|
|
d8bd7b9366 | ||
|
|
b52e4c6dee | ||
|
|
21046af42f | ||
|
|
3cbe1d6ac8 | ||
|
|
b4b1a99a27 | ||
|
|
f5a2d481e3 | ||
|
|
da57a15852 | ||
|
|
9d0ac624c5 | ||
|
|
b8ccc80b87 | ||
|
|
27e2dac22e | ||
|
|
a4ec4e382d | ||
|
|
30df5faf64 | ||
|
|
0aa29d8a91 | ||
|
|
3ace986e4a | ||
|
|
064ab48eee | ||
|
|
12c1725ab1 | ||
|
|
ba2ddf4163 | ||
|
|
3d16384acd | ||
|
|
0f73626025 | ||
|
|
84fb44e519 | ||
|
|
aafe23396a | ||
|
|
51f270df67 | ||
|
|
e9c404de92 | ||
|
|
141bda151b | ||
|
|
e952380ce6 | ||
|
|
721f5dc469 | ||
|
|
434b17eefe | ||
|
|
af6a1c84ef | ||
|
|
a0ce447a1f | ||
|
|
f24145f407 | ||
|
|
11c173b2e4 | ||
|
|
aff816d10c | ||
|
|
e1acaa3bdb | ||
|
|
c63743ac51 | ||
|
|
6832d9bf46 | ||
|
|
4c3ccbc06f | ||
|
|
f82596c372 | ||
|
|
4921a6ab8d | ||
|
|
ef9c242a59 | ||
|
|
a83c9937a5 | ||
|
|
cfa3ad4d9e | ||
|
|
ffc9638ebb | ||
|
|
000534654d | ||
|
|
68e9358d02 | ||
|
|
37e3859f8f | ||
|
|
e79b940b0d | ||
|
|
d8dfe3f289 | ||
|
|
394c286ee5 | ||
|
|
307bd6942c | ||
|
|
148b53e862 | ||
|
|
5c8cb0a013 | ||
|
|
4d644e0584 | ||
|
|
dce9c8b3d1 | ||
|
|
b117ee6404 | ||
|
|
c3f783bf7e | ||
|
|
4c65a6eded | ||
|
|
c382cab922 | ||
|
|
199fd4ed61 | ||
|
|
f86d62fbf8 | ||
|
|
3ea82dc384 | ||
|
|
03ae5834ee | ||
|
|
e39b5c20ee | ||
|
|
d6e131eb6e | ||
|
|
1c36b5f142 | ||
|
|
827bd0b59f | ||
|
|
2dab057652 | ||
|
|
488fbc5b63 | ||
|
|
17f511d7a3 | ||
|
|
63e633c0ec | ||
|
|
f46448c236 | ||
|
|
43023be32d | ||
|
|
4811d51c5d | ||
|
|
821dabca3d | ||
|
|
587f4ebb50 | ||
|
|
0c0b25fcd1 | ||
|
|
bdf07d04d4 | ||
|
|
6936675eb9 | ||
|
|
c39bf4b802 | ||
|
|
5a43b1b091 | ||
|
|
3e039e033c | ||
|
|
6a2af83ea3 | ||
|
|
5a12df240b | ||
|
|
2ea7d91fc7 | ||
|
|
d9903e7398 | ||
|
|
39b69f27ee | ||
|
|
31a1d19b4e | ||
|
|
f4a923c3dc | ||
|
|
171ff7d1e4 | ||
|
|
5cfbf22b81 | ||
|
|
5a35ed5ea1 | ||
|
|
1978359f15 | ||
|
|
fef6543f1a | ||
|
|
b1a9200803 | ||
|
|
fada30868a | ||
|
|
8414e9485f | ||
|
|
f6d8d485bc | ||
|
|
6ea0d6c631 | ||
|
|
31c6c05c1e | ||
|
|
d855d695db | ||
|
|
922cc82029 | ||
|
|
80498378f2 | ||
|
|
51856865df | ||
|
|
d26dcca37e | ||
|
|
5ac02fcb2e | ||
|
|
110cd65779 | ||
|
|
67e665b619 | ||
|
|
d1c431c370 | ||
|
|
2167a82c73 | ||
|
|
d113d3bf4a | ||
|
|
b2206adae5 | ||
|
|
8075cce1b1 | ||
|
|
29e4c79f75 | ||
|
|
3b299d3345 | ||
|
|
7421fff380 | ||
|
|
694aad637b | ||
|
|
c8c7222e06 | ||
|
|
9c6e31ef41 | ||
|
|
6a8d5c0c6e | ||
|
|
96ca10396b | ||
|
|
61cef824e8 | ||
|
|
972517d32d | ||
|
|
217a03642a | ||
|
|
f14783b8cf | ||
|
|
4f75c6e37b | ||
|
|
4eb3b66a0e | ||
|
|
6b74d5faed | ||
|
|
10d72ec42c | ||
|
|
9eae4ef819 | ||
|
|
b3657e396f | ||
|
|
a69885d05f |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -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
|
||||
|
||||
6
AUTHORS
6
AUTHORS
@@ -1,2 +1,8 @@
|
||||
Slava Monich <slava.monich@jolla.com>
|
||||
Matti Lehtimäki <matti.lehtimaki@gmail.com>
|
||||
Franz-Josef Haider <franz.haider@jolla.com>
|
||||
Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
Andrew Branson <andrew.branson@jolla.com>
|
||||
Rinigus <rinigus.git@gmail.com>
|
||||
George Hopkins <george-hopkins@null.net>
|
||||
Bart Ribbers <bribbers@disroot.org>
|
||||
|
||||
10
LICENSE
10
LICENSE
@@ -1,5 +1,5 @@
|
||||
Copyright (C) 2018 Jolla Ltd.
|
||||
Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
Copyright (C) 2018-2021 Jolla Ltd.
|
||||
Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of BSD license as follows:
|
||||
|
||||
@@ -12,9 +12,9 @@ are met:
|
||||
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
|
||||
|
||||
143
Makefile
143
Makefile
@@ -1,16 +1,25 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
#
|
||||
# LIBGLIBUTIL_PATH can be defined to point to libglibutil root directory
|
||||
# for side-by-side build.
|
||||
#
|
||||
|
||||
.PHONY: clean all debug release test
|
||||
.PHONY: print_debug_so print_release_so
|
||||
.PHONY: print_debug_lib print_release_lib
|
||||
.PHONY: print_debug_lib print_release_lib print_coverage_lib
|
||||
.PHONY: print_debug_link print_release_link
|
||||
.PHONY: print_debug_path print_release_path
|
||||
|
||||
#
|
||||
# Required packages
|
||||
# Library version
|
||||
#
|
||||
|
||||
PKGS = libglibutil glib-2.0 gobject-2.0
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 1
|
||||
VERSION_RELEASE = 13
|
||||
|
||||
# Version for pkg-config
|
||||
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
|
||||
|
||||
#
|
||||
# Default target
|
||||
@@ -19,15 +28,34 @@ PKGS = libglibutil glib-2.0 gobject-2.0
|
||||
all: debug release pkgconfig
|
||||
|
||||
#
|
||||
# Library version
|
||||
# Required packages
|
||||
#
|
||||
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 0
|
||||
VERSION_RELEASE = 7
|
||||
PKGS = glib-2.0 gobject-2.0
|
||||
|
||||
# Version for pkg-config
|
||||
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
|
||||
ifeq ($(LIBGLIBUTIL_PATH),)
|
||||
|
||||
# Assume that libglibutil devel package is installed
|
||||
PKGS += libglibutil
|
||||
|
||||
else
|
||||
|
||||
# Side-by-side build
|
||||
INCLUDES += -I$(LIBGLIBUTIL_PATH)/include
|
||||
DEBUG_LIBS = -L$(LIBGLIBUTIL_PATH)/build/debug -lglibutil
|
||||
RELEASE_LIBS = -L$(LIBGLIBUTIL_PATH)/build/release -lglibutil
|
||||
DEBUG_DEPS = libglibutil_debug
|
||||
RELEASE_DEPS = libglibutil_release
|
||||
|
||||
.PHONY: libglibutil_debug libglibutil_release
|
||||
|
||||
libglibutil_debug:
|
||||
make -C $(LIBGLIBUTIL_PATH) debug
|
||||
|
||||
libglibutil_release:
|
||||
make -C $(LIBGLIBUTIL_PATH) release
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Library name
|
||||
@@ -47,27 +75,35 @@ LIB = $(LIB_NAME).a
|
||||
#
|
||||
|
||||
SRC = \
|
||||
gbinder_bridge.c \
|
||||
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 \
|
||||
gbinder_local_object.c \
|
||||
gbinder_local_reply.c \
|
||||
gbinder_local_request.c \
|
||||
gbinder_log.c \
|
||||
gbinder_proxy_object.c \
|
||||
gbinder_reader.c \
|
||||
gbinder_remote_object.c \
|
||||
gbinder_remote_reply.c \
|
||||
gbinder_remote_request.c \
|
||||
gbinder_rpc_protocol.c \
|
||||
gbinder_servicename.c \
|
||||
gbinder_servicepoll.c \
|
||||
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
|
||||
@@ -87,10 +123,11 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
STRIP ?= strip
|
||||
LD = $(CC)
|
||||
WARNINGS = -Wall -Wstrict-aliasing -Wunused-result
|
||||
INCLUDES = -I$(INCLUDE_DIR)
|
||||
INCLUDES += -I$(INCLUDE_DIR)
|
||||
BASE_FLAGS = -fPIC
|
||||
FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) \
|
||||
-MMD -MP $(shell pkg-config --cflags $(PKGS))
|
||||
@@ -100,16 +137,13 @@ 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
|
||||
|
||||
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
|
||||
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
|
||||
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_LIBS) $(DEBUG_FLAGS)
|
||||
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_LIBS) $(RELEASE_FLAGS)
|
||||
DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
|
||||
RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
|
||||
COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
|
||||
@@ -123,6 +157,16 @@ DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
|
||||
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
|
||||
COVERAGE_OBJS = $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
|
||||
|
||||
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)
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
@@ -135,25 +179,22 @@ endif
|
||||
endif
|
||||
|
||||
$(PKGCONFIG): | $(BUILD_DIR)
|
||||
$(DEBUG_OBJS) $(DEBUG_SO): | $(DEBUG_BUILD_DIR)
|
||||
$(RELEASE_OBJS) $(RELEASE_SO): | $(RELEASE_BUILD_DIR)
|
||||
$(DEBUG_OBJS) $(DEBUG_SO): | $(DEBUG_BUILD_DIR) $(DEBUG_DEPS)
|
||||
$(RELEASE_OBJS) $(RELEASE_SO): | $(RELEASE_BUILD_DIR) $(RELEASE_DEPS)
|
||||
$(COVERAGE_OBJS) $(COVERAGE_LIB): | $(COVERAGE_BUILD_DIR)
|
||||
|
||||
$(DEBUG_LINK): | $(DEBUG_LIB)
|
||||
$(RELEASE_LINK): | $(RELEASE_LIB)
|
||||
$(DEBUG_DEV_LINK): | $(DEBUG_LINK)
|
||||
$(RELEASE_DEV_LINK): | $(RELEASE_LINK)
|
||||
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
|
||||
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_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
|
||||
RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
|
||||
COVERAGE_LIB = $(COVERAGE_BUILD_DIR)/$(LIB)
|
||||
debug: $(DEBUG_SO) $(DEBUG_LINK) $(DEBUG_DEV_LINK)
|
||||
|
||||
debug: $(DEBUG_SO)
|
||||
|
||||
release: $(RELEASE_SO)
|
||||
release: $(RELEASE_SO) $(RELEASE_LINK) $(RELEASE_DEV_LINK)
|
||||
|
||||
debug_lib: $(DEBUG_LIB)
|
||||
|
||||
@@ -199,6 +240,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
|
||||
@@ -226,13 +268,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)
|
||||
@@ -243,12 +283,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 $@
|
||||
|
||||
$(PKGCONFIG): $(LIB_NAME).pc.in
|
||||
sed -e 's/\[version\]/'$(PCVERSION)/g $< > $@
|
||||
#
|
||||
# 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' -e 's|@libdir@|$(ABS_LIBDIR)|g' $< > $@
|
||||
|
||||
debian/%.install: debian/%.install.in
|
||||
sed 's|@LIBDIR@|$(LIBDIR)|g' $< > $@
|
||||
|
||||
#
|
||||
# Install
|
||||
@@ -260,12 +323,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)
|
||||
|
||||
|
||||
43
README
43
README
@@ -1 +1,44 @@
|
||||
GLib-style interface to binder (Android IPC mechanism)
|
||||
|
||||
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.
|
||||
|
||||
379
debian/changelog
vendored
379
debian/changelog
vendored
@@ -1,3 +1,382 @@
|
||||
libgbinder (1.1.13) unstable; urgency=low
|
||||
|
||||
* Added gbinder_writer_strdup()
|
||||
* Added gbinder_writer_append_hidl_string_copy()
|
||||
* Dropped pkgconfig requirement for devel package
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 28 Oct 2021 14:31:01 +0300
|
||||
|
||||
libgbinder (1.1.12) unstable; urgency=low
|
||||
|
||||
* Added binder-call test tool
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 24 Sep 2021 16:46:05 +0300
|
||||
|
||||
libgbinder (1.1.11) unstable; urgency=low
|
||||
|
||||
* Fix potential deadlock in gbinder_ipc_looper_free()
|
||||
* Fix occasional crashes in pthread_setname_np()
|
||||
* Fix unit tests on some musl-based systems
|
||||
* Make unit tests comptible with glib < 2.36
|
||||
* Bump libglibutil requirement for debian build
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 02 Sep 2021 12:32:39 +0300
|
||||
|
||||
libgbinder (1.1.10) unstable; urgency=low
|
||||
|
||||
* Release dead binder nodes
|
||||
* Use gutil_memdup() instead of g_memdup()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 10 May 2021 02:36:43 +0300
|
||||
|
||||
libgbinder (1.1.9) unstable; urgency=low
|
||||
|
||||
* Include definition of _IOC_SIZE
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 20 Apr 2021 12:52:41 +0300
|
||||
|
||||
libgbinder (1.1.8) unstable; urgency=low
|
||||
|
||||
* Handle out-of-range transaction codes
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 16 Apr 2021 19:11:14 +0300
|
||||
|
||||
libgbinder (1.1.7) unstable; urgency=low
|
||||
|
||||
* Dropped use of g_main_context_invoke_full()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 31 Mar 2021 23:10:37 +0300
|
||||
|
||||
libgbinder (1.1.6) unstable; urgency=low
|
||||
|
||||
* Implemented support for passing object over the bridge
|
||||
* Retry service name registration
|
||||
* Wait for completion of the reply
|
||||
* Fixed death handling by GBinderBridge
|
||||
* Added gbinder_bridge_new2()
|
||||
* Added -s option to binder-bridge
|
||||
* Fixed invalid slice deallocation
|
||||
* Made unit tests more reliable
|
||||
* Make sure that libgbinder doesn't block on exit
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 02 Mar 2021 18:18:03 +0200
|
||||
|
||||
libgbinder (1.1.5) unstable; urgency=low
|
||||
|
||||
* Fixed gbinder_remote_reply_copy_to_local() for empty replies
|
||||
* Improved binder simulation
|
||||
* Added GBinderBridge object
|
||||
* Added proxy_object and bridge unit tests
|
||||
* Added binder-bridge to libgbinder-tools package
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 29 Jan 2021 04:00:09 +0200
|
||||
|
||||
libgbinder (1.1.4) unstable; urgency=low
|
||||
|
||||
* Fixed a threading issue
|
||||
* Decode NULL object reference
|
||||
* Added new basic HIDL types
|
||||
* Set TF_ACCEPT_FDS transaction flag
|
||||
* Added servicemanager_hidl unit test
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 21 Jan 2021 03:34:45 +0200
|
||||
|
||||
libgbinder (1.1.3) unstable; urgency=low
|
||||
|
||||
* Improved unit test coverage
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 23 Dec 2020 21:48:27 +0200
|
||||
|
||||
libgbinder (1.1.2) unstable; urgency=low
|
||||
|
||||
* Fixed random unit text failures
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 23 Dec 2020 12:39:22 +0200
|
||||
|
||||
libgbinder (1.1.1) unstable; urgency=low
|
||||
|
||||
* Handle corner cases for abandoned loopers
|
||||
* Pass 0x0f priority to aidl2 service list request.
|
||||
* Improved binder simulation for unit tests
|
||||
* Added servicemanager_aidl unit test
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 22 Dec 2020 15:15:10 +0200
|
||||
|
||||
libgbinder (1.1.0) unstable; urgency=low
|
||||
|
||||
* Made RPC protocol configurable per binder device
|
||||
* Made service managers configurable per binder device
|
||||
* Added support for multiple config files
|
||||
* Added "aidl2" variant of service manager
|
||||
* Added "aidl2" variant of RPC protocol
|
||||
* Added support for API level presets
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 04 Dec 2020 13:47:26 +0200
|
||||
|
||||
libgbinder (1.0.47) unstable; urgency=low
|
||||
|
||||
* Make library executable on RPM based systems
|
||||
|
||||
-- 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
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 02 Apr 2020 00:12:01 +0300
|
||||
|
||||
libgbinder (1.0.37) unstable; urgency=low
|
||||
|
||||
* Allow side-by-side linking with libglibutil
|
||||
* Fixed compilation warnings
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 17 Mar 2020 20:15:11 +0200
|
||||
|
||||
libgbinder (1.0.36) unstable; urgency=low
|
||||
|
||||
* Allow overwriting CC
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 16 Mar 2020 16:15:24 +0200
|
||||
|
||||
libgbinder (1.0.35) unstable; urgency=low
|
||||
|
||||
* Added binder-ping example
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 25 Feb 2020 13:58:19 +0200
|
||||
|
||||
libgbinder (1.0.34) unstable; urgency=low
|
||||
|
||||
* Better cleanup on unload to prevent crashes on exit
|
||||
* Fixed rare memory leak in GBinderServiceManager
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 16 Dec 2019 12:25:56 +0200
|
||||
|
||||
libgbinder (1.0.33) unstable; urgency=low
|
||||
|
||||
* Reuse loopers
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 13 Sep 2019 15:57:47 +0300
|
||||
|
||||
libgbinder (1.0.32) unstable; urgency=low
|
||||
|
||||
* Refuse to perform transactions with dead objects
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 17 May 2019 15:57:30 +0300
|
||||
|
||||
libgbinder (1.0.31) unstable; urgency=low
|
||||
|
||||
* Invalidate handle when remote object dies
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 13 May 2019 18:05:35 +0300
|
||||
|
||||
libgbinder (1.0.30) unstable; urgency=low
|
||||
|
||||
* Added gbinder_local_object_new()
|
||||
* Added gbinder_remote_object_ipc()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 20 Feb 2019 11:59:08 +0200
|
||||
|
||||
libgbinder (1.0.29) unstable; urgency=low
|
||||
|
||||
* Added gbinder_servicemanager_new_local_object2()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 14 Feb 2019 18:17:53 +0300
|
||||
|
||||
libgbinder (1.0.28) unstable; urgency=low
|
||||
|
||||
* Set type for local nulls to BINDER_TYPE_WEAK_BINDER
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 29 Jan 2019 02:49:10 +0200
|
||||
|
||||
libgbinder (1.0.27) unstable; urgency=low
|
||||
|
||||
* Fixed outgoing oneway transactions
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 24 Jan 2019 18:55:16 +0200
|
||||
|
||||
libgbinder (1.0.26) unstable; urgency=low
|
||||
|
||||
* Implement PING and INTERFACE transactions
|
||||
* Add GBinderServiceName API
|
||||
* Added gbinder_reader_read_string16_utf16()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 23 Jan 2019 17:43:41 +0200
|
||||
|
||||
libgbinder (1.0.25) unstable; urgency=low
|
||||
|
||||
* Added ServiceManager presence API
|
||||
|
||||
gbinder_servicemanager_wait()
|
||||
gbinder_servicemanager_is_present()
|
||||
gbinder_servicemanager_add_presence_handler()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 22 Jan 2019 16:03:57 +0200
|
||||
|
||||
libgbinder (1.0.24) unstable; urgency=low
|
||||
|
||||
* Revert "Make sure NULL objects are passed as BINDER_TYPE_WEAK_HANDLE"
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 18 Jan 2019 21:36:32 +0200
|
||||
|
||||
libgbinder (1.0.23) unstable; urgency=low
|
||||
|
||||
* Added gbinder_reader_read_hidl_string_c()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 15 Jan 2019 15:16:41 +0200
|
||||
|
||||
libgbinder (1.0.22) unstable; urgency=low
|
||||
|
||||
* Added gbinder_client_interface()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 10 Jan 2019 14:09:44 +0300
|
||||
|
||||
libgbinder (1.0.21) unstable; urgency=low
|
||||
|
||||
* Added API to overwrite prefix length
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 18 Dec 2018 14:05:14 +0200
|
||||
|
||||
libgbinder (1.0.20) unstable; urgency=low
|
||||
|
||||
* Added API to block incoming requests
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 17 Dec 2018 16:06:43 +0200
|
||||
|
||||
libgbinder (1.0.19) unstable; urgency=low
|
||||
|
||||
* Added GBinderWriter memory allocation and cleanup API
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 14 Dec 2018 16:27:51 +0200
|
||||
|
||||
libgbinder (1.0.18) unstable; urgency=low
|
||||
|
||||
* Implemented support for file descritors
|
||||
* Allow GBinderClient without RPC header
|
||||
* Added binder-dump test
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 10 Dec 2018 13:17:22 +0200
|
||||
|
||||
libgbinder (1.0.17) unstable; urgency=low
|
||||
|
||||
* Added gbinder_writer_append_string16_utf16()
|
||||
* Added gbinder_reader_read_nullable_string16_utf16()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Fri, 07 Dec 2018 02:54:07 +0200
|
||||
|
||||
libgbinder (1.0.16) unstable; urgency=low
|
||||
|
||||
* Added GBinderHidlVec and GBinderHidlString types
|
||||
* Added gbinder_reader_copy()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Thu, 06 Dec 2018 19:03:32 +0200
|
||||
|
||||
libgbinder (1.0.15) unstable; urgency=low
|
||||
|
||||
* Implemented service polling for old servicemanager
|
||||
* Added new tests and improved coverage for existing ones
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 05 Dec 2018 12:11:34 +0200
|
||||
|
||||
libgbinder (1.0.14) unstable; urgency=low
|
||||
|
||||
* Changed bool padding from 0xff to 0x00
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 27 Nov 2018 17:20:18 +0200
|
||||
|
||||
libgbinder (1.0.13) unstable; urgency=low
|
||||
|
||||
* Support for service registration notifications
|
||||
* Make sure looper is started before gbinder_ipc_looper_new() returns
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Sat, 17 Nov 2018 01:52:28 +0200
|
||||
|
||||
libgbinder (1.0.12) unstable; urgency=low
|
||||
|
||||
* Add byte array reader and writer
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 31 Oct 2018 17:04:38 +0300
|
||||
|
||||
libgbinder (1.0.11) unstable; urgency=low
|
||||
|
||||
* Use BINDER_TYPE_WEAK_HANDLE for NULL objects
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 24 Oct 2018 18:57:28 +0300
|
||||
|
||||
libgbinder (1.0.10) unstable; urgency=low
|
||||
|
||||
* Fixed dependencies for unit tests
|
||||
* Plugged memory leak in unit_reader
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Wed, 10 Oct 2018 14:44:44 +0300
|
||||
|
||||
libgbinder (1.0.9) unstable; urgency=low
|
||||
|
||||
* Respect strong refs to GBinderLocalObject
|
||||
* Added gbinder_reader_read_hidl_struct macro
|
||||
* Added gbinder_reader_read_hidl_type_vec macro
|
||||
* Added gbinder_reader_read_hidl_byte_vec macro
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Mon, 08 Oct 2018 11:41:33 +0300
|
||||
|
||||
libgbinder (1.0.8) unstable; urgency=low
|
||||
|
||||
* Added gbinder_writer_append_hidl_vec()
|
||||
* Added Added gbinder_reader_read_hidl_vec()
|
||||
|
||||
-- Slava Monich <slava.monich@jolla.com> Tue, 25 Sep 2018 01:08:54 +0300
|
||||
|
||||
libgbinder (1.0.7) unstable; urgency=low
|
||||
|
||||
* Added gbinder_remote_request_copy_to_local()
|
||||
|
||||
10
debian/control
vendored
10
debian/control
vendored
@@ -2,13 +2,13 @@ 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.29)
|
||||
Build-Depends: debhelper (>= 8.1.3), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.52), flex, bison
|
||||
Standards-Version: 3.8.4
|
||||
|
||||
Package: libgbinder
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Depends: libglibutil (>= 1.0.29), ${shlibs:Depends}, ${misc:Depends}
|
||||
Depends: libglibutil (>= 1.0.52), ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Binder client library
|
||||
|
||||
Package: libgbinder-dev
|
||||
@@ -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
|
||||
|
||||
10
debian/copyright
vendored
10
debian/copyright
vendored
@@ -1,5 +1,5 @@
|
||||
Copyright (C) 2018 Jolla Ltd.
|
||||
Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
Copyright (C) 2018-2021 Jolla Ltd.
|
||||
Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
|
||||
|
||||
You may use this file under the terms of BSD license as follows:
|
||||
|
||||
@@ -12,9 +12,9 @@ are met:
|
||||
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
|
||||
|
||||
3
debian/libgbinder-dev.install
vendored
3
debian/libgbinder-dev.install
vendored
@@ -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
3
debian/libgbinder-dev.install.in
vendored
Normal 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
1
debian/libgbinder-tools.install
vendored
Normal file
@@ -0,0 +1 @@
|
||||
debian/tmp/usr/bin/* usr/bin
|
||||
1
debian/libgbinder.install
vendored
1
debian/libgbinder.install
vendored
@@ -1 +0,0 @@
|
||||
debian/tmp/usr/lib/libgbinder.so.* usr/lib
|
||||
1
debian/libgbinder.install.in
vendored
Normal file
1
debian/libgbinder.install.in
vendored
Normal file
@@ -0,0 +1 @@
|
||||
debian/tmp/@LIBDIR@/libgbinder.so.* @LIBDIR@
|
||||
15
debian/rules
vendored
15
debian/rules
vendored
@@ -4,8 +4,21 @@
|
||||
# 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-bridge release
|
||||
dh_auto_build -- -C test/binder-call release
|
||||
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-bridge
|
||||
dh_auto_install -- -C test/binder-call
|
||||
dh_auto_install -- -C test/binder-list
|
||||
dh_auto_install -- -C test/binder-ping
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
/* Convenience header to pull in everything at once */
|
||||
|
||||
#include "gbinder_bridge.h"
|
||||
#include "gbinder_buffer.h"
|
||||
#include "gbinder_client.h"
|
||||
#include "gbinder_local_object.h"
|
||||
@@ -44,6 +45,7 @@
|
||||
#include "gbinder_remote_object.h"
|
||||
#include "gbinder_remote_reply.h"
|
||||
#include "gbinder_remote_request.h"
|
||||
#include "gbinder_servicename.h"
|
||||
#include "gbinder_servicemanager.h"
|
||||
#include "gbinder_writer.h"
|
||||
|
||||
|
||||
89
include/gbinder_bridge.h
Normal file
89
include/gbinder_bridge.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 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_BRIDGE_H
|
||||
#define GBINDER_BRIDGE_H
|
||||
|
||||
#include "gbinder_types.h"
|
||||
|
||||
/* Since 1.1.5 */
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* A binder bridge object.
|
||||
*
|
||||
* For example, bridging "foobar" with interfaces ["example@1.0::IFoo",
|
||||
* "example@1.0::IBar"] would:
|
||||
*
|
||||
* 1. Watch "example@1.0::IFoo/foobar" and "example@1.0::IBar/foobar" on dest
|
||||
* 2. When those names appears, register objects with the same name on src
|
||||
* 3. Pass calls coming from src to the dest objects and replies in the
|
||||
* opposite direction
|
||||
* 4. When dest objects disappear, remove the corresponding bridging objects
|
||||
* from src
|
||||
*
|
||||
* and so on.
|
||||
*/
|
||||
|
||||
GBinderBridge*
|
||||
gbinder_bridge_new(
|
||||
const char* name,
|
||||
const char* const* ifaces,
|
||||
GBinderServiceManager* src,
|
||||
GBinderServiceManager* dest) /* Since 1.1.5 */
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GBinderBridge*
|
||||
gbinder_bridge_new2(
|
||||
const char* src_name,
|
||||
const char* dest_name,
|
||||
const char* const* ifaces,
|
||||
GBinderServiceManager* src,
|
||||
GBinderServiceManager* dest) /* Since 1.1.6 */
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
void
|
||||
gbinder_bridge_free(
|
||||
GBinderBridge* bridge); /* Since 1.1.5 */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GBINDER_BRIDGE_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -58,10 +69,24 @@ void
|
||||
gbinder_client_unref(
|
||||
GBinderClient* client);
|
||||
|
||||
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
194
include/gbinder_eventloop.h
Normal 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:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* 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:
|
||||
*
|
||||
@@ -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
|
||||
@@ -37,6 +37,14 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_local_object_new(
|
||||
GBinderIpc* ipc,
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc handler,
|
||||
void* user_data) /* Since 1.0.30 */
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_local_object_ref(
|
||||
GBinderLocalObject* obj);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* 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:
|
||||
*
|
||||
@@ -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
|
||||
@@ -53,7 +53,7 @@ struct gbinder_reader {
|
||||
|
||||
gboolean
|
||||
gbinder_reader_at_end(
|
||||
GBinderReader* reader);
|
||||
const GBinderReader* reader);
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_byte(
|
||||
@@ -95,6 +95,15 @@ gbinder_reader_read_double(
|
||||
GBinderReader* reader,
|
||||
gdouble* value);
|
||||
|
||||
int
|
||||
gbinder_reader_read_fd(
|
||||
GBinderReader* reader); /* Since 1.0.18 */
|
||||
|
||||
int
|
||||
gbinder_reader_read_dup_fd(
|
||||
GBinderReader* reader) /* Since 1.0.18 */
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_nullable_object(
|
||||
GBinderReader* reader,
|
||||
@@ -113,11 +122,43 @@ gbinder_reader_read_buffer(
|
||||
GBinderReader* reader)
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
const void*
|
||||
gbinder_reader_read_hidl_struct1(
|
||||
GBinderReader* reader,
|
||||
gsize size); /* Since 1.0.9 */
|
||||
|
||||
#define gbinder_reader_read_hidl_struct(reader,type) \
|
||||
((const type*)gbinder_reader_read_hidl_struct1(reader, sizeof(type)))
|
||||
|
||||
const void*
|
||||
gbinder_reader_read_hidl_vec(
|
||||
GBinderReader* reader,
|
||||
gsize* count,
|
||||
gsize* elemsize);
|
||||
|
||||
const void*
|
||||
gbinder_reader_read_hidl_vec1(
|
||||
GBinderReader* reader,
|
||||
gsize* count,
|
||||
guint expected_elemsize); /* Since 1.0.9 */
|
||||
|
||||
#define gbinder_reader_read_hidl_type_vec(reader,type,count) \
|
||||
((const type*)gbinder_reader_read_hidl_vec1(reader, count, sizeof(type)))
|
||||
#define gbinder_reader_read_hidl_byte_vec(reader,count) /* vec<uint8_t> */ \
|
||||
gbinder_reader_read_hidl_type_vec(reader,guint8,count)
|
||||
|
||||
char*
|
||||
gbinder_reader_read_hidl_string(
|
||||
GBinderReader* reader)
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
const char*
|
||||
gbinder_reader_read_hidl_string_c(
|
||||
GBinderReader* reader); /* Since 1.0.23 */
|
||||
|
||||
#define gbinder_reader_skip_hidl_string(reader) \
|
||||
(gbinder_reader_read_hidl_string_c(reader) != NULL)
|
||||
|
||||
char**
|
||||
gbinder_reader_read_hidl_string_vec(
|
||||
GBinderReader* reader);
|
||||
@@ -140,17 +181,38 @@ gbinder_reader_read_nullable_string16(
|
||||
GBinderReader* reader,
|
||||
char** out);
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_nullable_string16_utf16(
|
||||
GBinderReader* reader,
|
||||
const gunichar2** out,
|
||||
gsize* len); /* Since 1.0.17 */
|
||||
|
||||
const gunichar2*
|
||||
gbinder_reader_read_string16_utf16(
|
||||
GBinderReader* reader,
|
||||
gsize* len); /* Since 1.0.26 */
|
||||
|
||||
gboolean
|
||||
gbinder_reader_skip_string16(
|
||||
GBinderReader* reader);
|
||||
|
||||
const void*
|
||||
gbinder_reader_read_byte_array(
|
||||
GBinderReader* reader,
|
||||
gsize* len); /* Since 1.0.12 */
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_read(
|
||||
GBinderReader* reader);
|
||||
const GBinderReader* reader);
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_remaining(
|
||||
GBinderReader* reader);
|
||||
const GBinderReader* reader);
|
||||
|
||||
void
|
||||
gbinder_reader_copy(
|
||||
GBinderReader* dest,
|
||||
const GBinderReader* src); /* Since 1.0.16 */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* 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:
|
||||
*
|
||||
@@ -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
|
||||
@@ -51,6 +51,10 @@ void
|
||||
gbinder_remote_object_unref(
|
||||
GBinderRemoteObject* obj);
|
||||
|
||||
GBinderIpc*
|
||||
gbinder_remote_object_ipc(
|
||||
GBinderRemoteObject* obj); /* Since 1.0.30 */
|
||||
|
||||
gboolean
|
||||
gbinder_remote_object_is_dead(
|
||||
GBinderRemoteObject* obj);
|
||||
|
||||
@@ -67,6 +67,16 @@ gbinder_remote_request_copy_to_local(
|
||||
GBinderRemoteRequest* req) /* since 1.0.6 */
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
void
|
||||
gbinder_remote_request_block(
|
||||
GBinderRemoteRequest* req); /* Since 1.0.20 */
|
||||
|
||||
void
|
||||
gbinder_remote_request_complete(
|
||||
GBinderRemoteRequest* req,
|
||||
GBinderLocalReply* reply,
|
||||
int status); /* Since 1.0.20 */
|
||||
|
||||
/* Convenience function to decode requests with just one data item */
|
||||
|
||||
gboolean
|
||||
|
||||
@@ -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
|
||||
@@ -37,6 +37,12 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef
|
||||
void
|
||||
(*GBinderServiceManagerFunc)(
|
||||
GBinderServiceManager* sm,
|
||||
void* user_data);
|
||||
|
||||
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
|
||||
* list, otherwise the caller will deallocate it. */
|
||||
typedef
|
||||
@@ -61,24 +67,42 @@ void
|
||||
int status,
|
||||
void* user_data);
|
||||
|
||||
typedef
|
||||
void
|
||||
(*GBinderServiceManagerRegistrationFunc)(
|
||||
GBinderServiceManager* sm,
|
||||
const char* name,
|
||||
void* user_data);
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_servicemanager_new(
|
||||
const char* dev);
|
||||
|
||||
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(
|
||||
GBinderServiceManager* sm,
|
||||
const char* iface,
|
||||
GBinderLocalTransactFunc handler,
|
||||
void* user_data);
|
||||
void* user_data)
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_servicemanager_new_local_object2(
|
||||
GBinderServiceManager* sm,
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc handler,
|
||||
void* user_data) /* Since 1.0.29 */
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_servicemanager_ref(
|
||||
@@ -88,6 +112,15 @@ void
|
||||
gbinder_servicemanager_unref(
|
||||
GBinderServiceManager* sm);
|
||||
|
||||
gboolean
|
||||
gbinder_servicemanager_is_present(
|
||||
GBinderServiceManager* sm); /* Since 1.0.25 */
|
||||
|
||||
gboolean
|
||||
gbinder_servicemanager_wait(
|
||||
GBinderServiceManager* sm,
|
||||
long max_wait_ms); /* Since 1.0.25 */
|
||||
|
||||
gulong
|
||||
gbinder_servicemanager_list(
|
||||
GBinderServiceManager* sm,
|
||||
@@ -96,7 +129,9 @@ gbinder_servicemanager_list(
|
||||
|
||||
char**
|
||||
gbinder_servicemanager_list_sync(
|
||||
GBinderServiceManager* sm);
|
||||
GBinderServiceManager* sm)
|
||||
G_GNUC_WARN_UNUSED_RESULT
|
||||
G_GNUC_MALLOC;
|
||||
|
||||
gulong
|
||||
gbinder_servicemanager_get_service(
|
||||
@@ -130,6 +165,33 @@ gbinder_servicemanager_cancel(
|
||||
GBinderServiceManager* sm,
|
||||
gulong id);
|
||||
|
||||
gulong
|
||||
gbinder_servicemanager_add_presence_handler(
|
||||
GBinderServiceManager* sm,
|
||||
GBinderServiceManagerFunc func,
|
||||
void* user_data); /* Since 1.0.25 */
|
||||
|
||||
gulong
|
||||
gbinder_servicemanager_add_registration_handler(
|
||||
GBinderServiceManager* sm,
|
||||
const char* name,
|
||||
GBinderServiceManagerRegistrationFunc func,
|
||||
void* user_data); /* Since 1.0.13 */
|
||||
|
||||
void
|
||||
gbinder_servicemanager_remove_handler(
|
||||
GBinderServiceManager* sm,
|
||||
gulong id); /* Since 1.0.13 */
|
||||
|
||||
void
|
||||
gbinder_servicemanager_remove_handlers(
|
||||
GBinderServiceManager* sm,
|
||||
gulong* ids,
|
||||
guint count); /* Since 1.0.25 */
|
||||
|
||||
#define gbinder_servicemanager_remove_all_handlers(r,ids) \
|
||||
gbinder_servicemanager_remove_handlers(sm, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GBINDER_SERVICEMANAGER_H */
|
||||
|
||||
70
include/gbinder_servicename.h
Normal file
70
include/gbinder_servicename.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Jolla Ltd.
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#ifndef GBINDER_SERVICENAME_H
|
||||
#define GBINDER_SERVICENAME_H
|
||||
|
||||
#include "gbinder_types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* Since 1.0.26 */
|
||||
|
||||
struct gbinder_servicename {
|
||||
const char* name;
|
||||
};
|
||||
|
||||
GBinderServiceName*
|
||||
gbinder_servicename_new(
|
||||
GBinderServiceManager* sm,
|
||||
GBinderLocalObject* object,
|
||||
const char* name);
|
||||
|
||||
GBinderServiceName*
|
||||
gbinder_servicename_ref(
|
||||
GBinderServiceName* name);
|
||||
|
||||
void
|
||||
gbinder_servicename_unref(
|
||||
GBinderServiceName* name);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GBINDER_SERVICENAME_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -59,8 +59,10 @@ G_BEGIN_DECLS
|
||||
* 6. Reader parses the data coming with RemoteRequest and RemoteReply
|
||||
*/
|
||||
|
||||
typedef struct gbinder_bridge GBinderBridge; /* Since 1.1.5 */
|
||||
typedef struct gbinder_buffer GBinderBuffer;
|
||||
typedef struct gbinder_client GBinderClient;
|
||||
typedef struct gbinder_ipc GBinderIpc;
|
||||
typedef struct gbinder_local_object GBinderLocalObject;
|
||||
typedef struct gbinder_local_reply GBinderLocalReply;
|
||||
typedef struct gbinder_local_request GBinderLocalRequest;
|
||||
@@ -68,10 +70,80 @@ typedef struct gbinder_reader GBinderReader;
|
||||
typedef struct gbinder_remote_object GBinderRemoteObject;
|
||||
typedef struct gbinder_remote_reply GBinderRemoteReply;
|
||||
typedef struct gbinder_remote_request GBinderRemoteRequest;
|
||||
typedef struct gbinder_servicename GBinderServiceName;
|
||||
typedef struct gbinder_servicemanager GBinderServiceManager;
|
||||
typedef struct gbinder_writer GBinderWriter;
|
||||
typedef struct gbinder_parent GBinderParent;
|
||||
|
||||
/* Basic HIDL types */
|
||||
|
||||
#define GBINDER_ALIGNED(x) __attribute__ ((aligned(x)))
|
||||
|
||||
typedef struct gbinder_hidl_vec {
|
||||
union {
|
||||
guint64 value;
|
||||
const void* ptr;
|
||||
} data;
|
||||
guint32 count;
|
||||
guint8 owns_buffer;
|
||||
guint8 pad[3];
|
||||
} GBinderHidlVec;
|
||||
|
||||
#define GBINDER_HIDL_VEC_BUFFER_OFFSET (0)
|
||||
G_STATIC_ASSERT(sizeof(GBinderHidlVec) == 16);
|
||||
|
||||
typedef struct gbinder_hidl_string {
|
||||
union {
|
||||
guint64 value;
|
||||
const char* str;
|
||||
} data;
|
||||
guint32 len;
|
||||
guint8 owns_buffer;
|
||||
guint8 pad[3];
|
||||
} GBinderHidlString;
|
||||
|
||||
#define GBINDER_HIDL_STRING_BUFFER_OFFSET (0)
|
||||
G_STATIC_ASSERT(sizeof(GBinderHidlString) == 16);
|
||||
|
||||
typedef struct gbinder_fds {
|
||||
guint32 version GBINDER_ALIGNED(4);
|
||||
guint32 num_fds GBINDER_ALIGNED(4);
|
||||
guint32 num_ints GBINDER_ALIGNED(4);
|
||||
} GBINDER_ALIGNED(4) GBinderFds; /* Since 1.1.4 */
|
||||
|
||||
/* Actual fds immediately follow GBinderFds: */
|
||||
#define gbinder_fds_get_fd(fds,i) (((const int*)((fds) + 1))[i])
|
||||
|
||||
#define GBINDER_HIDL_FDS_VERSION (12)
|
||||
G_STATIC_ASSERT(sizeof(GBinderFds) == GBINDER_HIDL_FDS_VERSION);
|
||||
|
||||
typedef struct gbinder_hidl_handle {
|
||||
union {
|
||||
guint64 value;
|
||||
const GBinderFds* fds;
|
||||
} data;
|
||||
guint8 owns_handle;
|
||||
guint8 pad[7];
|
||||
} GBinderHidlHandle; /* Since 1.1.4 */
|
||||
|
||||
#define GBINDER_HIDL_HANDLE_VALUE_OFFSET (0)
|
||||
G_STATIC_ASSERT(sizeof(GBinderHidlHandle) == 16);
|
||||
|
||||
typedef struct gbinder_hidl_memory {
|
||||
union {
|
||||
guint64 value;
|
||||
const GBinderFds* fds;
|
||||
} data;
|
||||
guint8 owns_buffer;
|
||||
guint8 pad[7];
|
||||
guint64 size;
|
||||
GBinderHidlString name;
|
||||
} GBinderHidlMemory; /* Since 1.1.4 */
|
||||
|
||||
#define GBINDER_HIDL_MEMORY_PTR_OFFSET (0)
|
||||
#define GBINDER_HIDL_MEMORY_NAME_OFFSET (24)
|
||||
G_STATIC_ASSERT(sizeof(GBinderHidlMemory) == 40);
|
||||
|
||||
/*
|
||||
* Each RPC call is identified by the interface name returned
|
||||
* by gbinder_remote_request_interface() the transaction code.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -86,6 +86,12 @@ gbinder_writer_append_string16_len(
|
||||
const char* utf8,
|
||||
gssize num_bytes);
|
||||
|
||||
void
|
||||
gbinder_writer_append_string16_utf16(
|
||||
GBinderWriter* writer,
|
||||
const gunichar2* utf16,
|
||||
gssize length); /* Since 1.0.17 */
|
||||
|
||||
void
|
||||
gbinder_writer_append_string8(
|
||||
GBinderWriter* writer,
|
||||
@@ -108,6 +114,21 @@ gbinder_writer_append_bytes(
|
||||
const void* data,
|
||||
gsize size);
|
||||
|
||||
void
|
||||
gbinder_writer_append_fd(
|
||||
GBinderWriter* writer,
|
||||
int fd); /* Since 1.0.18 */
|
||||
|
||||
gsize
|
||||
gbinder_writer_bytes_written(
|
||||
GBinderWriter* writer); /* Since 1.0.21 */
|
||||
|
||||
void
|
||||
gbinder_writer_overwrite_int32(
|
||||
GBinderWriter* writer,
|
||||
gsize offset,
|
||||
gint32 value); /* Since 1.0.21 */
|
||||
|
||||
guint
|
||||
gbinder_writer_append_buffer_object_with_parent(
|
||||
GBinderWriter* writer,
|
||||
@@ -121,11 +142,23 @@ gbinder_writer_append_buffer_object(
|
||||
const void* buf,
|
||||
gsize len);
|
||||
|
||||
void
|
||||
gbinder_writer_append_hidl_vec(
|
||||
GBinderWriter* writer,
|
||||
const void* base,
|
||||
guint count,
|
||||
guint elemsize); /* Since 1.0.8 */
|
||||
|
||||
void
|
||||
gbinder_writer_append_hidl_string(
|
||||
GBinderWriter* writer,
|
||||
const char* str);
|
||||
|
||||
void
|
||||
gbinder_writer_append_hidl_string_copy(
|
||||
GBinderWriter* writer,
|
||||
const char* str); /* Since 1.1.13 */
|
||||
|
||||
void
|
||||
gbinder_writer_append_hidl_string_vec(
|
||||
GBinderWriter* writer,
|
||||
@@ -142,6 +175,47 @@ gbinder_writer_append_remote_object(
|
||||
GBinderWriter* writer,
|
||||
GBinderRemoteObject* obj);
|
||||
|
||||
void
|
||||
gbinder_writer_append_byte_array(
|
||||
GBinderWriter* writer,
|
||||
const void* byte_array,
|
||||
gint32 len); /* Since 1.0.12 */
|
||||
|
||||
/* Note: memory allocated by GBinderWriter is owned by GBinderWriter */
|
||||
|
||||
void*
|
||||
gbinder_writer_malloc(
|
||||
GBinderWriter* writer,
|
||||
gsize size); /* Since 1.0.19 */
|
||||
|
||||
void*
|
||||
gbinder_writer_malloc0(
|
||||
GBinderWriter* writer,
|
||||
gsize size); /* Since 1.0.19 */
|
||||
|
||||
#define gbinder_writer_new(writer,type) \
|
||||
((type*) gbinder_writer_malloc(writer, sizeof(type)))
|
||||
|
||||
#define gbinder_writer_new0(writer,type) \
|
||||
((type*) gbinder_writer_malloc0(writer, sizeof(type)))
|
||||
|
||||
void
|
||||
gbinder_writer_add_cleanup(
|
||||
GBinderWriter* writer,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data); /* Since 1.0.19 */
|
||||
|
||||
void*
|
||||
gbinder_writer_memdup(
|
||||
GBinderWriter* writer,
|
||||
const void* buf,
|
||||
gsize size); /* Since 1.0.19 */
|
||||
|
||||
char*
|
||||
gbinder_writer_strdup(
|
||||
GBinderWriter* writer,
|
||||
const char* str); /* Since 1.1.13 */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GBINDER_WRITER_H */
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
Name: libgbinder
|
||||
Version: 1.0.7
|
||||
|
||||
Version: 1.1.13
|
||||
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.29
|
||||
|
||||
%define libglibutil_version 1.0.52
|
||||
|
||||
BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.29
|
||||
BuildRequires: pkgconfig(libglibutil) >= %{libglibutil_version}
|
||||
BuildRequires: pkgconfig
|
||||
BuildRequires: bison
|
||||
BuildRequires: flex
|
||||
Requires: libglibutil >= %{libglibutil_version}
|
||||
Requires(post): /sbin/ldconfig
|
||||
Requires(postun): /sbin/ldconfig
|
||||
|
||||
@@ -18,7 +24,6 @@ C interfaces for Android binder
|
||||
%package devel
|
||||
Summary: Development library for %{name}
|
||||
Requires: %{name} = %{version}
|
||||
Requires: pkgconfig
|
||||
|
||||
%description devel
|
||||
This package contains the development library for %{name}.
|
||||
@@ -27,11 +32,19 @@ This package contains the development library for %{name}.
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
make KEEP_SYMBOLS=1 release pkgconfig
|
||||
make %{_smp_mflags} LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig
|
||||
make -C test/binder-bridge KEEP_SYMBOLS=1 release
|
||||
make -C test/binder-list KEEP_SYMBOLS=1 release
|
||||
make -C test/binder-ping KEEP_SYMBOLS=1 release
|
||||
make -C test/binder-call KEEP_SYMBOLS=1 release
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
make install-dev DESTDIR=%{buildroot}
|
||||
make LIBDIR=%{_libdir} DESTDIR=%{buildroot} install-dev
|
||||
make -C test/binder-bridge DESTDIR=%{buildroot} install
|
||||
make -C test/binder-list DESTDIR=%{buildroot} install
|
||||
make -C test/binder-ping DESTDIR=%{buildroot} install
|
||||
make -C test/binder-call DESTDIR=%{buildroot} install
|
||||
|
||||
%check
|
||||
make -C unit test
|
||||
@@ -49,3 +62,19 @@ make -C unit test
|
||||
%{_libdir}/pkgconfig/*.pc
|
||||
%{_libdir}/%{name}.so
|
||||
%{_includedir}/gbinder/*.h
|
||||
|
||||
# Tools
|
||||
|
||||
%package tools
|
||||
Summary: Binder tools
|
||||
Requires: %{name} >= %{version}
|
||||
|
||||
%description tools
|
||||
Binder command line utilities
|
||||
|
||||
%files tools
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/binder-bridge
|
||||
%{_bindir}/binder-list
|
||||
%{_bindir}/binder-ping
|
||||
%{_bindir}/binder-call
|
||||
|
||||
272
src/gbinder_bridge.c
Normal file
272
src/gbinder_bridge.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 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_local_request.h"
|
||||
#include "gbinder_local_reply.h"
|
||||
#include "gbinder_proxy_object.h"
|
||||
#include "gbinder_remote_request_p.h"
|
||||
#include "gbinder_remote_reply.h"
|
||||
#include "gbinder_remote_object_p.h"
|
||||
#include "gbinder_servicename.h"
|
||||
#include "gbinder_servicemanager_p.h"
|
||||
#include "gbinder_client_p.h"
|
||||
#include "gbinder_bridge.h"
|
||||
#include "gbinder_ipc.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct gbinder_bridge_interface {
|
||||
GBinderBridge* bridge;
|
||||
char* iface;
|
||||
char* fqname;
|
||||
char* src_name;
|
||||
char* dest_name;
|
||||
gulong dest_watch_id;
|
||||
gulong dest_death_id;
|
||||
GBinderRemoteObject* dest_obj;
|
||||
GBinderServiceName* src_service;
|
||||
GBinderProxyObject* proxy;
|
||||
} GBinderBridgeInterface;
|
||||
|
||||
struct gbinder_bridge {
|
||||
GBinderBridgeInterface** ifaces;
|
||||
GBinderServiceManager* src;
|
||||
GBinderServiceManager* dest;
|
||||
};
|
||||
|
||||
/*==========================================================================*
|
||||
* Implementation
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_bridge_dest_drop_remote_object(
|
||||
GBinderBridgeInterface* bi)
|
||||
{
|
||||
if (bi->dest_obj) {
|
||||
GDEBUG("Detached from %s", bi->fqname);
|
||||
gbinder_remote_object_remove_handler(bi->dest_obj, bi->dest_death_id);
|
||||
gbinder_remote_object_unref(bi->dest_obj);
|
||||
bi->dest_death_id = 0;
|
||||
bi->dest_obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_bridge_interface_deactivate(
|
||||
GBinderBridgeInterface* bi)
|
||||
{
|
||||
gbinder_bridge_dest_drop_remote_object(bi);
|
||||
if (bi->proxy) {
|
||||
gbinder_local_object_drop(GBINDER_LOCAL_OBJECT(bi->proxy));
|
||||
bi->proxy = NULL;
|
||||
}
|
||||
if (bi->src_service) {
|
||||
gbinder_servicename_unref(bi->src_service);
|
||||
bi->src_service = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_bridge_interface_free(
|
||||
GBinderBridgeInterface* bi)
|
||||
{
|
||||
GBinderBridge* bridge = bi->bridge;
|
||||
|
||||
gbinder_bridge_interface_deactivate(bi);
|
||||
gbinder_servicemanager_remove_handler(bridge->dest, bi->dest_watch_id);
|
||||
g_free(bi->iface);
|
||||
g_free(bi->fqname);
|
||||
g_free(bi->src_name);
|
||||
g_free(bi->dest_name);
|
||||
gutil_slice_free(bi);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_bridge_dest_death_proc(
|
||||
GBinderRemoteObject* obj,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderBridgeInterface* bi = user_data;
|
||||
|
||||
GDEBUG("%s has died", bi->fqname);
|
||||
gbinder_bridge_interface_deactivate(bi);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_bridge_interface_activate(
|
||||
GBinderBridgeInterface* bi)
|
||||
{
|
||||
GBinderBridge* bridge = bi->bridge;
|
||||
GBinderServiceManager* src = bridge->src;
|
||||
GBinderServiceManager* dest = bridge->dest;
|
||||
|
||||
if (bi->dest_obj && bi->dest_obj->dead) {
|
||||
gbinder_bridge_dest_drop_remote_object(bi);
|
||||
}
|
||||
if (!bi->dest_obj) {
|
||||
bi->dest_obj = gbinder_servicemanager_get_service_sync(dest,
|
||||
bi->fqname, NULL);
|
||||
if (bi->dest_obj) {
|
||||
GDEBUG("Attached to %s", bi->fqname);
|
||||
gbinder_remote_object_ref(bi->dest_obj);
|
||||
bi->dest_death_id = gbinder_remote_object_add_death_handler
|
||||
(bi->dest_obj, gbinder_bridge_dest_death_proc, bi);
|
||||
}
|
||||
}
|
||||
if (bi->dest_obj && !bi->proxy) {
|
||||
bi->proxy = gbinder_proxy_object_new(gbinder_servicemanager_ipc(src),
|
||||
bi->dest_obj);
|
||||
}
|
||||
if (bi->proxy && !bi->src_service) {
|
||||
bi->src_service = gbinder_servicename_new(src,
|
||||
GBINDER_LOCAL_OBJECT(bi->proxy), bi->src_name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_bridge_dest_registration_proc(
|
||||
GBinderServiceManager* sm,
|
||||
const char* name,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderBridgeInterface* bi = user_data;
|
||||
|
||||
if (!g_strcmp0(name, bi->fqname)) {
|
||||
GDEBUG("%s has been registered", bi->fqname);
|
||||
gbinder_bridge_interface_activate(bi);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
GBinderBridgeInterface*
|
||||
gbinder_bridge_interface_new(
|
||||
GBinderBridge* self,
|
||||
const char* src_name,
|
||||
const char* dest_name,
|
||||
const char* iface)
|
||||
{
|
||||
GBinderBridgeInterface* bi = g_slice_new0(GBinderBridgeInterface);
|
||||
|
||||
bi->bridge = self;
|
||||
bi->iface = g_strdup(iface);
|
||||
bi->fqname = g_strconcat(iface, "/", dest_name, NULL);
|
||||
bi->src_name = g_strdup(src_name);
|
||||
bi->dest_name = g_strdup(dest_name);
|
||||
bi->dest_watch_id = gbinder_servicemanager_add_registration_handler
|
||||
(self->dest, bi->fqname, gbinder_bridge_dest_registration_proc, bi);
|
||||
|
||||
/* Try to activate at startup */
|
||||
gbinder_bridge_interface_activate(bi);
|
||||
return bi;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Interface
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderBridge*
|
||||
gbinder_bridge_new(
|
||||
const char* name,
|
||||
const char* const* ifaces,
|
||||
GBinderServiceManager* src,
|
||||
GBinderServiceManager* dest) /* Since 1.1.5 */
|
||||
{
|
||||
return gbinder_bridge_new2(name, NULL, ifaces, src, dest);
|
||||
}
|
||||
|
||||
GBinderBridge*
|
||||
gbinder_bridge_new2(
|
||||
const char* src_name,
|
||||
const char* dest_name,
|
||||
const char* const* ifaces,
|
||||
GBinderServiceManager* src,
|
||||
GBinderServiceManager* dest) /* Since 1.1.6 */
|
||||
{
|
||||
const guint n = gutil_strv_length((const GStrV*)ifaces);
|
||||
|
||||
if (!src_name) {
|
||||
src_name = dest_name;
|
||||
} else if (!dest_name) {
|
||||
dest_name = src_name;
|
||||
}
|
||||
if (G_LIKELY(src_name) && G_LIKELY(n) && G_LIKELY(src) && G_LIKELY(dest)) {
|
||||
GBinderBridge* self = g_slice_new0(GBinderBridge);
|
||||
guint i;
|
||||
|
||||
self->src = gbinder_servicemanager_ref(src);
|
||||
self->dest = gbinder_servicemanager_ref(dest);
|
||||
self->ifaces = g_new(GBinderBridgeInterface*, n + 1);
|
||||
for (i = 0; i < n; i++) {
|
||||
self->ifaces[i] = gbinder_bridge_interface_new(self,
|
||||
src_name, dest_name, ifaces[i]);
|
||||
}
|
||||
self->ifaces[i] = NULL;
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_bridge_free(
|
||||
GBinderBridge* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderBridgeInterface** bi = self->ifaces;
|
||||
|
||||
while (*bi) {
|
||||
gbinder_bridge_interface_free(*bi);
|
||||
bi++;
|
||||
}
|
||||
gbinder_servicemanager_unref(self->src);
|
||||
gbinder_servicemanager_unref(self->dest);
|
||||
g_free(self->ifaces);
|
||||
gutil_slice_free(self);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -36,54 +36,62 @@
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
struct gbinder_buffer_memory {
|
||||
struct gbinder_buffer_contents {
|
||||
gint refcount;
|
||||
void* buffer;
|
||||
gsize size;
|
||||
void** objects;
|
||||
GBinderDriver* driver;
|
||||
};
|
||||
|
||||
typedef struct gbinder_buffer_priv {
|
||||
GBinderBuffer pub;
|
||||
GBinderBufferMemory* memory;
|
||||
GBinderBufferContents* contents;
|
||||
} GBinderBufferPriv;
|
||||
|
||||
static inline GBinderBufferPriv* gbinder_buffer_cast(GBinderBuffer* buf)
|
||||
{ return G_CAST(buf, GBinderBufferPriv, pub); }
|
||||
|
||||
/*==========================================================================*
|
||||
* GBinderBufferMemory
|
||||
* GBinderBufferContents
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory_new(
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents_new(
|
||||
GBinderDriver* driver,
|
||||
void* buffer,
|
||||
gsize size)
|
||||
gsize size,
|
||||
void** objects)
|
||||
{
|
||||
GBinderBufferMemory* self = g_slice_new0(GBinderBufferMemory);
|
||||
GBinderBufferContents* self = g_slice_new0(GBinderBufferContents);
|
||||
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
self->buffer = buffer;
|
||||
self->size = size;
|
||||
self->objects = objects;
|
||||
self->driver = gbinder_driver_ref(driver);
|
||||
return self;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_buffer_memory_free(
|
||||
GBinderBufferMemory* self)
|
||||
gbinder_buffer_contents_free(
|
||||
GBinderBufferContents* self)
|
||||
{
|
||||
if (self->objects) {
|
||||
gbinder_driver_close_fds(self->driver, self->objects,
|
||||
((guint8*)self->buffer) + self->size);
|
||||
g_free(self->objects);
|
||||
}
|
||||
gbinder_driver_free_buffer(self->driver, self->buffer);
|
||||
gbinder_driver_unref(self->driver);
|
||||
g_slice_free(GBinderBufferMemory, self);
|
||||
g_slice_free(GBinderBufferContents, self);
|
||||
}
|
||||
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory_ref(
|
||||
GBinderBufferMemory* self)
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents_ref(
|
||||
GBinderBufferContents* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GASSERT(self->refcount > 0);
|
||||
@@ -93,17 +101,58 @@ gbinder_buffer_memory_ref(
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_buffer_memory_unref(
|
||||
GBinderBufferMemory* self)
|
||||
gbinder_buffer_contents_unref(
|
||||
GBinderBufferContents* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GASSERT(self->refcount > 0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
gbinder_buffer_memory_free(self);
|
||||
gbinder_buffer_contents_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* GBinderBufferContentsList
|
||||
* It's actually a GSList containing GBinderBufferContents refs.
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderBufferContentsList*
|
||||
gbinder_buffer_contents_list_add(
|
||||
GBinderBufferContentsList* list,
|
||||
GBinderBufferContents* contents)
|
||||
{
|
||||
/* Prepend rather than append for better efficiency */
|
||||
return contents ? (GBinderBufferContentsList*) g_slist_prepend((GSList*)
|
||||
list, gbinder_buffer_contents_ref(contents)) : list;
|
||||
}
|
||||
|
||||
GBinderBufferContentsList*
|
||||
gbinder_buffer_contents_list_dup(
|
||||
GBinderBufferContentsList* list)
|
||||
{
|
||||
GSList* out = NULL;
|
||||
|
||||
if (list) {
|
||||
GSList* l = (GSList*) list;
|
||||
|
||||
/* The order gets reversed but it doesn't matter */
|
||||
while (l) {
|
||||
out = g_slist_prepend(out, gbinder_buffer_contents_ref(l->data));
|
||||
l = l->next;
|
||||
}
|
||||
}
|
||||
return (GBinderBufferContentsList*) out;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_buffer_contents_list_free(
|
||||
GBinderBufferContentsList* list)
|
||||
{
|
||||
g_slist_free_full((GSList*) list, (GDestroyNotify)
|
||||
gbinder_buffer_contents_unref);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* GBinderBuffer
|
||||
*==========================================================================*/
|
||||
@@ -111,14 +160,14 @@ gbinder_buffer_memory_unref(
|
||||
static
|
||||
GBinderBuffer*
|
||||
gbinder_buffer_alloc(
|
||||
GBinderBufferMemory* memory,
|
||||
GBinderBufferContents* contents,
|
||||
void* data,
|
||||
gsize size)
|
||||
{
|
||||
GBinderBufferPriv* priv = g_slice_new0(GBinderBufferPriv);
|
||||
GBinderBuffer* self = &priv->pub;
|
||||
|
||||
priv->memory = memory;
|
||||
priv->contents = contents;
|
||||
self->data = data;
|
||||
self->size = size;
|
||||
return self;
|
||||
@@ -131,7 +180,7 @@ gbinder_buffer_free(
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
||||
|
||||
gbinder_buffer_memory_unref(priv->memory);
|
||||
gbinder_buffer_contents_unref(priv->contents);
|
||||
g_slice_free(GBinderBufferPriv, priv);
|
||||
}
|
||||
}
|
||||
@@ -140,10 +189,12 @@ GBinderBuffer*
|
||||
gbinder_buffer_new(
|
||||
GBinderDriver* driver,
|
||||
void* data,
|
||||
gsize size)
|
||||
gsize size,
|
||||
void** objects)
|
||||
{
|
||||
return gbinder_buffer_alloc((driver && data) ?
|
||||
gbinder_buffer_memory_new(driver, data, size) : NULL, data, size);
|
||||
gbinder_buffer_contents_new(driver, data, size, objects) : NULL,
|
||||
data, size);
|
||||
}
|
||||
|
||||
GBinderBuffer*
|
||||
@@ -153,7 +204,7 @@ gbinder_buffer_new_with_parent(
|
||||
gsize size)
|
||||
{
|
||||
return gbinder_buffer_alloc(parent ?
|
||||
gbinder_buffer_memory_ref(gbinder_buffer_memory(parent)) : NULL,
|
||||
gbinder_buffer_contents_ref(gbinder_buffer_contents(parent)) : NULL,
|
||||
data, size);
|
||||
}
|
||||
|
||||
@@ -162,13 +213,13 @@ gbinder_buffer_data(
|
||||
GBinderBuffer* self,
|
||||
gsize* size)
|
||||
{
|
||||
GBinderBufferMemory* memory = gbinder_buffer_memory(self);
|
||||
GBinderBufferContents* contents = gbinder_buffer_contents(self);
|
||||
|
||||
if (G_LIKELY(memory)) {
|
||||
if (G_LIKELY(contents)) {
|
||||
if (size) {
|
||||
*size = memory->size;
|
||||
*size = contents->size;
|
||||
}
|
||||
return memory->buffer;
|
||||
return contents->buffer;
|
||||
} else {
|
||||
if (size) {
|
||||
*size = 0;
|
||||
@@ -184,8 +235,8 @@ gbinder_buffer_driver(
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
||||
|
||||
if (priv->memory) {
|
||||
return priv->memory->driver;
|
||||
if (priv->contents) {
|
||||
return priv->contents->driver;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -200,11 +251,25 @@ gbinder_buffer_io(
|
||||
return driver ? gbinder_driver_io(driver) : NULL;
|
||||
}
|
||||
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory(
|
||||
void**
|
||||
gbinder_buffer_objects(
|
||||
GBinderBuffer* self)
|
||||
{
|
||||
return G_LIKELY(self) ? gbinder_buffer_cast(self)->memory : NULL;
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
||||
|
||||
if (priv->contents) {
|
||||
return priv->contents->objects;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents(
|
||||
GBinderBuffer* self)
|
||||
{
|
||||
return G_LIKELY(self) ? gbinder_buffer_cast(self)->contents : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -41,38 +41,68 @@ GBinderBuffer*
|
||||
gbinder_buffer_new(
|
||||
GBinderDriver* driver,
|
||||
void* data,
|
||||
gsize size);
|
||||
gsize size,
|
||||
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;
|
||||
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory(
|
||||
GBinderBuffer* buf);
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents(
|
||||
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;
|
||||
|
||||
GBinderBufferMemory*
|
||||
gbinder_buffer_memory_ref(
|
||||
GBinderBufferMemory* mem);
|
||||
void**
|
||||
gbinder_buffer_objects(
|
||||
GBinderBuffer* buffer)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderBufferContents*
|
||||
gbinder_buffer_contents_ref(
|
||||
GBinderBufferContents* contents)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_buffer_memory_unref(
|
||||
GBinderBufferMemory* mem);
|
||||
gbinder_buffer_contents_unref(
|
||||
GBinderBufferContents* contents)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderBufferContentsList*
|
||||
gbinder_buffer_contents_list_add(
|
||||
GBinderBufferContentsList* list,
|
||||
GBinderBufferContents* contents)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderBufferContentsList*
|
||||
gbinder_buffer_contents_list_dup(
|
||||
GBinderBufferContentsList* list)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_buffer_contents_list_free(
|
||||
GBinderBufferContentsList* list)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_BUFFER_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -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,11 +48,33 @@ struct gbinder_cleanup {
|
||||
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
|
||||
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_cleanup_destroy_func(
|
||||
gpointer data)
|
||||
{
|
||||
GBinderCleanupItem* item = data;
|
||||
|
||||
item->destroy(item->pointer);
|
||||
}
|
||||
|
||||
static
|
||||
GBinderCleanup*
|
||||
gbinder_cleanup_new()
|
||||
{
|
||||
return (GBinderCleanup*)g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
|
||||
GArray* array = g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
|
||||
|
||||
g_array_set_clear_func(array, gbinder_cleanup_destroy_func);
|
||||
return (GBinderCleanup*)array;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_cleanup_reset(
|
||||
GBinderCleanup* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_array_set_size((GArray*)self, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -60,11 +82,6 @@ gbinder_cleanup_free(
|
||||
GBinderCleanup* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->count; i++) {
|
||||
self->items[i].destroy(self->items[i].pointer);
|
||||
}
|
||||
g_array_free((GArray*)self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -37,13 +37,20 @@
|
||||
|
||||
void
|
||||
gbinder_cleanup_free(
|
||||
GBinderCleanup* cleanup);
|
||||
GBinderCleanup* cleanup)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_cleanup_reset(
|
||||
GBinderCleanup* cleanup)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderCleanup*
|
||||
gbinder_cleanup_add(
|
||||
GBinderCleanup* cleanup,
|
||||
GDestroyNotify destroy,
|
||||
gpointer pointer);
|
||||
gpointer pointer)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_CLEANUP_H */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -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,17 +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;
|
||||
|
||||
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);
|
||||
gbinder_local_request_unref(priv->basic_req);
|
||||
g_free(priv->iface);
|
||||
g_bytes_unref(priv->rpc_header);
|
||||
g_slice_free(GBinderClientPriv, priv);
|
||||
}
|
||||
|
||||
@@ -108,38 +178,127 @@ gbinder_client_transact_destroy(
|
||||
g_slice_free(GBinderClientTx, tx);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal interface
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderRemoteReply*
|
||||
gbinder_client_transact_sync_reply2(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req,
|
||||
int* status,
|
||||
const GBinderIpcSyncApi* api)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderRemoteObject* obj = self->remote;
|
||||
|
||||
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) */
|
||||
if (r) {
|
||||
req = r->basic_req;
|
||||
}
|
||||
}
|
||||
if (req) {
|
||||
return api->sync_reply(obj->ipc, obj->handle, code, req,
|
||||
status);
|
||||
} else {
|
||||
GWARN("Unable to build empty request for tx code %u", code);
|
||||
}
|
||||
} else {
|
||||
GDEBUG("Refusing to perform transaction with a dead object");
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
gbinder_client_transact_sync_oneway2(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req,
|
||||
const GBinderIpcSyncApi* api)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderRemoteObject* obj = self->remote;
|
||||
|
||||
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) */
|
||||
if (r) {
|
||||
req = r->basic_req;
|
||||
}
|
||||
}
|
||||
if (req) {
|
||||
return api->sync_oneway(obj->ipc, obj->handle, code, req);
|
||||
} else {
|
||||
GWARN("Unable to build empty request for tx code %u", code);
|
||||
}
|
||||
} else {
|
||||
GDEBUG("Refusing to perform transaction with a dead object");
|
||||
return (-ESTALE);
|
||||
}
|
||||
}
|
||||
return (-EINVAL);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Interface
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderClient*
|
||||
gbinder_client_new2(
|
||||
GBinderRemoteObject* remote,
|
||||
const GBinderClientIfaceInfo* ifaces,
|
||||
gsize count)
|
||||
{
|
||||
if (G_LIKELY(remote)) {
|
||||
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
|
||||
GBinderClient* self = &priv->pub;
|
||||
GBinderDriver* driver = remote->ipc->driver;
|
||||
|
||||
g_atomic_int_set(&priv->refcount, 1);
|
||||
self->remote = gbinder_remote_object_ref(remote);
|
||||
if (count > 0) {
|
||||
gsize i;
|
||||
|
||||
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 {
|
||||
/* 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;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderClient*
|
||||
gbinder_client_new(
|
||||
GBinderRemoteObject* remote,
|
||||
const char* iface)
|
||||
{
|
||||
if (G_LIKELY(remote) && G_LIKELY(iface)) {
|
||||
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
|
||||
GBinderClient* self = &priv->pub;
|
||||
GBinderIpc* ipc = remote->ipc;
|
||||
GBinderOutputData* hdr;
|
||||
GBinderClientIfaceInfo info;
|
||||
|
||||
g_atomic_int_set(&priv->refcount, 1);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
priv->basic_req = gbinder_driver_local_request_new(ipc->driver, iface);
|
||||
hdr = gbinder_local_request_data(priv->basic_req);
|
||||
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
|
||||
|
||||
self->remote = gbinder_remote_object_ref(remote);
|
||||
self->iface = priv->iface = g_strdup(iface);
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
info.iface = iface;
|
||||
info.last_code = UINT_MAX;
|
||||
return gbinder_client_new2(remote, &info, 1);
|
||||
}
|
||||
|
||||
GBinderClient*
|
||||
@@ -169,6 +328,29 @@ gbinder_client_unref(
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
gbinder_client_interface(
|
||||
GBinderClient* self) /* since 1.0.22 */
|
||||
{
|
||||
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*
|
||||
gbinder_client_new_request(
|
||||
GBinderClient* self)
|
||||
@@ -176,7 +358,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;
|
||||
}
|
||||
@@ -188,17 +390,8 @@ gbinder_client_transact_sync_reply(
|
||||
GBinderLocalRequest* req,
|
||||
int* status)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderRemoteObject* obj = self->remote;
|
||||
|
||||
if (!req) {
|
||||
/* Default empty request (just the header, no parameters) */
|
||||
req = gbinder_client_cast(self)->basic_req;
|
||||
}
|
||||
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
|
||||
code, req, status);
|
||||
}
|
||||
return NULL;
|
||||
return gbinder_client_transact_sync_reply2(self, code, req, status,
|
||||
&gbinder_ipc_sync_main);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -207,18 +400,8 @@ gbinder_client_transact_sync_oneway(
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderRemoteObject* obj = self->remote;
|
||||
|
||||
if (!req) {
|
||||
/* Default empty request (just the header, no parameters) */
|
||||
req = gbinder_client_cast(self)->basic_req;
|
||||
}
|
||||
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
|
||||
code, req);
|
||||
} else {
|
||||
return (-EINVAL);
|
||||
}
|
||||
return gbinder_client_transact_sync_oneway2(self, code, req,
|
||||
&gbinder_ipc_sync_main);
|
||||
}
|
||||
|
||||
gulong
|
||||
@@ -233,23 +416,35 @@ gbinder_client_transact(
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderRemoteObject* obj = self->remote;
|
||||
|
||||
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) */
|
||||
if (r) {
|
||||
req = r->basic_req;
|
||||
}
|
||||
}
|
||||
if (req) {
|
||||
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
|
||||
|
||||
tx->client = gbinder_client_ref(self);
|
||||
tx->reply = reply;
|
||||
tx->destroy = destroy;
|
||||
tx->user_data = user_data;
|
||||
|
||||
if (!req) {
|
||||
/* Default empty request (just the header, no parameters) */
|
||||
req = gbinder_client_cast(self)->basic_req;
|
||||
}
|
||||
|
||||
return gbinder_ipc_transact(obj->ipc, obj->handle, code, flags, req,
|
||||
gbinder_client_transact_reply, gbinder_client_transact_destroy, tx);
|
||||
return gbinder_ipc_transact(obj->ipc, obj->handle, code,
|
||||
flags, req, gbinder_client_transact_reply,
|
||||
gbinder_client_transact_destroy, tx);
|
||||
} else {
|
||||
return 0;
|
||||
GWARN("Unable to build empty request for tx code %u", code);
|
||||
}
|
||||
} else {
|
||||
GDEBUG("Refusing to perform transaction with a dead object");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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,10 +38,27 @@
|
||||
#include "gbinder_types_p.h"
|
||||
|
||||
struct gbinder_client {
|
||||
const char* iface;
|
||||
GBinderRemoteObject* remote;
|
||||
};
|
||||
|
||||
GBinderRemoteReply*
|
||||
gbinder_client_transact_sync_reply2(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req,
|
||||
int* status,
|
||||
const GBinderIpcSyncApi* api)
|
||||
G_GNUC_WARN_UNUSED_RESULT
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
int
|
||||
gbinder_client_transact_sync_oneway2(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req,
|
||||
const GBinderIpcSyncApi* api)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#define gbinder_client_ipc(client) ((client)->remote->ipc)
|
||||
|
||||
#endif /* GBINDER_CLIENT_PRIVATE_H */
|
||||
|
||||
384
src/gbinder_config.c
Normal file
384
src/gbinder_config.c
Normal file
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gbinder_config.h"
|
||||
#include "gbinder_eventloop_p.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* The contents of the config file is queried from (at least) two places,
|
||||
* and pretty much always this happens the same stack. Which means that
|
||||
* we can avoid reading the same file twice if we delay dereferencing of
|
||||
* GKeyFile until the next idle loop.
|
||||
*/
|
||||
|
||||
static GKeyFile* gbinder_config_keyfile = NULL;
|
||||
static GBinderEventLoopCallback* gbinder_config_autorelease = NULL;
|
||||
|
||||
static const char gbinder_config_suffix[] = ".conf";
|
||||
static const char gbinder_config_default_file[] = "/etc/gbinder.conf";
|
||||
static const char gbinder_config_default_dir[] = "/etc/gbinder.d";
|
||||
|
||||
const char* gbinder_config_file = gbinder_config_default_file;
|
||||
const char* gbinder_config_dir = gbinder_config_default_dir;
|
||||
|
||||
/*
|
||||
* Presets for particular API level can be chosen with ApiLevel
|
||||
* setting, e.g.
|
||||
*
|
||||
* [General]
|
||||
* ApiLevel=29
|
||||
*
|
||||
*/
|
||||
|
||||
static const char CONF_GENERAL[] = "General";
|
||||
static const char CONG_API_LEVEL[] = "ApiLevel";
|
||||
|
||||
typedef struct gbinder_config_preset_entry {
|
||||
const char* key;
|
||||
const char* value;
|
||||
} GBinderConfigPresetEntry;
|
||||
|
||||
typedef struct gbinder_config_preset_group {
|
||||
const char* name;
|
||||
const GBinderConfigPresetEntry* entries;
|
||||
} GBinderConfigPresetGroup;
|
||||
|
||||
typedef struct gbinder_config_preset {
|
||||
guint api_level;
|
||||
const GBinderConfigPresetGroup* groups;
|
||||
} GBinderConfigPreset;
|
||||
|
||||
/* API level 28 */
|
||||
|
||||
static const GBinderConfigPresetEntry gbinder_config_28_servicemanager[] = {
|
||||
{ "/dev/binder", "aidl2" },
|
||||
{ "/dev/vndbinder", "aidl2" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const GBinderConfigPresetGroup gbinder_config_28[] = {
|
||||
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_28_servicemanager },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* API level 29 */
|
||||
|
||||
static const GBinderConfigPresetEntry gbinder_config_29_protocol[] = {
|
||||
{ "/dev/binder", "aidl2" },
|
||||
{ "/dev/vndbinder", "aidl2" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
#define gbinder_config_29_servicemanager gbinder_config_28_servicemanager
|
||||
|
||||
static const GBinderConfigPresetGroup gbinder_config_29[] = {
|
||||
{ GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_29_protocol },
|
||||
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_29_servicemanager },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* Presets sorted by API level in descending order */
|
||||
|
||||
static const GBinderConfigPreset gbinder_config_presets[] = {
|
||||
{ 29, gbinder_config_29 },
|
||||
{ 28, gbinder_config_28 }
|
||||
};
|
||||
|
||||
static
|
||||
char**
|
||||
gbinder_config_collect_files(
|
||||
const char* path,
|
||||
const char* suffix)
|
||||
{
|
||||
/*
|
||||
* Returns sorted list of regular files in the directory,
|
||||
* optionally having the specified suffix (e.g. ".conf").
|
||||
* Returns NULL if nothing appropriate has been found.
|
||||
*/
|
||||
char** files = NULL;
|
||||
|
||||
if (path) {
|
||||
GDir* dir = g_dir_open(path, 0, NULL);
|
||||
|
||||
if (dir) {
|
||||
GPtrArray* list = g_ptr_array_new();
|
||||
const gchar* name;
|
||||
|
||||
while ((name = g_dir_read_name(dir)) != NULL) {
|
||||
if (g_str_has_suffix(name, suffix)) {
|
||||
char* fullname = g_build_filename(path, name, NULL);
|
||||
struct stat st;
|
||||
|
||||
if (!stat(fullname, &st) && S_ISREG(st.st_mode)) {
|
||||
g_ptr_array_add(list, fullname);
|
||||
} else {
|
||||
g_free(fullname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list->len > 0) {
|
||||
g_ptr_array_add(list, NULL);
|
||||
files = (char**) g_ptr_array_free(list, FALSE);
|
||||
gutil_strv_sort(files, TRUE);
|
||||
} else {
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
|
||||
g_dir_close(dir);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
static
|
||||
GKeyFile*
|
||||
gbinder_config_merge_keyfiles(
|
||||
GKeyFile* dest,
|
||||
GKeyFile* src)
|
||||
{
|
||||
gsize i, ngroups;
|
||||
gchar** groups = g_key_file_get_groups(src, &ngroups);
|
||||
|
||||
for (i = 0; i < ngroups; i++) {
|
||||
gsize k, nkeys;
|
||||
const char* group = groups[i];
|
||||
char** keys = g_key_file_get_keys(src, group, &nkeys, NULL);
|
||||
|
||||
for (k = 0; k < nkeys; k++) {
|
||||
const char* key = keys[k];
|
||||
char* value = g_key_file_get_value(src, group, key, NULL);
|
||||
|
||||
g_key_file_set_value(dest, group, key, value);
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
g_strfreev(keys);
|
||||
}
|
||||
|
||||
g_strfreev(groups);
|
||||
return dest;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_config_apply_presets(
|
||||
GKeyFile* config,
|
||||
const GBinderConfigPreset* preset)
|
||||
{
|
||||
const GBinderConfigPresetGroup* g;
|
||||
|
||||
GDEBUG("Applying presets for API level %d", preset->api_level);
|
||||
for (g = preset->groups; g->name; g++) {
|
||||
const GBinderConfigPresetEntry* e;
|
||||
|
||||
for (e = g->entries; e->key; e++) {
|
||||
if (!g_key_file_has_key(config, g->name, e->key, NULL)) {
|
||||
g_key_file_set_value(config, g->name, e->key, e->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
GKeyFile*
|
||||
gbinder_config_load_files()
|
||||
{
|
||||
GError* error = NULL;
|
||||
GKeyFile* out = NULL;
|
||||
char** files = gbinder_config_collect_files(gbinder_config_dir,
|
||||
gbinder_config_suffix);
|
||||
|
||||
if (gbinder_config_file &&
|
||||
g_file_test(gbinder_config_file, G_FILE_TEST_EXISTS)) {
|
||||
out = g_key_file_new();
|
||||
if (g_key_file_load_from_file(out, gbinder_config_file,
|
||||
G_KEY_FILE_NONE, &error)) {
|
||||
GDEBUG("Loaded %s", gbinder_config_file);
|
||||
} else {
|
||||
GERR("Error loading %s: %s", gbinder_config_file, error->message);
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
gbinder_config_file = NULL; /* Don't retry */
|
||||
g_key_file_unref(out);
|
||||
out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Files in the config directory overwrite /etc/gbinder.conf */
|
||||
if (files) {
|
||||
char** ptr;
|
||||
GKeyFile* override = NULL;
|
||||
|
||||
for (ptr = files; *ptr; ptr++) {
|
||||
const char* file = *ptr;
|
||||
|
||||
if (!override) {
|
||||
override = g_key_file_new();
|
||||
}
|
||||
if (g_key_file_load_from_file(override, file,
|
||||
G_KEY_FILE_NONE, &error)) {
|
||||
GDEBUG("Loaded %s", file);
|
||||
if (!out) {
|
||||
out = override;
|
||||
override = NULL;
|
||||
} else {
|
||||
out = gbinder_config_merge_keyfiles(out, override);
|
||||
}
|
||||
} else {
|
||||
GERR("Error loading %s: %s", file, error->message);
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(files);
|
||||
if (override) {
|
||||
g_key_file_unref(override);
|
||||
}
|
||||
}
|
||||
|
||||
if (out) {
|
||||
/* Apply presets */
|
||||
const int api_level = g_key_file_get_integer(out,
|
||||
CONF_GENERAL, CONG_API_LEVEL, NULL);
|
||||
|
||||
if (api_level > 0) {
|
||||
int i;
|
||||
|
||||
GDEBUG("API level %d", api_level);
|
||||
for (i = 0; i < G_N_ELEMENTS(gbinder_config_presets); i++) {
|
||||
const GBinderConfigPreset* preset = gbinder_config_presets + i;
|
||||
|
||||
if (api_level >= preset->api_level) {
|
||||
gbinder_config_apply_presets(out, preset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_config_autorelease_cb(
|
||||
gpointer data)
|
||||
{
|
||||
GASSERT(gbinder_config_keyfile == data);
|
||||
gbinder_config_keyfile = NULL;
|
||||
g_key_file_unref(data);
|
||||
}
|
||||
|
||||
GKeyFile* /* autoreleased */
|
||||
gbinder_config_get()
|
||||
{
|
||||
if (!gbinder_config_keyfile &&
|
||||
(gbinder_config_file || gbinder_config_dir)) {
|
||||
gbinder_config_keyfile = gbinder_config_load_files();
|
||||
if (gbinder_config_keyfile) {
|
||||
/* See the comment at the top of the file why this is needed */
|
||||
gbinder_config_autorelease = gbinder_idle_callback_schedule_new
|
||||
(gbinder_config_autorelease_cb, gbinder_config_keyfile, NULL);
|
||||
}
|
||||
}
|
||||
return gbinder_config_keyfile;
|
||||
}
|
||||
|
||||
/* Helper for loading config group in device = ident format */
|
||||
GHashTable*
|
||||
gbinder_config_load(
|
||||
const char* group,
|
||||
GBinderConfigValueMapFunc mapper)
|
||||
{
|
||||
GKeyFile* k = gbinder_config_get();
|
||||
GHashTable* map = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, NULL);
|
||||
|
||||
if (k) {
|
||||
gsize n;
|
||||
char** devs = g_key_file_get_keys(k, group, &n, NULL);
|
||||
|
||||
if (devs) {
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
char* dev = devs[i];
|
||||
char* sval = g_key_file_get_value(k, group, dev, NULL);
|
||||
gconstpointer val = mapper(sval);
|
||||
|
||||
if (val) {
|
||||
g_hash_table_replace(map, dev, (gpointer) val);
|
||||
} else {
|
||||
GWARN("Unknown gbinder config '%s' for %s in group [%s]",
|
||||
sval, dev, group);
|
||||
g_free(dev);
|
||||
}
|
||||
g_free(sval);
|
||||
}
|
||||
|
||||
/* Shallow delete (contents got stolen or freed) */
|
||||
g_free(devs);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_config_exit()
|
||||
{
|
||||
if (gbinder_config_autorelease) {
|
||||
gbinder_idle_callback_destroy(gbinder_config_autorelease);
|
||||
gbinder_config_autorelease = NULL;
|
||||
}
|
||||
if (gbinder_config_keyfile) {
|
||||
g_key_file_unref(gbinder_config_keyfile);
|
||||
gbinder_config_keyfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
78
src/gbinder_config.h
Normal file
78
src/gbinder_config.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GBINDER_CONFIG_H
|
||||
#define GBINDER_CONFIG_H
|
||||
|
||||
#include "gbinder_types_p.h"
|
||||
|
||||
typedef
|
||||
gconstpointer
|
||||
(*GBinderConfigValueMapFunc)(
|
||||
const char* value);
|
||||
|
||||
GHashTable*
|
||||
gbinder_config_load(
|
||||
const char* group,
|
||||
GBinderConfigValueMapFunc map)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GKeyFile* /* autoreleased */
|
||||
gbinder_config_get(
|
||||
void)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
/* This one declared strictly for unit tests */
|
||||
void
|
||||
gbinder_config_exit(
|
||||
void)
|
||||
GBINDER_INTERNAL
|
||||
GBINDER_DESTRUCTOR;
|
||||
|
||||
/* And these too */
|
||||
extern const char* gbinder_config_file GBINDER_INTERNAL;
|
||||
extern const char* gbinder_config_dir GBINDER_INTERNAL;
|
||||
|
||||
/* Configuration groups and special value */
|
||||
#define GBINDER_CONFIG_GROUP_PROTOCOL "Protocol"
|
||||
#define GBINDER_CONFIG_GROUP_SERVICEMANAGER "ServiceManager"
|
||||
#define GBINDER_CONFIG_VALUE_DEFAULT "Default"
|
||||
|
||||
#endif /* GBINDER_CONFIG_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 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_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 GBinderServiceManager GBinderDefaultServiceManager;
|
||||
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
|
||||
|
||||
G_DEFINE_TYPE(GBinderDefaultServiceManager,
|
||||
gbinder_defaultservicemanager,
|
||||
GBINDER_TYPE_SERVICEMANAGER)
|
||||
|
||||
enum gbinder_defaultservicemanager_calls {
|
||||
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
|
||||
CHECK_SERVICE_TRANSACTION,
|
||||
ADD_SERVICE_TRANSACTION,
|
||||
LIST_SERVICES_TRANSACTION
|
||||
};
|
||||
|
||||
/* As a special case, ServiceManager's handle is zero */
|
||||
#define DEFAULTSERVICEMANAGER_HANDLE (0)
|
||||
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager"
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_defaultservicemanager_new(
|
||||
const char* dev)
|
||||
{
|
||||
return gbinder_servicemanager_new_with_type
|
||||
(gbinder_defaultservicemanager_get_type(), dev);
|
||||
}
|
||||
|
||||
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
|
||||
void
|
||||
gbinder_defaultservicemanager_init(
|
||||
GBinderDefaultServiceManager* self)
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_defaultservicemanager_class_init(
|
||||
GBinderDefaultServiceManagerClass* klass)
|
||||
{
|
||||
klass->handle = DEFAULTSERVICEMANAGER_HANDLE;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "gbinder_driver.h"
|
||||
#include "gbinder_buffer_p.h"
|
||||
#include "gbinder_cleanup.h"
|
||||
#include "gbinder_handler.h"
|
||||
#include "gbinder_io.h"
|
||||
#include "gbinder_local_object_p.h"
|
||||
@@ -60,9 +61,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
/* Log module */
|
||||
GLOG_MODULE_DEFINE("gbinder");
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/* BINDER_VM_SIZE copied from native/libs/binder/ProcessState.cpp */
|
||||
#define BINDER_VM_SIZE ((1024*1024) - sysconf(_SC_PAGE_SIZE)*2)
|
||||
@@ -87,10 +86,30 @@ struct gbinder_driver {
|
||||
const GBinderRpcProtocol* protocol;
|
||||
};
|
||||
|
||||
typedef struct gbinder_io_read_buf {
|
||||
GBinderIoBuf buf;
|
||||
typedef struct gbinder_driver_read_buf {
|
||||
GBinderIoBuf io;
|
||||
gsize offset;
|
||||
} GBinderDriverReadBuf;
|
||||
|
||||
typedef struct gbinder_driver_read_data {
|
||||
GBinderDriverReadBuf buf;
|
||||
guint8 data[GBINDER_IO_READ_BUFFER_SIZE];
|
||||
} GBinderIoReadBuf;
|
||||
} GBinderDriverReadData;
|
||||
|
||||
typedef struct gbinder_driver_context {
|
||||
GBinderDriverReadBuf* rbuf;
|
||||
GBinderObjectRegistry* reg;
|
||||
GBinderHandler* handler;
|
||||
GBinderCleanup* unrefs;
|
||||
GBinderBufferContentsList* bufs;
|
||||
} GBinderDriverContext;
|
||||
|
||||
static
|
||||
int
|
||||
gbinder_driver_txstatus(
|
||||
GBinderDriver* self,
|
||||
GBinderDriverContext* context,
|
||||
GBinderRemoteReply* reply);
|
||||
|
||||
/*==========================================================================*
|
||||
* Implementation
|
||||
@@ -143,21 +162,41 @@ gbinder_driver_verbose_transaction_data(
|
||||
guint n = 0;
|
||||
while (tx->objects[n]) n++;
|
||||
if (tx->status) {
|
||||
GVERBOSE("> %s %d (%u bytes, %u objects)", name, tx->status,
|
||||
(guint)tx->size, n);
|
||||
if (tx->target) {
|
||||
GVERBOSE("> %s %p %d (%u bytes, %u objects)", name,
|
||||
tx->target, tx->status, (guint)tx->size, n);
|
||||
} else {
|
||||
GVERBOSE("> %s (%u bytes, %u objects)", name,
|
||||
(guint)tx->size, n);
|
||||
GVERBOSE("> %s %d (%u bytes, %u objects)", name,
|
||||
tx->status, (guint)tx->size, n);
|
||||
}
|
||||
} else {
|
||||
if (tx->target) {
|
||||
GVERBOSE("> %s %p (%u bytes, %u objects)", name,
|
||||
tx->target, (guint)tx->size, n);
|
||||
} else {
|
||||
GVERBOSE("> %s (%u bytes, %u objects)", name, (guint)
|
||||
tx->size, n);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (tx->status) {
|
||||
GVERBOSE("> %s %d (%u bytes)", name, tx->status,
|
||||
(guint)tx->size);
|
||||
if (tx->target) {
|
||||
GVERBOSE("> %s %p %d (%u bytes)", name, tx->target,
|
||||
tx->status, (guint)tx->size);
|
||||
} else {
|
||||
GVERBOSE("> %s %d (%u bytes)", name, tx->status, (guint)
|
||||
tx->size);
|
||||
}
|
||||
} else {
|
||||
if (tx->target) {
|
||||
GVERBOSE("> %s %p (%u bytes)", name, tx->target, (guint)
|
||||
tx->size);
|
||||
} else {
|
||||
GVERBOSE("> %s (%u bytes)", name, (guint)tx->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -178,9 +217,11 @@ gbinder_driver_write(
|
||||
gbinder_driver_verbose_dump('<',
|
||||
buf->ptr + buf->consumed,
|
||||
buf->size - buf->consumed);
|
||||
GVERBOSE_("%u/%u", (guint)buf->consumed, (guint)buf->size);
|
||||
GVERBOSE("gbinder_driver_write(%d) %u/%u", self->fd,
|
||||
(guint)buf->consumed, (guint)buf->size);
|
||||
err = self->io->write_read(self->fd, buf, NULL);
|
||||
GVERBOSE_("%u/%u err %d", (guint)buf->consumed, (guint)buf->size, err);
|
||||
GVERBOSE("gbinder_driver_write(%d) %u/%u err %d", self->fd,
|
||||
(guint)buf->consumed, (guint)buf->size, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -190,11 +231,24 @@ int
|
||||
gbinder_driver_write_read(
|
||||
GBinderDriver* self,
|
||||
GBinderIoBuf* write,
|
||||
GBinderIoBuf* read)
|
||||
GBinderDriverReadBuf* rbuf)
|
||||
{
|
||||
int err = (-EAGAIN);
|
||||
GBinderIoBuf rio;
|
||||
GBinderIoBuf* read;
|
||||
|
||||
/* rbuf is never NULL */
|
||||
if (rbuf->offset) {
|
||||
rio.ptr = rbuf->io.ptr + rbuf->offset;
|
||||
rio.size = rbuf->io.size - rbuf->offset;
|
||||
rio.consumed = rbuf->io.consumed - rbuf->offset;
|
||||
read = &rio;
|
||||
} else {
|
||||
read = &rbuf->io;
|
||||
}
|
||||
|
||||
while (err == (-EAGAIN)) {
|
||||
|
||||
#if GUTIL_LOG_VERBOSE
|
||||
const gsize were_consumed = read ? read->consumed : 0;
|
||||
if (GLOG_ENABLED(GLOG_LEVEL_VERBOSE)) {
|
||||
@@ -203,7 +257,8 @@ gbinder_driver_write_read(
|
||||
write->ptr + write->consumed,
|
||||
write->size - write->consumed);
|
||||
}
|
||||
GVERBOSE_("write %u/%u read %u/%u",
|
||||
GVERBOSE("gbinder_driver_write_read(%d) "
|
||||
"write %u/%u read %u/%u", self->fd,
|
||||
(guint)(write ? write->consumed : 0),
|
||||
(guint)(write ? write->size : 0),
|
||||
(guint)(read ? read->consumed : 0),
|
||||
@@ -213,7 +268,8 @@ gbinder_driver_write_read(
|
||||
err = self->io->write_read(self->fd, write, read);
|
||||
#if GUTIL_LOG_VERBOSE
|
||||
if (GLOG_ENABLED(GLOG_LEVEL_VERBOSE)) {
|
||||
GVERBOSE_("write %u/%u read %u/%u err %d",
|
||||
GVERBOSE("gbinder_driver_write_read(%d) "
|
||||
"write %u/%u read %u/%u err %d", self->fd,
|
||||
(guint)(write ? write->consumed : 0),
|
||||
(guint)(write ? write->size : 0),
|
||||
(guint)(read ? read->consumed : 0),
|
||||
@@ -226,6 +282,10 @@ gbinder_driver_write_read(
|
||||
}
|
||||
#endif /* GUTIL_LOG_VERBOSE */
|
||||
}
|
||||
|
||||
if (rbuf->offset) {
|
||||
rbuf->io.consumed = rio.consumed + rbuf->offset;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -283,61 +343,80 @@ gbinder_driver_cmd_data(
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_driver_death_notification(
|
||||
gbinder_driver_handle_cookie(
|
||||
GBinderDriver* self,
|
||||
guint32 cmd,
|
||||
GBinderRemoteObject* obj)
|
||||
{
|
||||
if (G_LIKELY(obj)) {
|
||||
GBinderIoBuf write;
|
||||
guint8 buf[4 + GBINDER_MAX_DEATH_NOTIFICATION_SIZE];
|
||||
guint8 buf[4 + GBINDER_MAX_HANDLE_COOKIE_SIZE];
|
||||
guint32* data = (guint32*)buf;
|
||||
|
||||
data[0] = cmd;
|
||||
memset(&write, 0, sizeof(write));
|
||||
write.ptr = (uintptr_t)buf;
|
||||
write.size = 4 + self->io->encode_death_notification(data + 1, obj);
|
||||
|
||||
write.size = 4 + self->io->encode_handle_cookie(data + 1, obj);
|
||||
return gbinder_driver_write(self, &write) >= 0;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_driver_read_init(
|
||||
GBinderIoReadBuf* rb)
|
||||
GBinderDriverReadData* read)
|
||||
{
|
||||
rb->buf.ptr = (uintptr_t)(rb->data);
|
||||
rb->buf.size = sizeof(rb->data);
|
||||
rb->buf.consumed = 0;
|
||||
|
||||
/*
|
||||
* It shouldn't be necessary to zero-initialize the buffer but
|
||||
* valgrind complains about access to uninitialised data if we
|
||||
* don't do so. Oh well...
|
||||
* It shouldn't be necessary to zero-initialize the whole buffer
|
||||
* but valgrind complains about access to uninitialised data if
|
||||
* we don't do so. Oh well...
|
||||
*/
|
||||
memset(rb->data, 0, sizeof(rb->data));
|
||||
memset(read, 0, sizeof(*read));
|
||||
read->buf.io.ptr = GPOINTER_TO_SIZE(read->data);
|
||||
read->buf.io.size = sizeof(read->data);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_driver_context_init(
|
||||
GBinderDriverContext* context,
|
||||
GBinderDriverReadBuf* rbuf,
|
||||
GBinderObjectRegistry* reg,
|
||||
GBinderHandler* handler)
|
||||
{
|
||||
context->rbuf = rbuf;
|
||||
context->reg = reg;
|
||||
context->handler = handler;
|
||||
context->unrefs = NULL;
|
||||
context->bufs = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_driver_context_cleanup(
|
||||
GBinderDriverContext* context)
|
||||
{
|
||||
gbinder_cleanup_free(context->unrefs);
|
||||
gbinder_buffer_contents_list_free(context->bufs);
|
||||
}
|
||||
|
||||
static
|
||||
guint32
|
||||
gbinder_driver_next_command(
|
||||
GBinderDriver* self,
|
||||
const GBinderIoBuf* buf)
|
||||
const GBinderDriverReadBuf* rbuf)
|
||||
{
|
||||
const size_t remaining = buf->size - buf->consumed;
|
||||
guint32 cmd = 0;
|
||||
if (rbuf->io.consumed > rbuf->offset) {
|
||||
const gsize remaining = rbuf->io.consumed - rbuf->offset;
|
||||
|
||||
if (remaining >= sizeof(cmd)) {
|
||||
int datalen;
|
||||
if (remaining >= 4) {
|
||||
/* The size of the data to follow is encoded in the command code */
|
||||
cmd = *(guint32*)(buf->ptr + buf->consumed);
|
||||
datalen = _IOC_SIZE(cmd);
|
||||
if (remaining >= sizeof(cmd) + datalen) {
|
||||
const guint32 cmd = *(guint32*)(rbuf->io.ptr + rbuf->offset);
|
||||
const guint datalen = _IOC_SIZE(cmd);
|
||||
|
||||
if (remaining >= 4 + datalen) {
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -384,18 +463,18 @@ gbinder_driver_reply_data(
|
||||
GUtilIntArray* offsets = gbinder_output_data_offsets(data);
|
||||
void* offsets_buf = NULL;
|
||||
|
||||
/* Build BC_TRANSACTION */
|
||||
/* Build BC_REPLY */
|
||||
if (extra_buffers) {
|
||||
GVERBOSE("< BC_REPLY_SG %u bytes", (guint)extra_buffers);
|
||||
gbinder_driver_verbose_dump_bytes(' ', data->bytes);
|
||||
*cmd = io->bc.reply_sg;
|
||||
len += io->encode_transaction_sg(buf + len, 0, 0, data->bytes, 0,
|
||||
len += io->encode_reply_sg(buf + len, 0, 0, data->bytes,
|
||||
offsets, &offsets_buf, extra_buffers);
|
||||
} else {
|
||||
GVERBOSE("< BC_REPLY");
|
||||
gbinder_driver_verbose_dump_bytes(' ', data->bytes);
|
||||
*cmd = io->bc.reply;
|
||||
len += io->encode_transaction(buf + len, 0, 0, data->bytes, 0,
|
||||
len += io->encode_reply(buf + len, 0, 0, data->bytes,
|
||||
offsets, &offsets_buf);
|
||||
}
|
||||
|
||||
@@ -420,16 +499,16 @@ static
|
||||
void
|
||||
gbinder_driver_handle_transaction(
|
||||
GBinderDriver* self,
|
||||
GBinderObjectRegistry* reg,
|
||||
GBinderHandler* h,
|
||||
GBinderDriverContext* context,
|
||||
const void* data)
|
||||
{
|
||||
GBinderLocalReply* reply = NULL;
|
||||
GBinderObjectRegistry* reg = context->reg;
|
||||
GBinderRemoteRequest* req;
|
||||
GBinderIoTxData tx;
|
||||
GBinderLocalObject* obj;
|
||||
const char* iface;
|
||||
int status = -EBADMSG;
|
||||
int txstatus = -EBADMSG;
|
||||
|
||||
self->io->decode_transaction_data(data, &tx);
|
||||
gbinder_driver_verbose_transaction_data("BR_TRANSACTION", &tx);
|
||||
@@ -438,12 +517,15 @@ gbinder_driver_handle_transaction(
|
||||
|
||||
/* Transfer data ownership to the request */
|
||||
if (tx.data && tx.size) {
|
||||
GBinderBuffer* buf = gbinder_buffer_new(self,
|
||||
tx.data, tx.size, tx.objects);
|
||||
|
||||
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
|
||||
gbinder_remote_request_set_data(req,
|
||||
gbinder_buffer_new(self, tx.data, tx.size),
|
||||
tx.objects);
|
||||
gbinder_remote_request_set_data(req, tx.code, buf);
|
||||
context->bufs = gbinder_buffer_contents_list_add(context->bufs,
|
||||
gbinder_buffer_contents(buf));
|
||||
} else {
|
||||
g_free(tx.objects);
|
||||
GASSERT(!tx.objects);
|
||||
gbinder_driver_free_buffer(self, tx.data);
|
||||
}
|
||||
|
||||
@@ -452,24 +534,42 @@ gbinder_driver_handle_transaction(
|
||||
switch (gbinder_local_object_can_handle_transaction(obj, iface, tx.code)) {
|
||||
case GBINDER_LOCAL_TRANSACTION_LOOPER:
|
||||
reply = gbinder_local_object_handle_looper_transaction(obj, req,
|
||||
tx.code, tx.flags, &status);
|
||||
tx.code, tx.flags, &txstatus);
|
||||
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 = context->handler ?
|
||||
gbinder_handler_transact(context->handler, obj, req, tx.code,
|
||||
tx.flags, &txstatus) :
|
||||
gbinder_local_object_handle_transaction(obj, req, tx.code,
|
||||
tx.flags, &txstatus);
|
||||
break;
|
||||
default:
|
||||
GWARN("Unhandled transaction 0x%08x", tx.code);
|
||||
GWARN("Unhandled transaction %s 0x%08x", iface, tx.code);
|
||||
break;
|
||||
}
|
||||
|
||||
/* No reply for one-way transactions */
|
||||
if (!(tx.flags & GBINDER_TX_FLAG_ONEWAY)) {
|
||||
if (reply) {
|
||||
context->bufs = gbinder_buffer_contents_list_add(context->bufs,
|
||||
gbinder_local_reply_contents(reply));
|
||||
gbinder_driver_reply_data(self, gbinder_local_reply_data(reply));
|
||||
} else {
|
||||
gbinder_driver_reply_status(self, status);
|
||||
gbinder_driver_reply_status(self, txstatus);
|
||||
}
|
||||
|
||||
/* Wait until the reply is handled */
|
||||
do {
|
||||
txstatus = gbinder_driver_write_read(self, NULL, context->rbuf);
|
||||
if (txstatus >= 0) {
|
||||
txstatus = gbinder_driver_txstatus(self, context, NULL);
|
||||
}
|
||||
} while (txstatus == (-EAGAIN));
|
||||
}
|
||||
|
||||
/* Free the data allocated for the transaction */
|
||||
@@ -478,23 +578,45 @@ gbinder_driver_handle_transaction(
|
||||
gbinder_local_object_unref(obj);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_driver_cleanup_decrefs(
|
||||
gpointer pointer)
|
||||
{
|
||||
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(pointer);
|
||||
|
||||
gbinder_local_object_handle_decrefs(obj);
|
||||
gbinder_local_object_unref(obj);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_driver_cleanup_release(
|
||||
gpointer pointer)
|
||||
{
|
||||
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(pointer);
|
||||
|
||||
gbinder_local_object_handle_release(obj);
|
||||
gbinder_local_object_unref(obj);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_driver_handle_command(
|
||||
GBinderDriver* self,
|
||||
GBinderObjectRegistry* reg,
|
||||
GBinderHandler* handler,
|
||||
GBinderDriverContext* context,
|
||||
guint32 cmd,
|
||||
const void* data)
|
||||
{
|
||||
const GBinderIo* io = self->io;
|
||||
GBinderObjectRegistry* reg = context->reg;
|
||||
|
||||
if (cmd == io->br.noop) {
|
||||
GVERBOSE("> BR_NOOP");
|
||||
} else if (cmd == io->br.ok) {
|
||||
GVERBOSE("> BR_OK");
|
||||
} else if (cmd == io->br.transaction_complete) {
|
||||
GVERBOSE("> BR_TRANSACTION_COMPLETE");
|
||||
GVERBOSE("> BR_TRANSACTION_COMPLETE (?)");
|
||||
} else if (cmd == io->br.spawn_looper) {
|
||||
GVERBOSE("> BR_SPAWN_LOOPER");
|
||||
} else if (cmd == io->br.finished) {
|
||||
@@ -502,7 +624,7 @@ gbinder_driver_handle_command(
|
||||
} else if (cmd == io->br.increfs) {
|
||||
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
|
||||
GBinderLocalObject* obj = gbinder_object_registry_get_local
|
||||
(reg, io->decode_binder_ptr_cookie(data));
|
||||
(reg, io->decode_ptr_cookie(data));
|
||||
|
||||
GVERBOSE("> BR_INCREFS %p", obj);
|
||||
gbinder_local_object_handle_increfs(obj);
|
||||
@@ -511,111 +633,150 @@ gbinder_driver_handle_command(
|
||||
gbinder_driver_cmd_data(self, io->bc.increfs_done, data, buf);
|
||||
} else if (cmd == io->br.decrefs) {
|
||||
GBinderLocalObject* obj = gbinder_object_registry_get_local
|
||||
(reg, io->decode_binder_ptr_cookie(data));
|
||||
(reg, io->decode_ptr_cookie(data));
|
||||
|
||||
GVERBOSE("> BR_DECREFS %p", obj);
|
||||
gbinder_local_object_handle_decrefs(obj);
|
||||
gbinder_local_object_unref(obj);
|
||||
if (obj) {
|
||||
/*
|
||||
* Unrefs must be processed only after clearing the incoming
|
||||
* command queue.
|
||||
*/
|
||||
context->unrefs = gbinder_cleanup_add(context->unrefs,
|
||||
gbinder_driver_cleanup_decrefs, obj);
|
||||
}
|
||||
} else if (cmd == io->br.acquire) {
|
||||
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
|
||||
GBinderLocalObject* obj = gbinder_object_registry_get_local
|
||||
(reg, io->decode_binder_ptr_cookie(data));
|
||||
(reg, io->decode_ptr_cookie(data));
|
||||
|
||||
GVERBOSE("> BR_ACQUIRE %p", obj);
|
||||
gbinder_local_object_handle_acquire(obj);
|
||||
if (obj) {
|
||||
/* BC_ACQUIRE_DONE will be sent after the request is handled */
|
||||
gbinder_local_object_handle_acquire(obj, context->bufs);
|
||||
gbinder_local_object_unref(obj);
|
||||
GVERBOSE("< BC_ACQUIRE_DONE %p", obj);
|
||||
} else {
|
||||
/* This shouldn't normally happen. Just send the same data back. */
|
||||
GVERBOSE("< BC_ACQUIRE_DONE");
|
||||
gbinder_driver_cmd_data(self, io->bc.acquire_done, data, buf);
|
||||
}
|
||||
} else if (cmd == io->br.release) {
|
||||
GBinderLocalObject* obj = gbinder_object_registry_get_local
|
||||
(reg, io->decode_binder_ptr_cookie(data));
|
||||
(reg, io->decode_ptr_cookie(data));
|
||||
|
||||
GVERBOSE("> BR_RELEASE %p", obj);
|
||||
gbinder_local_object_handle_release(obj);
|
||||
gbinder_local_object_unref(obj);
|
||||
if (obj) {
|
||||
/*
|
||||
* Unrefs must be processed only after clearing the incoming
|
||||
* command queue.
|
||||
*/
|
||||
context->unrefs = gbinder_cleanup_add(context->unrefs,
|
||||
gbinder_driver_cleanup_release, obj);
|
||||
}
|
||||
} else if (cmd == io->br.transaction) {
|
||||
gbinder_driver_handle_transaction(self, reg, handler, data);
|
||||
gbinder_driver_handle_transaction(self, context, data);
|
||||
} else if (cmd == io->br.dead_binder) {
|
||||
guint64 handle = 0;
|
||||
GBinderRemoteObject* obj;
|
||||
|
||||
io->decode_cookie(data, &handle);
|
||||
GVERBOSE("> BR_DEAD_BINDER %llu", (long long unsigned int)handle);
|
||||
obj = gbinder_object_registry_get_remote(reg, (guint32)handle);
|
||||
GVERBOSE("> BR_DEAD_BINDER 0x%08llx", (long long unsigned int) handle);
|
||||
obj = gbinder_object_registry_get_remote(reg, (guint32)handle,
|
||||
REMOTE_REGISTRY_DONT_CREATE);
|
||||
if (obj) {
|
||||
/* BC_DEAD_BINDER_DONE will be sent after the request is handled */
|
||||
gbinder_remote_object_handle_death_notification(obj);
|
||||
gbinder_remote_object_unref(obj);
|
||||
} else {
|
||||
guint8 buf[4 + GBINDER_MAX_COOKIE_SIZE];
|
||||
|
||||
/* This shouldn't normally happen. Just send the same data back. */
|
||||
GVERBOSE("< BC_DEAD_BINDER_DONE 0x%08llx", (long long unsigned int)
|
||||
handle);
|
||||
gbinder_driver_cmd_data(self, io->bc.dead_binder_done, data, buf);
|
||||
}
|
||||
} else if (cmd == io->br.clear_death_notification_done) {
|
||||
GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE");
|
||||
#if GUTIL_LOG_VERBOSE
|
||||
if (GLOG_ENABLED(GLOG_LEVEL_VERBOSE)) {
|
||||
guint64 handle = 0;
|
||||
|
||||
io->decode_cookie(data, &handle);
|
||||
GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE 0x%08llx",
|
||||
(long long unsigned int) handle);
|
||||
}
|
||||
#endif /* GUTIL_LOG_VERBOSE */
|
||||
} else {
|
||||
#pragma message("TODO: handle more commands from the driver")
|
||||
GWARN("Unexpected command 0x%08x", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_driver_compact_read_buf(
|
||||
GBinderDriverReadBuf* buf)
|
||||
{
|
||||
/*
|
||||
* Move the data to the beginning of the buffer to make room for the
|
||||
* next portion of data (in case if we need one)
|
||||
*/
|
||||
if (buf->io.consumed > buf->offset) {
|
||||
const gsize unprocessed = buf->io.consumed - buf->offset;
|
||||
guint8* data = GSIZE_TO_POINTER(buf->io.ptr);
|
||||
|
||||
memmove(data, data + buf->offset, unprocessed);
|
||||
buf->io.consumed = unprocessed;
|
||||
} else {
|
||||
buf->io.consumed = 0;
|
||||
}
|
||||
buf->offset = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_driver_handle_commands(
|
||||
GBinderDriver* self,
|
||||
GBinderObjectRegistry* reg,
|
||||
GBinderHandler* handler,
|
||||
GBinderIoReadBuf* rb)
|
||||
GBinderDriverContext* context)
|
||||
{
|
||||
GBinderDriverReadBuf* rbuf = context->rbuf;
|
||||
guint32 cmd;
|
||||
gsize unprocessed;
|
||||
GBinderIoBuf buf;
|
||||
|
||||
buf.ptr = rb->buf.ptr;
|
||||
buf.size = rb->buf.consumed;
|
||||
buf.consumed = 0;
|
||||
|
||||
while ((cmd = gbinder_driver_next_command(self, &buf)) != 0) {
|
||||
const size_t datalen = _IOC_SIZE(cmd);
|
||||
const size_t total = datalen + sizeof(cmd);
|
||||
while ((cmd = gbinder_driver_next_command(self, rbuf)) != 0) {
|
||||
const gsize datalen = _IOC_SIZE(cmd);
|
||||
const gsize total = datalen + sizeof(cmd);
|
||||
const void* data = GSIZE_TO_POINTER(rbuf->io.ptr + rbuf->offset + 4);
|
||||
|
||||
/* Handle this command */
|
||||
gbinder_driver_handle_command(self, reg, handler, cmd,
|
||||
(void*)(buf.ptr + buf.consumed + sizeof(cmd)));
|
||||
|
||||
/* Switch to the next packet in the buffer */
|
||||
buf.consumed += total;
|
||||
rbuf->offset += total;
|
||||
gbinder_driver_handle_command(self, context, cmd, data);
|
||||
}
|
||||
|
||||
/* Move the data to the beginning of the buffer to make room for the
|
||||
* next portion of data (in case if we need one) */
|
||||
unprocessed = buf.size - buf.consumed;
|
||||
memmove(rb->data, rb->data + buf.consumed, unprocessed);
|
||||
rb->buf.consumed = unprocessed;
|
||||
gbinder_driver_compact_read_buf(rbuf);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
gbinder_driver_txstatus(
|
||||
GBinderDriver* self,
|
||||
GBinderObjectRegistry* reg,
|
||||
GBinderHandler* handler,
|
||||
GBinderIoReadBuf* rb,
|
||||
GBinderDriverContext* context,
|
||||
GBinderRemoteReply* reply)
|
||||
{
|
||||
guint32 cmd;
|
||||
gsize unprocessed;
|
||||
int txstatus = (-EAGAIN);
|
||||
GBinderIoBuf buf;
|
||||
GBinderDriverReadBuf* rbuf = context->rbuf;
|
||||
const guint8* buf = GSIZE_TO_POINTER(rbuf->io.ptr);
|
||||
const GBinderIo* io = self->io;
|
||||
|
||||
buf.ptr = rb->buf.ptr;
|
||||
buf.size = rb->buf.consumed;
|
||||
buf.consumed = 0;
|
||||
|
||||
while (txstatus == (-EAGAIN) && (cmd =
|
||||
gbinder_driver_next_command(self, &buf)) != 0) {
|
||||
gbinder_driver_next_command(self, context->rbuf)) != 0) {
|
||||
/* The size of the data is encoded in the command code */
|
||||
const size_t datalen = _IOC_SIZE(cmd);
|
||||
const size_t total = datalen + sizeof(cmd);
|
||||
const void* data = (void*)(buf.ptr + buf.consumed + sizeof(cmd));
|
||||
const gsize datalen = _IOC_SIZE(cmd);
|
||||
const gsize total = datalen + sizeof(cmd);
|
||||
const void* data = buf + rbuf->offset + sizeof(cmd);
|
||||
|
||||
/* Handle the packet */
|
||||
/* Swallow this packet */
|
||||
rbuf->offset += total;
|
||||
|
||||
/* Handle the command */
|
||||
if (cmd == io->br.transaction_complete) {
|
||||
GVERBOSE("> BR_TRANSACTION_COMPLETE");
|
||||
if (!reply) {
|
||||
@@ -633,33 +794,44 @@ gbinder_driver_txstatus(
|
||||
io->decode_transaction_data(data, &tx);
|
||||
gbinder_driver_verbose_transaction_data("BR_REPLY", &tx);
|
||||
|
||||
/* Transfer data ownership to the request */
|
||||
/* Transfer data ownership to the reply */
|
||||
if (tx.data && tx.size) {
|
||||
GBinderBuffer* buf = gbinder_buffer_new(self,
|
||||
tx.data, tx.size, tx.objects);
|
||||
|
||||
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
|
||||
gbinder_remote_reply_set_data(reply,
|
||||
gbinder_buffer_new(self, tx.data, tx.size),
|
||||
tx.objects);
|
||||
gbinder_remote_reply_set_data(reply, buf);
|
||||
context->bufs = gbinder_buffer_contents_list_add(context->bufs,
|
||||
gbinder_buffer_contents(buf));
|
||||
} else {
|
||||
g_free(tx.objects);
|
||||
GASSERT(!tx.objects);
|
||||
gbinder_driver_free_buffer(self, tx.data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Filter out special cases. It's a bit unfortunate that
|
||||
* libgbinder API historically mixed TF_STATUS_CODE payload
|
||||
* with special delivery errors. It's not a bit deal though,
|
||||
* because in real life TF_STATUS_CODE transactions are not
|
||||
* being used that often, if at all.
|
||||
*/
|
||||
switch (tx.status) {
|
||||
case (-EAGAIN):
|
||||
case GBINDER_STATUS_FAILED:
|
||||
case GBINDER_STATUS_DEAD_OBJECT:
|
||||
txstatus = (-EFAULT);
|
||||
GWARN("Replacing tx status %d with %d", tx.status, txstatus);
|
||||
break;
|
||||
default:
|
||||
txstatus = tx.status;
|
||||
GASSERT(txstatus != (-EAGAIN));
|
||||
if (txstatus == (-EAGAIN)) txstatus = (-EFAULT);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
gbinder_driver_handle_command(self, reg, handler, cmd, data);
|
||||
gbinder_driver_handle_command(self, context, cmd, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch to the next packet in the buffer */
|
||||
buf.consumed += total;
|
||||
}
|
||||
|
||||
/* Move the data to the beginning of the buffer to make room for the
|
||||
* next portion of data (in case if we need one) */
|
||||
unprocessed = buf.size - buf.consumed;
|
||||
memmove(rb->data, rb->data + buf.consumed, unprocessed);
|
||||
rb->buf.consumed = unprocessed;
|
||||
gbinder_driver_compact_read_buf(rbuf);
|
||||
return txstatus;
|
||||
}
|
||||
|
||||
@@ -713,7 +885,7 @@ gbinder_driver_new(
|
||||
max_threads, strerror(errno));
|
||||
}
|
||||
/* Choose the protocol based on the device name
|
||||
* if none is explicitely specified */
|
||||
* if none is explicitly specified */
|
||||
self->protocol = protocol ? protocol :
|
||||
gbinder_rpc_protocol_for_device(dev);
|
||||
return self;
|
||||
@@ -746,11 +918,23 @@ gbinder_driver_unref(
|
||||
{
|
||||
GASSERT(self->refcount > 0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
gbinder_driver_close(self);
|
||||
g_free(self->dev);
|
||||
g_slice_free(GBinderDriver, self);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_driver_close(
|
||||
GBinderDriver* self)
|
||||
{
|
||||
if (self->vm) {
|
||||
GDEBUG("Closing %s", self->dev);
|
||||
gbinder_system_munmap(self->vm, self->vmsize);
|
||||
gbinder_system_close(self->fd);
|
||||
g_free(self->dev);
|
||||
g_slice_free(GBinderDriver, self);
|
||||
self->fd = -1;
|
||||
self->vm = NULL;
|
||||
self->vmsize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -809,13 +993,67 @@ gbinder_driver_io(
|
||||
return self->io;
|
||||
}
|
||||
|
||||
const GBinderRpcProtocol*
|
||||
gbinder_driver_protocol(
|
||||
GBinderDriver* self)
|
||||
{
|
||||
return self->protocol;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_driver_acquire_done(
|
||||
GBinderDriver* self,
|
||||
GBinderLocalObject* obj)
|
||||
{
|
||||
GBinderIoBuf write;
|
||||
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
|
||||
guint32* data = (guint32*)buf;
|
||||
const GBinderIo* io = self->io;
|
||||
|
||||
data[0] = io->bc.acquire_done;
|
||||
memset(&write, 0, sizeof(write));
|
||||
write.ptr = (uintptr_t)buf;
|
||||
write.size = 4 + io->encode_ptr_cookie(data + 1, obj);
|
||||
|
||||
GVERBOSE("< BC_ACQUIRE_DONE %p", obj);
|
||||
return gbinder_driver_write(self, &write) >= 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_driver_dead_binder_done(
|
||||
GBinderDriver* self,
|
||||
GBinderRemoteObject* obj)
|
||||
{
|
||||
if (G_LIKELY(obj)) {
|
||||
GBinderIoBuf write;
|
||||
guint8 buf[4 + GBINDER_MAX_COOKIE_SIZE];
|
||||
guint32* data = (guint32*)buf;
|
||||
const GBinderIo* io = self->io;
|
||||
|
||||
data[0] = io->bc.dead_binder_done;
|
||||
memset(&write, 0, sizeof(write));
|
||||
write.ptr = (uintptr_t)buf;
|
||||
write.size = 4 + io->encode_cookie(data + 1, obj->handle);
|
||||
|
||||
GVERBOSE("< BC_DEAD_BINDER_DONE 0x%08x", obj->handle);
|
||||
return gbinder_driver_write(self, &write) >= 0;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_driver_request_death_notification(
|
||||
GBinderDriver* self,
|
||||
GBinderRemoteObject* obj)
|
||||
{
|
||||
return gbinder_driver_death_notification
|
||||
(self, self->io->bc.request_death_notification, obj);
|
||||
if (G_LIKELY(obj)) {
|
||||
GVERBOSE("< BC_REQUEST_DEATH_NOTIFICATION 0x%08x", obj->handle);
|
||||
return gbinder_driver_handle_cookie(self,
|
||||
self->io->bc.request_death_notification, obj);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -823,8 +1061,13 @@ gbinder_driver_clear_death_notification(
|
||||
GBinderDriver* self,
|
||||
GBinderRemoteObject* obj)
|
||||
{
|
||||
return gbinder_driver_death_notification
|
||||
(self, self->io->bc.clear_death_notification, obj);
|
||||
if (G_LIKELY(obj)) {
|
||||
GVERBOSE("< BC_CLEAR_DEATH_NOTIFICATION 0x%08x", obj->handle);
|
||||
return gbinder_driver_handle_cookie(self,
|
||||
self->io->bc.clear_death_notification, obj);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -863,6 +1106,32 @@ gbinder_driver_release(
|
||||
return gbinder_driver_cmd_int32(self, self->io->bc.release, handle);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_driver_close_fds(
|
||||
GBinderDriver* self,
|
||||
void** objects,
|
||||
const void* end)
|
||||
{
|
||||
const GBinderIo* io = self->io;
|
||||
void** ptr;
|
||||
|
||||
/* Caller checks objects for NULL */
|
||||
for (ptr = objects; *ptr; ptr++) {
|
||||
void* obj = *ptr;
|
||||
|
||||
GASSERT(obj < end);
|
||||
if (obj < end) {
|
||||
int fd;
|
||||
|
||||
if (io->decode_fd_object(obj, (guint8*)end - (guint8*)obj, &fd)) {
|
||||
if (close(fd) < 0) {
|
||||
GWARN("Error closing fd %d: %s", fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_driver_free_buffer(
|
||||
GBinderDriver* self,
|
||||
@@ -909,23 +1178,26 @@ gbinder_driver_read(
|
||||
GBinderObjectRegistry* reg,
|
||||
GBinderHandler* handler)
|
||||
{
|
||||
GBinderIoReadBuf rb;
|
||||
GBinderDriverReadData read;
|
||||
GBinderDriverContext context;
|
||||
int ret;
|
||||
|
||||
gbinder_driver_read_init(&rb);
|
||||
ret = gbinder_driver_write_read(self, NULL, &rb.buf);
|
||||
gbinder_driver_read_init(&read);
|
||||
gbinder_driver_context_init(&context, &read.buf, reg, handler);
|
||||
ret = gbinder_driver_write_read(self, NULL, context.rbuf);
|
||||
if (ret >= 0) {
|
||||
/* Loop until we have handled all the incoming commands */
|
||||
gbinder_driver_handle_commands(self, reg, handler, &rb);
|
||||
while (rb.buf.consumed) {
|
||||
ret = gbinder_driver_write_read(self, NULL, &rb.buf);
|
||||
gbinder_driver_handle_commands(self, &context);
|
||||
while (read.buf.io.consumed && gbinder_handler_can_loop(handler)) {
|
||||
ret = gbinder_driver_write_read(self, NULL, context.rbuf);
|
||||
if (ret >= 0) {
|
||||
gbinder_driver_handle_commands(self, reg, handler, &rb);
|
||||
gbinder_driver_handle_commands(self, &context);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
gbinder_driver_context_cleanup(&context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -933,13 +1205,16 @@ int
|
||||
gbinder_driver_transact(
|
||||
GBinderDriver* self,
|
||||
GBinderObjectRegistry* reg,
|
||||
GBinderHandler* handler,
|
||||
guint32 handle,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req,
|
||||
GBinderRemoteReply* reply)
|
||||
{
|
||||
GBinderDriverReadData read;
|
||||
GBinderDriverContext context;
|
||||
GBinderIoBuf write;
|
||||
GBinderIoReadBuf rb;
|
||||
GBinderDriverReadBuf* rbuf = &read.buf;
|
||||
const GBinderIo* io = self->io;
|
||||
const guint flags = reply ? 0 : GBINDER_TX_FLAG_ONEWAY;
|
||||
GBinderOutputData* data = gbinder_local_request_data(req);
|
||||
@@ -951,7 +1226,8 @@ gbinder_driver_transact(
|
||||
guint len = sizeof(*cmd);
|
||||
int txstatus = (-EAGAIN);
|
||||
|
||||
gbinder_driver_read_init(&rb);
|
||||
gbinder_driver_read_init(&read);
|
||||
gbinder_driver_context_init(&context, &read.buf, reg, handler);
|
||||
|
||||
/* Build BC_TRANSACTION */
|
||||
if (extra_buffers) {
|
||||
@@ -985,11 +1261,11 @@ gbinder_driver_transact(
|
||||
* negative is a driver error (except for -EAGAIN meaning that there's
|
||||
* no status yet) */
|
||||
while (txstatus == (-EAGAIN)) {
|
||||
int err = gbinder_driver_write_read(self, &write, &rb.buf);
|
||||
int err = gbinder_driver_write_read(self, &write, rbuf);
|
||||
if (err < 0) {
|
||||
txstatus = err;
|
||||
} else {
|
||||
txstatus = gbinder_driver_txstatus(self, reg, NULL, &rb, reply);
|
||||
txstatus = gbinder_driver_txstatus(self, &context, reply);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,18 +1274,19 @@ 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);
|
||||
while (rb.buf.consumed) {
|
||||
int err = gbinder_driver_write_read(self, NULL, &rb.buf);
|
||||
gbinder_driver_handle_commands(self, &context);
|
||||
while (rbuf->io.consumed) {
|
||||
int err = gbinder_driver_write_read(self, NULL, rbuf);
|
||||
if (err < 0) {
|
||||
txstatus = err;
|
||||
break;
|
||||
} else {
|
||||
gbinder_driver_handle_commands(self, reg, NULL, &rb);
|
||||
gbinder_driver_handle_commands(self, &context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gbinder_driver_context_cleanup(&context);
|
||||
g_free(offsets_buf);
|
||||
return txstatus;
|
||||
}
|
||||
@@ -1018,12 +1295,19 @@ GBinderLocalRequest*
|
||||
gbinder_driver_local_request_new(
|
||||
GBinderDriver* self,
|
||||
const char* iface)
|
||||
{
|
||||
return gbinder_local_request_new_iface(self->io, self->protocol, iface);
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_driver_local_request_new_ping(
|
||||
GBinderDriver* self)
|
||||
{
|
||||
GBinderLocalRequest* req = gbinder_local_request_new(self->io, NULL);
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
self->protocol->write_rpc_header(&writer, iface);
|
||||
self->protocol->write_ping(&writer);
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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,95 +40,149 @@ 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;
|
||||
|
||||
void
|
||||
gbinder_driver_close(
|
||||
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;
|
||||
|
||||
const GBinderRpcProtocol*
|
||||
gbinder_driver_protocol(
|
||||
GBinderDriver* driver)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
gboolean
|
||||
gbinder_driver_acquire_done(
|
||||
GBinderDriver* driver,
|
||||
GBinderLocalObject* obj)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
gboolean
|
||||
gbinder_driver_dead_binder_done(
|
||||
GBinderDriver* driver,
|
||||
GBinderRemoteObject* obj)
|
||||
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* driver,
|
||||
void** objects,
|
||||
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;
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_driver_local_request_new(
|
||||
GBinderDriver* self,
|
||||
const char* iface);
|
||||
GBinderDriver* driver,
|
||||
const char* iface)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_driver_local_request_new_ping(
|
||||
GBinderDriver* self)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_DRIVER_H */
|
||||
|
||||
|
||||
405
src/gbinder_eventloop.c
Normal file
405
src/gbinder_eventloop.c
Normal file
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Jolla Ltd.
|
||||
* Copyright (C) 2020-2021 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>
|
||||
|
||||
typedef struct gbinder_idle_callback_data {
|
||||
GBinderEventLoopCallback* cb;
|
||||
GBinderEventLoopCallbackFunc func;
|
||||
GDestroyNotify destroy;
|
||||
gpointer data;
|
||||
} GBinderIdleCallbackData;
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
/*==========================================================================*
|
||||
* Implementation
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_idle_callback_invoke_proc(
|
||||
void* user_data)
|
||||
{
|
||||
GBinderIdleCallbackData* idle = user_data;
|
||||
|
||||
if (idle->func) {
|
||||
idle->func(idle->data);
|
||||
}
|
||||
gbinder_idle_callback_unref(idle->cb);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_idle_callback_invoke_done(
|
||||
void* user_data)
|
||||
{
|
||||
GBinderIdleCallbackData* idle = user_data;
|
||||
|
||||
if (idle->destroy) {
|
||||
idle->destroy(idle->data);
|
||||
}
|
||||
gutil_slice_free(idle);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Non-cancellable callback */
|
||||
void
|
||||
gbinder_idle_callback_invoke_later(
|
||||
GBinderEventLoopCallbackFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify destroy)
|
||||
{
|
||||
GBinderIdleCallbackData* idle = g_slice_new(GBinderIdleCallbackData);
|
||||
|
||||
idle->func = func;
|
||||
idle->data = data;
|
||||
idle->destroy = destroy;
|
||||
idle->cb = gbinder_idle_callback_new(gbinder_idle_callback_invoke_proc,
|
||||
idle, gbinder_idle_callback_invoke_done);
|
||||
gbinder_idle_callback_schedule(idle->cb);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Public interface
|
||||
*==========================================================================*/
|
||||
|
||||
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:
|
||||
*/
|
||||
115
src/gbinder_eventloop_p.h
Normal file
115
src/gbinder_eventloop_p.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Jolla Ltd.
|
||||
* Copyright (C) 2020-2021 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)
|
||||
G_GNUC_WARN_UNUSED_RESULT
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderEventLoopTimeout*
|
||||
gbinder_idle_add(
|
||||
GSourceFunc func,
|
||||
gpointer data)
|
||||
G_GNUC_WARN_UNUSED_RESULT
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_timeout_remove(
|
||||
GBinderEventLoopTimeout* timeout)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderEventLoopCallback*
|
||||
gbinder_idle_callback_new(
|
||||
GBinderEventLoopCallbackFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify destroy)
|
||||
G_GNUC_WARN_UNUSED_RESULT
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderEventLoopCallback*
|
||||
gbinder_idle_callback_schedule_new(
|
||||
GBinderEventLoopCallbackFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify destroy)
|
||||
G_GNUC_WARN_UNUSED_RESULT
|
||||
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;
|
||||
|
||||
void
|
||||
gbinder_idle_callback_invoke_later(
|
||||
GBinderEventLoopCallbackFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify destroy)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_EVENTLOOP_PRIVATE_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -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
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "gbinder_types_p.h"
|
||||
|
||||
typedef struct gbinder_handler_functions {
|
||||
gboolean (*can_loop)(GBinderHandler* handler);
|
||||
GBinderLocalReply* (*transact)(GBinderHandler* handler,
|
||||
GBinderLocalObject* obj, GBinderRemoteRequest* req, guint code,
|
||||
guint flags, int* status);
|
||||
@@ -47,6 +48,14 @@ struct gbinder_handler {
|
||||
|
||||
/* Inline wrappers */
|
||||
|
||||
GBINDER_INLINE_FUNC
|
||||
gboolean
|
||||
gbinder_handler_can_loop(
|
||||
GBinderHandler* self)
|
||||
{
|
||||
return self && self->f->can_loop && self->f->can_loop(self);
|
||||
}
|
||||
|
||||
GBINDER_INLINE_FUNC
|
||||
GBinderLocalReply*
|
||||
gbinder_handler_transact(
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 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_log.h"
|
||||
|
||||
#include <gbinder_client.h>
|
||||
#include <gbinder_local_request.h>
|
||||
#include <gbinder_remote_reply.h>
|
||||
#include <gbinder_reader.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
|
||||
typedef GBinderServiceManager GBinderHwServiceManager;
|
||||
typedef GBinderServiceManagerClass GBinderHwServiceManagerClass;
|
||||
|
||||
G_DEFINE_TYPE(GBinderHwServiceManager,
|
||||
gbinder_hwservicemanager,
|
||||
GBINDER_TYPE_SERVICEMANAGER)
|
||||
|
||||
enum gbinder_hwservicemanager_calls {
|
||||
GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
|
||||
ADD_TRANSACTION,
|
||||
GET_TRANSPORT_TRANSACTION,
|
||||
LIST_TRANSACTION,
|
||||
LIST_BY_INTERFACE_TRANSACTION,
|
||||
REGISTER_FOR_NOTIFICATIONS_TRANSACTION,
|
||||
DEBUG_DUMP_TRANSACTION,
|
||||
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
|
||||
};
|
||||
|
||||
/* As a special case, ServiceManager's handle is zero */
|
||||
#define HWSERVICEMANAGER_HANDLE (0)
|
||||
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_hwservicemanager_new(
|
||||
const char* dev)
|
||||
{
|
||||
return gbinder_servicemanager_new_with_type
|
||||
(gbinder_hwservicemanager_get_type(), dev);
|
||||
}
|
||||
|
||||
static
|
||||
char**
|
||||
gbinder_hwservicemanager_list(
|
||||
GBinderHwServiceManager* self)
|
||||
{
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply
|
||||
(self->client, LIST_TRANSACTION, req, NULL);
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
if (reply) {
|
||||
GBinderReader reader;
|
||||
char** result = NULL;
|
||||
int status = -1;
|
||||
|
||||
gbinder_remote_reply_init_reader(reply, &reader);
|
||||
|
||||
/* Read status */
|
||||
GVERIFY(gbinder_reader_read_int32(&reader, &status));
|
||||
GASSERT(status == GBINDER_STATUS_OK);
|
||||
|
||||
/* Followed by hidl_vec<string> */
|
||||
result = gbinder_reader_read_hidl_string_vec(&reader);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
return result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderRemoteObject*
|
||||
gbinder_hwservicemanager_get_service(
|
||||
GBinderServiceManager* self,
|
||||
const char* fqinstance,
|
||||
int* status)
|
||||
{
|
||||
/* e.g. "android.hardware.radio@1.1::IRadio/slot1" */
|
||||
const char* sep = strchr(fqinstance, '/');
|
||||
GBinderRemoteObject* obj = NULL;
|
||||
if (sep) {
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||
char* fqname = g_strndup(fqinstance, sep - fqinstance);
|
||||
const char* name = sep + 1;
|
||||
|
||||
gbinder_local_request_append_hidl_string(req, fqname);
|
||||
gbinder_local_request_append_hidl_string(req, name);
|
||||
|
||||
reply = gbinder_client_transact_sync_reply(self->client,
|
||||
GET_TRANSACTION, req, status);
|
||||
|
||||
if (reply) {
|
||||
GBinderReader reader;
|
||||
int status = -1;
|
||||
|
||||
gbinder_remote_reply_init_reader(reply, &reader);
|
||||
|
||||
/* Read status */
|
||||
GVERIFY(gbinder_reader_read_int32(&reader, &status));
|
||||
GASSERT(status == GBINDER_STATUS_OK);
|
||||
|
||||
/* Read the object */
|
||||
obj = gbinder_reader_read_object(&reader);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
}
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
g_free(fqname);
|
||||
} else {
|
||||
GERR("Invalid instance \"%s\"", fqinstance);
|
||||
if (status) *status = (-EINVAL);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
gbinder_hwservicemanager_add_service(
|
||||
GBinderServiceManager* self,
|
||||
const char* name,
|
||||
GBinderLocalObject* obj)
|
||||
{
|
||||
int status;
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||
|
||||
/* add(string name, interface service) generates (bool success); */
|
||||
gbinder_local_request_append_hidl_string(req, name);
|
||||
gbinder_local_request_append_local_object(req, obj);
|
||||
|
||||
reply = gbinder_client_transact_sync_reply(self->client,
|
||||
ADD_TRANSACTION, req, &status);
|
||||
|
||||
gbinder_remote_reply_unref(reply);
|
||||
gbinder_local_request_unref(req);
|
||||
return status;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_hwservicemanager_init(
|
||||
GBinderHwServiceManager* self)
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_hwservicemanager_class_init(
|
||||
GBinderHwServiceManagerClass* klass)
|
||||
{
|
||||
klass->handle = HWSERVICEMANAGER_HANDLE;
|
||||
klass->iface = HWSERVICEMANAGER_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
228
src/gbinder_io.c
228
src/gbinder_io.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -90,19 +90,49 @@ GBINDER_IO_FN(write_read)(
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns size of the object */
|
||||
static
|
||||
gsize
|
||||
GBINDER_IO_FN(object_size)(
|
||||
const void* obj)
|
||||
{
|
||||
if (obj) {
|
||||
const struct binder_object_header* hdr = obj;
|
||||
|
||||
switch (hdr->type) {
|
||||
case BINDER_TYPE_BINDER:
|
||||
case BINDER_TYPE_WEAK_BINDER:
|
||||
case BINDER_TYPE_HANDLE:
|
||||
case BINDER_TYPE_WEAK_HANDLE:
|
||||
return sizeof(struct flat_binder_object);
|
||||
case BINDER_TYPE_FD:
|
||||
return sizeof(struct binder_fd_object);
|
||||
case BINDER_TYPE_FDA:
|
||||
return sizeof(struct binder_fd_array_object);
|
||||
case BINDER_TYPE_PTR:
|
||||
return sizeof(struct binder_buffer_object);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns size of the object's extra data */
|
||||
static
|
||||
gsize
|
||||
GBINDER_IO_FN(object_data_size)(
|
||||
const void* obj)
|
||||
{
|
||||
const struct binder_buffer_object* buf = obj;
|
||||
if (obj) {
|
||||
const struct binder_object_header* hdr = obj;
|
||||
|
||||
if (buf && buf->hdr.type == BINDER_TYPE_PTR) {
|
||||
return buf->length;
|
||||
} else {
|
||||
return 0;
|
||||
switch (hdr->type) {
|
||||
case BINDER_TYPE_PTR:
|
||||
return ((struct binder_buffer_object*)obj)->length;
|
||||
case BINDER_TYPE_FDA:
|
||||
return ((struct binder_fd_array_object*)obj)->num_fds * 4;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Writes pointer to the buffer */
|
||||
@@ -118,7 +148,20 @@ GBINDER_IO_FN(encode_pointer)(
|
||||
return sizeof(*dest);
|
||||
}
|
||||
|
||||
/* Encodes flat_buffer_object */
|
||||
/* Writes cookie to the buffer */
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_cookie)(
|
||||
void* out,
|
||||
guint64 cookie)
|
||||
{
|
||||
binder_uintptr_t* dest = out;
|
||||
|
||||
*dest = (uintptr_t)cookie;
|
||||
return sizeof(*dest);
|
||||
}
|
||||
|
||||
/* Encodes flat_binder_object */
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_local_object)(
|
||||
@@ -128,9 +171,13 @@ GBINDER_IO_FN(encode_local_object)(
|
||||
struct flat_binder_object* dest = out;
|
||||
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
if (obj) {
|
||||
dest->hdr.type = BINDER_TYPE_BINDER;
|
||||
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||
dest->binder = (uintptr_t)obj;
|
||||
} else {
|
||||
dest->hdr.type = BINDER_TYPE_WEAK_BINDER;
|
||||
}
|
||||
return sizeof(*dest);
|
||||
}
|
||||
|
||||
@@ -153,6 +200,21 @@ GBINDER_IO_FN(encode_remote_object)(
|
||||
return sizeof(*dest);
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_fd_object)(
|
||||
void* out,
|
||||
int fd)
|
||||
{
|
||||
struct binder_fd_object* dest = out;
|
||||
|
||||
memset(dest, 0, sizeof(*dest));
|
||||
dest->hdr.type = BINDER_TYPE_FD;
|
||||
dest->pad_flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||
dest->fd = fd;
|
||||
return sizeof(*dest);
|
||||
}
|
||||
|
||||
/* Encodes binder_buffer_object */
|
||||
static
|
||||
guint
|
||||
@@ -178,7 +240,7 @@ GBINDER_IO_FN(encode_buffer_object)(
|
||||
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_death_notification)(
|
||||
GBINDER_IO_FN(encode_handle_cookie)(
|
||||
void* out,
|
||||
GBinderRemoteObject* obj)
|
||||
{
|
||||
@@ -190,7 +252,21 @@ GBINDER_IO_FN(encode_death_notification)(
|
||||
return sizeof(*dest);
|
||||
}
|
||||
|
||||
/* Encodes BC_TRANSACTION data */
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_ptr_cookie)(
|
||||
void* out,
|
||||
GBinderLocalObject* obj)
|
||||
{
|
||||
struct binder_ptr_cookie* dest = out;
|
||||
|
||||
/* We never send these cookies and don't expect them back */
|
||||
dest->ptr = (uintptr_t)obj;
|
||||
dest->cookie = 0;
|
||||
return sizeof(dest);
|
||||
}
|
||||
|
||||
/* Fills binder_transaction_data for BC_TRANSACTION/REPLY */
|
||||
static
|
||||
void
|
||||
GBINDER_IO_FN(fill_transaction_data)(
|
||||
@@ -198,7 +274,7 @@ GBINDER_IO_FN(fill_transaction_data)(
|
||||
guint32 handle,
|
||||
guint32 code,
|
||||
const GByteArray* payload,
|
||||
guint flags,
|
||||
guint tx_flags,
|
||||
GUtilIntArray* offsets,
|
||||
void** offsets_buf)
|
||||
{
|
||||
@@ -207,9 +283,7 @@ GBINDER_IO_FN(fill_transaction_data)(
|
||||
tr->code = code;
|
||||
tr->data_size = payload->len;
|
||||
tr->data.ptr.buffer = (uintptr_t)payload->data;
|
||||
if (flags & GBINDER_TX_FLAG_ONEWAY) {
|
||||
tr->flags |= TF_ONE_WAY;
|
||||
}
|
||||
tr->flags = tx_flags;
|
||||
if (offsets && offsets->count) {
|
||||
guint i;
|
||||
binder_size_t* tx_offsets = g_new(binder_size_t, offsets->count);
|
||||
@@ -225,6 +299,7 @@ GBINDER_IO_FN(fill_transaction_data)(
|
||||
}
|
||||
}
|
||||
|
||||
/* Encodes BC_TRANSACTION data */
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_transaction)(
|
||||
@@ -238,7 +313,8 @@ GBINDER_IO_FN(encode_transaction)(
|
||||
{
|
||||
struct binder_transaction_data* tr = out;
|
||||
|
||||
GBINDER_IO_FN(fill_transaction_data)(tr, handle, code, payload, flags,
|
||||
GBINDER_IO_FN(fill_transaction_data)(tr, handle, code, payload,
|
||||
(flags & GBINDER_TX_FLAG_ONEWAY) ? TF_ONE_WAY : TF_ACCEPT_FDS,
|
||||
offsets, offsets_buf);
|
||||
return sizeof(*tr);
|
||||
}
|
||||
@@ -259,13 +335,53 @@ GBINDER_IO_FN(encode_transaction_sg)(
|
||||
struct binder_transaction_data_sg* sg = out;
|
||||
|
||||
GBINDER_IO_FN(fill_transaction_data)(&sg->transaction_data, handle, code,
|
||||
payload, flags, offsets, offsets_buf);
|
||||
payload, (flags & GBINDER_TX_FLAG_ONEWAY) ? TF_ONE_WAY : TF_ACCEPT_FDS,
|
||||
offsets, offsets_buf);
|
||||
/* The driver seems to require buffers to be 8-byte aligned */
|
||||
sg->buffers_size = G_ALIGN8(buffers_size);
|
||||
return sizeof(*sg);
|
||||
}
|
||||
|
||||
/* Encode BC_REPLY */
|
||||
/* Encodes BC_REPLY data */
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_reply)(
|
||||
void* out,
|
||||
guint32 handle,
|
||||
guint32 code,
|
||||
const GByteArray* payload,
|
||||
GUtilIntArray* offsets,
|
||||
void** offsets_buf)
|
||||
{
|
||||
struct binder_transaction_data* tr = out;
|
||||
|
||||
GBINDER_IO_FN(fill_transaction_data)(tr, handle, code, payload, 0,
|
||||
offsets, offsets_buf);
|
||||
return sizeof(*tr);
|
||||
}
|
||||
|
||||
/* Encodes BC_REPLY_SG data */
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_reply_sg)(
|
||||
void* out,
|
||||
guint32 handle,
|
||||
guint32 code,
|
||||
const GByteArray* payload,
|
||||
GUtilIntArray* offsets,
|
||||
void** offsets_buf,
|
||||
gsize buffers_size)
|
||||
{
|
||||
struct binder_transaction_data_sg* sg = out;
|
||||
|
||||
GBINDER_IO_FN(fill_transaction_data)(&sg->transaction_data, handle, code,
|
||||
payload, 0, offsets, offsets_buf);
|
||||
/* The driver seems to require buffers to be 8-byte aligned */
|
||||
sg->buffers_size = G_ALIGN8(buffers_size);
|
||||
return sizeof(*sg);
|
||||
}
|
||||
|
||||
/* Encode BC_REPLY with just status */
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(encode_status_reply)(
|
||||
@@ -353,7 +469,7 @@ GBINDER_IO_FN(decode_cookie)(
|
||||
/* Decode struct binder_ptr_cookie */
|
||||
static
|
||||
void*
|
||||
GBINDER_IO_FN(decode_binder_ptr_cookie)(
|
||||
GBINDER_IO_FN(decode_ptr_cookie)(
|
||||
const void* data)
|
||||
{
|
||||
const struct binder_ptr_cookie* ptr = data;
|
||||
@@ -363,6 +479,24 @@ GBINDER_IO_FN(decode_binder_ptr_cookie)(
|
||||
return (void*)(uintptr_t)ptr->ptr;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(decode_binder_handle)(
|
||||
const void* data,
|
||||
guint32* handle)
|
||||
{
|
||||
const struct flat_binder_object* obj = data;
|
||||
|
||||
/* Caller guarantees that data points to an object */
|
||||
if (obj->hdr.type == BINDER_TYPE_HANDLE) {
|
||||
if (handle) {
|
||||
*handle = obj->handle;
|
||||
}
|
||||
return sizeof(*obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(decode_binder_object)(
|
||||
@@ -377,9 +511,19 @@ GBINDER_IO_FN(decode_binder_object)(
|
||||
switch (obj->hdr.type) {
|
||||
case BINDER_TYPE_HANDLE:
|
||||
if (out) {
|
||||
*out = gbinder_object_registry_get_remote(reg, obj->handle);
|
||||
*out = gbinder_object_registry_get_remote(reg, obj->handle,
|
||||
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE);
|
||||
}
|
||||
return sizeof(*obj);
|
||||
case BINDER_TYPE_BINDER:
|
||||
if (!obj->binder) {
|
||||
/* That's a NULL reference */
|
||||
if (out) {
|
||||
*out = NULL;
|
||||
}
|
||||
return sizeof(*obj);
|
||||
}
|
||||
/* fallthrough */
|
||||
default:
|
||||
GERR("Unsupported binder object type 0x%08x", obj->hdr.type);
|
||||
break;
|
||||
@@ -394,7 +538,7 @@ guint
|
||||
GBINDER_IO_FN(decode_buffer_object)(
|
||||
GBinderBuffer* buf,
|
||||
gsize offset,
|
||||
GBinderBuffer** out)
|
||||
GBinderIoBufferObject* out)
|
||||
{
|
||||
const void* data = (guint8*)buf->data + offset;
|
||||
const gsize size = (offset < buf->size) ? (buf->size - offset) : 0;
|
||||
@@ -402,12 +546,36 @@ GBINDER_IO_FN(decode_buffer_object)(
|
||||
|
||||
if (size >= sizeof(*flat) && flat->hdr.type == BINDER_TYPE_PTR) {
|
||||
if (out) {
|
||||
*out = gbinder_buffer_new_with_parent(buf,
|
||||
(void*)(uintptr_t)flat->buffer, flat->length);
|
||||
out->data = (void*)(uintptr_t)flat->buffer;
|
||||
out->size = (gsize)flat->length;
|
||||
out->parent_offset = (gsize)flat->parent_offset;
|
||||
out->has_parent = (flat->flags & BINDER_BUFFER_FLAG_HAS_PARENT) ?
|
||||
TRUE : FALSE;
|
||||
}
|
||||
return sizeof(*flat);
|
||||
}
|
||||
if (out) *out = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
GBINDER_IO_FN(decode_fd_object)(
|
||||
const void* data,
|
||||
gsize size,
|
||||
int* fd)
|
||||
{
|
||||
const struct flat_binder_object* obj = data;
|
||||
|
||||
if (size >= sizeof(*obj)) {
|
||||
switch (obj->hdr.type) {
|
||||
case BINDER_TYPE_FD:
|
||||
if (fd) *fd = obj->handle;
|
||||
return sizeof(*obj);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fd) *fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -460,24 +628,32 @@ const GBinderIo GBINDER_IO_PREFIX = {
|
||||
.failed_reply = BR_FAILED_REPLY
|
||||
},
|
||||
|
||||
.object_size = GBINDER_IO_FN(object_size),
|
||||
.object_data_size = GBINDER_IO_FN(object_data_size),
|
||||
|
||||
/* Encoders */
|
||||
.encode_pointer = GBINDER_IO_FN(encode_pointer),
|
||||
.encode_cookie = GBINDER_IO_FN(encode_cookie),
|
||||
.encode_local_object = GBINDER_IO_FN(encode_local_object),
|
||||
.encode_remote_object = GBINDER_IO_FN(encode_remote_object),
|
||||
.encode_fd_object = GBINDER_IO_FN(encode_fd_object),
|
||||
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
|
||||
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
|
||||
.encode_handle_cookie = GBINDER_IO_FN(encode_handle_cookie),
|
||||
.encode_ptr_cookie = GBINDER_IO_FN(encode_ptr_cookie),
|
||||
.encode_transaction = GBINDER_IO_FN(encode_transaction),
|
||||
.encode_transaction_sg = GBINDER_IO_FN(encode_transaction_sg),
|
||||
.encode_reply = GBINDER_IO_FN(encode_reply),
|
||||
.encode_reply_sg = GBINDER_IO_FN(encode_reply_sg),
|
||||
.encode_status_reply = GBINDER_IO_FN(encode_status_reply),
|
||||
|
||||
/* Decoders */
|
||||
.decode_transaction_data = GBINDER_IO_FN(decode_transaction_data),
|
||||
.decode_cookie = GBINDER_IO_FN(decode_cookie),
|
||||
.decode_binder_ptr_cookie = GBINDER_IO_FN(decode_binder_ptr_cookie),
|
||||
.decode_ptr_cookie = GBINDER_IO_FN(decode_ptr_cookie),
|
||||
.decode_binder_handle = GBINDER_IO_FN(decode_binder_handle),
|
||||
.decode_binder_object = GBINDER_IO_FN(decode_binder_object),
|
||||
.decode_buffer_object = GBINDER_IO_FN(decode_buffer_object),
|
||||
.decode_fd_object = GBINDER_IO_FN(decode_fd_object),
|
||||
|
||||
/* ioctl wrappers */
|
||||
.write_read = GBINDER_IO_FN(write_read)
|
||||
@@ -490,7 +666,7 @@ G_STATIC_ASSERT(sizeof(struct flat_binder_object) <=
|
||||
G_STATIC_ASSERT(sizeof(struct binder_buffer_object) <=
|
||||
GBINDER_MAX_BUFFER_OBJECT_SIZE);
|
||||
G_STATIC_ASSERT(sizeof(struct binder_handle_cookie) <=
|
||||
GBINDER_MAX_DEATH_NOTIFICATION_SIZE);
|
||||
GBINDER_MAX_HANDLE_COOKIE_SIZE);
|
||||
G_STATIC_ASSERT(sizeof(struct binder_transaction_data) <=
|
||||
GBINDER_MAX_BC_TRANSACTION_SIZE);
|
||||
G_STATIC_ASSERT(sizeof(struct binder_transaction_data_sg) <=
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -43,6 +43,13 @@ typedef struct gbinder_io_buf {
|
||||
gsize consumed;
|
||||
} GBinderIoBuf;
|
||||
|
||||
typedef struct gbinder_io_buffer_object {
|
||||
void* data;
|
||||
gsize size;
|
||||
gsize parent_offset;
|
||||
gboolean has_parent;
|
||||
} GBinderIoBufferObject;
|
||||
|
||||
typedef struct gbinder_io_tx_data {
|
||||
int status;
|
||||
guint32 code;
|
||||
@@ -118,7 +125,8 @@ struct gbinder_io {
|
||||
guint failed_reply;
|
||||
} br;
|
||||
|
||||
/* Size of the object's extra data */
|
||||
/* Size of the object and its extra data */
|
||||
gsize (*object_size)(const void* obj);
|
||||
gsize (*object_data_size)(const void* obj);
|
||||
|
||||
/* Writes pointer to the buffer. The destination buffer must have
|
||||
@@ -127,53 +135,71 @@ struct gbinder_io {
|
||||
#define GBINDER_MAX_POINTER_SIZE (8)
|
||||
guint (*encode_pointer)(void* out, const void* pointer);
|
||||
|
||||
/* Writes cookie to the buffer. The destination buffer must have
|
||||
* at least GBINDER_IO_MAX_COOKIE_SIZE bytes available. The
|
||||
* actual size is returned. */
|
||||
#define GBINDER_MAX_COOKIE_SIZE GBINDER_MAX_POINTER_SIZE
|
||||
guint (*encode_cookie)(void* out, guint64 cookie);
|
||||
|
||||
/* Encode flat_buffer_object */
|
||||
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
|
||||
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
|
||||
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
|
||||
guint (*encode_fd_object)(void* out, int fd);
|
||||
|
||||
/* Encode binder_buffer_object */
|
||||
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
|
||||
guint (*encode_buffer_object)(void* out, const void* data, gsize size,
|
||||
const GBinderParent* parent);
|
||||
|
||||
/* Encode death notification */
|
||||
#define GBINDER_MAX_DEATH_NOTIFICATION_SIZE (12)
|
||||
guint (*encode_death_notification)(void* out, GBinderRemoteObject* obj);
|
||||
/* Encode binder_handle_cookie */
|
||||
#define GBINDER_MAX_HANDLE_COOKIE_SIZE (12)
|
||||
guint (*encode_handle_cookie)(void* out, GBinderRemoteObject* obj);
|
||||
|
||||
/* Encode BC_TRANSACTION/REPLY data */
|
||||
/* Encode binder_ptr_cookie */
|
||||
#define GBINDER_MAX_PTR_COOKIE_SIZE (16)
|
||||
guint (*encode_ptr_cookie)(void* out, GBinderLocalObject* obj);
|
||||
|
||||
/* Encode BC_TRANSACTION/BC_TRANSACTION_SG data */
|
||||
#define GBINDER_MAX_BC_TRANSACTION_SIZE (64)
|
||||
guint (*encode_transaction)(void* out, guint32 handle, guint32 code,
|
||||
const GByteArray* data, guint flags /* See below */,
|
||||
GUtilIntArray* offsets, void** offsets_buf);
|
||||
|
||||
/* Encode BC_TRANSACTION_SG/REPLY_SG data */
|
||||
#define GBINDER_MAX_BC_TRANSACTION_SG_SIZE (72)
|
||||
guint (*encode_transaction_sg)(void* out, guint32 handle, guint32 code,
|
||||
const GByteArray* data, guint flags /* GBINDER_TX_FLAG_xxx */,
|
||||
GUtilIntArray* offsets, void** offsets_buf,
|
||||
gsize buffers_size);
|
||||
|
||||
/* Encode BC_REPLY/REPLY_SG data */
|
||||
#define GBINDER_MAX_BC_REPLY_SIZE GBINDER_MAX_BC_TRANSACTION_SIZE
|
||||
guint (*encode_reply)(void* out, guint32 handle, guint32 code,
|
||||
const GByteArray* data, GUtilIntArray* offsets, void** offsets_buf);
|
||||
#define GBINDER_MAX_BC_REPLY_SG_SIZE GBINDER_MAX_BC_TRANSACTION_SG_SIZE
|
||||
guint (*encode_reply_sg)(void* out, guint32 handle, guint32 code,
|
||||
const GByteArray* data, GUtilIntArray* offsets, void** offsets_buf,
|
||||
gsize buffers_size);
|
||||
|
||||
/* Encode BC_REPLY */
|
||||
guint (*encode_status_reply)(void* out, gint32* status);
|
||||
|
||||
/* Decoders */
|
||||
void (*decode_transaction_data)(const void* data, GBinderIoTxData* tx);
|
||||
|
||||
#define GBINDER_MAX_PTR_COOKIE_SIZE (16)
|
||||
void* (*decode_binder_ptr_cookie)(const void* data);
|
||||
void* (*decode_ptr_cookie)(const void* data);
|
||||
guint (*decode_cookie)(const void* data, guint64* cookie);
|
||||
guint (*decode_binder_handle)(const void* obj, guint32* handle);
|
||||
guint (*decode_binder_object)(const void* data, gsize size,
|
||||
GBinderObjectRegistry* reg, GBinderRemoteObject** obj);
|
||||
guint (*decode_buffer_object)(GBinderBuffer* buf, gsize offset,
|
||||
GBinderBuffer** out);
|
||||
GBinderIoBufferObject* out);
|
||||
guint (*decode_fd_object)(const void* data, gsize size, int* fd);
|
||||
|
||||
/* ioctl wrappers */
|
||||
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 */
|
||||
|
||||
|
||||
1447
src/gbinder_ipc.c
1447
src/gbinder_ipc.c
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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;
|
||||
};
|
||||
|
||||
@@ -60,6 +59,12 @@ struct gbinder_ipc_tx {
|
||||
void* user_data;
|
||||
};
|
||||
|
||||
typedef
|
||||
gboolean
|
||||
(*GBinderIpcLocalObjectCheckFunc)(
|
||||
GBinderLocalObject* obj,
|
||||
void* user_data);
|
||||
|
||||
typedef
|
||||
void
|
||||
(*GBinderIpcReplyFunc)(
|
||||
@@ -68,54 +73,99 @@ void
|
||||
int status,
|
||||
void* user_data);
|
||||
|
||||
GBinderIpc*
|
||||
gbinder_ipc_new(
|
||||
const char* dev,
|
||||
const GBinderRpcProtocol* protocol);
|
||||
|
||||
GBinderIpc*
|
||||
gbinder_ipc_ref(
|
||||
GBinderIpc* ipc);
|
||||
|
||||
void
|
||||
gbinder_ipc_unref(
|
||||
GBinderIpc* ipc);
|
||||
|
||||
void
|
||||
gbinder_ipc_looper_check(
|
||||
GBinderIpc* ipc);
|
||||
|
||||
GBinderObjectRegistry*
|
||||
gbinder_ipc_object_registry(
|
||||
GBinderIpc* ipc);
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_ipc_new_local_object(
|
||||
GBinderIpc* ipc,
|
||||
const char* iface,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* data);
|
||||
|
||||
GBinderRemoteObject*
|
||||
gbinder_ipc_get_remote_object(
|
||||
GBinderIpc* ipc,
|
||||
guint32 handle);
|
||||
|
||||
typedef
|
||||
GBinderRemoteReply*
|
||||
gbinder_ipc_transact_sync_reply(
|
||||
(*GBinderIpcSyncReplyFunc)(
|
||||
GBinderIpc* ipc,
|
||||
guint32 handle,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req,
|
||||
int* status);
|
||||
|
||||
typedef
|
||||
int
|
||||
gbinder_ipc_transact_sync_oneway(
|
||||
(*GBinderIpcSyncOnewayFunc)(
|
||||
GBinderIpc* ipc,
|
||||
guint32 handle,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req);
|
||||
|
||||
struct gbinder_ipc_sync_api {
|
||||
GBinderIpcSyncReplyFunc sync_reply;
|
||||
GBinderIpcSyncOnewayFunc sync_oneway;
|
||||
};
|
||||
|
||||
extern const GBinderIpcSyncApi gbinder_ipc_sync_main GBINDER_INTERNAL;
|
||||
extern const GBinderIpcSyncApi gbinder_ipc_sync_worker GBINDER_INTERNAL;
|
||||
|
||||
GBinderIpc*
|
||||
gbinder_ipc_new(
|
||||
const char* dev)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderIpc*
|
||||
gbinder_ipc_ref(
|
||||
GBinderIpc* ipc)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_ipc_unref(
|
||||
GBinderIpc* ipc)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_ipc_looper_check(
|
||||
GBinderIpc* ipc)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderObjectRegistry*
|
||||
gbinder_ipc_object_registry(
|
||||
GBinderIpc* ipc)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
const GBinderIo*
|
||||
gbinder_ipc_io(
|
||||
GBinderIpc* ipc)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
const GBinderRpcProtocol*
|
||||
gbinder_ipc_protocol(
|
||||
GBinderIpc* ipc)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_ipc_find_local_object(
|
||||
GBinderIpc* ipc,
|
||||
GBinderIpcLocalObjectCheckFunc func,
|
||||
void* user_data)
|
||||
GBINDER_INTERNAL
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
void
|
||||
gbinder_ipc_register_local_object(
|
||||
GBinderIpc* ipc,
|
||||
GBinderLocalObject* obj)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderRemoteObject*
|
||||
gbinder_ipc_get_service_manager(
|
||||
GBinderIpc* self)
|
||||
GBINDER_INTERNAL
|
||||
G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
void
|
||||
gbinder_ipc_invalidate_remote_handle(
|
||||
GBinderIpc* ipc,
|
||||
guint32 handle)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
int
|
||||
gbinder_ipc_ping_sync(
|
||||
GBinderIpc* ipc,
|
||||
guint32 handle,
|
||||
const GBinderIpcSyncApi* api)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
gulong
|
||||
gbinder_ipc_transact(
|
||||
GBinderIpc* ipc,
|
||||
@@ -125,7 +175,8 @@ gbinder_ipc_transact(
|
||||
GBinderLocalRequest* req,
|
||||
GBinderIpcReplyFunc func,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data);
|
||||
void* user_data)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
gulong
|
||||
gbinder_ipc_transact_custom(
|
||||
@@ -133,24 +184,42 @@ gbinder_ipc_transact_custom(
|
||||
GBinderIpcTxFunc exec,
|
||||
GBinderIpcTxFunc done,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data);
|
||||
void* user_data)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_ipc_cancel(
|
||||
GBinderIpc* ipc,
|
||||
gulong id);
|
||||
gulong id)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
/* Internal for GBinderLocalObject */
|
||||
void
|
||||
gbinder_ipc_local_object_disposed(
|
||||
GBinderIpc* self,
|
||||
GBinderLocalObject* obj);
|
||||
GBinderLocalObject* obj)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
/* Internal for GBinderRemoteObject */
|
||||
void
|
||||
gbinder_ipc_remote_object_disposed(
|
||||
GBinderIpc* self,
|
||||
GBinderRemoteObject* obj);
|
||||
GBinderRemoteObject* obj)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
/* Needed by unit tests */
|
||||
gboolean
|
||||
gbinder_ipc_set_max_threads(
|
||||
GBinderIpc* self,
|
||||
gint max_threads)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
/* Declared for unit tests */
|
||||
void
|
||||
gbinder_ipc_exit(
|
||||
void)
|
||||
GBINDER_INTERNAL
|
||||
GBINDER_DESTRUCTOR;
|
||||
|
||||
#endif /* GBINDER_IPC_H */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -30,29 +30,48 @@
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "gbinder_driver.h"
|
||||
#include "gbinder_ipc.h"
|
||||
#include "gbinder_buffer_p.h"
|
||||
#include "gbinder_local_object_p.h"
|
||||
#include "gbinder_local_reply_p.h"
|
||||
#include "gbinder_remote_request.h"
|
||||
#include "gbinder_eventloop_p.h"
|
||||
#include "gbinder_writer.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
struct gbinder_local_object_priv {
|
||||
GMainContext* context;
|
||||
char* iface;
|
||||
char** ifaces;
|
||||
GBinderLocalTransactFunc txproc;
|
||||
void* user_data;
|
||||
};
|
||||
|
||||
typedef struct gbinder_local_object_acquire_data {
|
||||
GBinderLocalObject* object;
|
||||
GBinderBufferContentsList* bufs;
|
||||
} GBinderLocalObjectAcquireData;
|
||||
|
||||
G_DEFINE_TYPE(GBinderLocalObject, gbinder_local_object, G_TYPE_OBJECT)
|
||||
|
||||
#define PARENT_CLASS gbinder_local_object_parent_class
|
||||
#define GBINDER_LOCAL_OBJECT_GET_CLASS(obj) \
|
||||
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_LOCAL_OBJECT, \
|
||||
GBinderLocalObjectClass)
|
||||
|
||||
typedef
|
||||
GBinderLocalReply*
|
||||
(*GBinderLocalObjectTxHandler)(
|
||||
GBinderLocalObject* self,
|
||||
GBinderRemoteRequest* req,
|
||||
int* status);
|
||||
|
||||
enum gbinder_local_object_signal {
|
||||
SIGNAL_WEAK_REFS_CHANGED,
|
||||
SIGNAL_STRONG_REFS_CHANGED,
|
||||
@@ -78,6 +97,9 @@ gbinder_local_object_default_can_handle_transaction(
|
||||
guint code)
|
||||
{
|
||||
switch (code) {
|
||||
case GBINDER_PING_TRANSACTION:
|
||||
case GBINDER_INTERFACE_TRANSACTION:
|
||||
return GBINDER_LOCAL_TRANSACTION_LOOPER;
|
||||
case HIDL_PING_TRANSACTION:
|
||||
case HIDL_GET_DESCRIPTOR_TRANSACTION:
|
||||
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
|
||||
@@ -110,6 +132,39 @@ gbinder_local_object_default_handle_transaction(
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
gbinder_local_object_ping_transaction(
|
||||
GBinderLocalObject* self,
|
||||
GBinderRemoteRequest* req,
|
||||
int* status)
|
||||
{
|
||||
const GBinderIo* io = gbinder_local_object_io(self);
|
||||
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
||||
|
||||
GVERBOSE(" PING_TRANSACTION");
|
||||
gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK);
|
||||
*status = GBINDER_STATUS_OK;
|
||||
return reply;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
gbinder_local_object_interface_transaction(
|
||||
GBinderLocalObject* self,
|
||||
GBinderRemoteRequest* req,
|
||||
int* status)
|
||||
{
|
||||
const GBinderIo* io = gbinder_local_object_io(self);
|
||||
GBinderLocalObjectPriv* priv = self->priv;
|
||||
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
||||
|
||||
GVERBOSE(" INTERFACE_TRANSACTION");
|
||||
gbinder_local_reply_append_string16(reply, priv->ifaces[0]);
|
||||
*status = GBINDER_STATUS_OK;
|
||||
return reply;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
gbinder_local_object_hidl_ping_transaction(
|
||||
@@ -120,12 +175,10 @@ gbinder_local_object_hidl_ping_transaction(
|
||||
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
|
||||
const GBinderIo* io = gbinder_local_object_io(self);
|
||||
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
||||
GBinderWriter writer;
|
||||
|
||||
GVERBOSE(" HIDL_PING_TRANSACTION \"%s\"",
|
||||
gbinder_remote_request_interface(req));
|
||||
gbinder_local_reply_init_writer(reply, &writer);
|
||||
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
|
||||
gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK);
|
||||
*status = GBINDER_STATUS_OK;
|
||||
return reply;
|
||||
}
|
||||
@@ -139,6 +192,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
|
||||
{
|
||||
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
|
||||
const GBinderIo* io = gbinder_local_object_io(self);
|
||||
GBinderLocalObjectPriv* priv = self->priv;
|
||||
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
||||
GBinderWriter writer;
|
||||
|
||||
@@ -146,8 +200,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
|
||||
gbinder_remote_request_interface(req));
|
||||
gbinder_local_reply_init_writer(reply, &writer);
|
||||
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
|
||||
gbinder_writer_append_hidl_string(&writer, self->iface ? self->iface :
|
||||
hidl_base_interface);
|
||||
gbinder_writer_append_hidl_string(&writer, priv->ifaces[0]);
|
||||
*status = GBINDER_STATUS_OK;
|
||||
return reply;
|
||||
}
|
||||
@@ -163,17 +216,14 @@ gbinder_local_object_hidl_descriptor_chain_transaction(
|
||||
const GBinderIo* io = gbinder_local_object_io(self);
|
||||
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
||||
GBinderWriter writer;
|
||||
const char* chain[2];
|
||||
int n = 0;
|
||||
|
||||
GVERBOSE(" HIDL_DESCRIPTOR_CHAIN_TRANSACTION \"%s\"",
|
||||
gbinder_remote_request_interface(req));
|
||||
if (self->iface) chain[n++] = self->iface;
|
||||
chain[n++] = hidl_base_interface;
|
||||
|
||||
gbinder_local_reply_init_writer(reply, &writer);
|
||||
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
|
||||
gbinder_writer_append_hidl_string_vec(&writer, chain, n);
|
||||
gbinder_writer_append_hidl_string_vec(&writer, (const char**)
|
||||
self->ifaces, -1);
|
||||
*status = GBINDER_STATUS_OK;
|
||||
return reply;
|
||||
}
|
||||
@@ -187,91 +237,142 @@ gbinder_local_object_default_handle_looper_transaction(
|
||||
guint flags,
|
||||
int* status)
|
||||
{
|
||||
GBinderLocalObjectTxHandler handler = NULL;
|
||||
|
||||
switch (code) {
|
||||
case GBINDER_PING_TRANSACTION:
|
||||
handler = gbinder_local_object_ping_transaction;
|
||||
break;
|
||||
case GBINDER_INTERFACE_TRANSACTION:
|
||||
handler = gbinder_local_object_interface_transaction;
|
||||
break;
|
||||
case HIDL_PING_TRANSACTION:
|
||||
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
|
||||
return gbinder_local_object_hidl_ping_transaction
|
||||
(self, req, status);
|
||||
handler = gbinder_local_object_hidl_ping_transaction;
|
||||
break;
|
||||
case HIDL_GET_DESCRIPTOR_TRANSACTION:
|
||||
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
|
||||
return gbinder_local_object_hidl_get_descriptor_transaction
|
||||
(self, req, status);
|
||||
handler = gbinder_local_object_hidl_get_descriptor_transaction;
|
||||
break;
|
||||
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
|
||||
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
|
||||
return gbinder_local_object_hidl_descriptor_chain_transaction
|
||||
(self, req, status);
|
||||
handler = gbinder_local_object_hidl_descriptor_chain_transaction;
|
||||
break;
|
||||
default:
|
||||
if (status) *status = (-EBADMSG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
|
||||
return handler(self, req, status);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_local_object_default_drop(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
GBinderLocalObjectPriv* priv = self->priv;
|
||||
|
||||
/* Clear the transaction callback */
|
||||
priv->txproc = NULL;
|
||||
priv->user_data = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_local_object_handle_later(
|
||||
GBinderLocalObject* self,
|
||||
GSourceFunc function)
|
||||
GBinderEventLoopCallbackFunc function)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderLocalObjectPriv* priv = self->priv;
|
||||
|
||||
g_main_context_invoke_full(priv->context, G_PRIORITY_DEFAULT, function,
|
||||
gbinder_idle_callback_invoke_later(function,
|
||||
gbinder_local_object_ref(self), g_object_unref);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_local_object_handle_increfs_proc(
|
||||
gpointer local)
|
||||
void
|
||||
gbinder_local_object_increfs_proc(
|
||||
gpointer user_data)
|
||||
{
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(user_data);
|
||||
|
||||
self->weak_refs++;
|
||||
g_signal_emit(self, gbinder_local_object_signals
|
||||
[SIGNAL_WEAK_REFS_CHANGED], 0);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_local_object_handle_decrefs_proc(
|
||||
gpointer local)
|
||||
void
|
||||
gbinder_local_object_decrefs_proc(
|
||||
gpointer user_data)
|
||||
{
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(user_data);
|
||||
|
||||
GASSERT(self->weak_refs > 0);
|
||||
self->weak_refs--;
|
||||
g_signal_emit(self, gbinder_local_object_signals
|
||||
[SIGNAL_WEAK_REFS_CHANGED], 0);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_local_object_handle_acquire_proc(
|
||||
gpointer local)
|
||||
void
|
||||
gbinder_local_object_default_acquire(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
|
||||
|
||||
self->strong_refs++;
|
||||
gbinder_local_object_ref(self);
|
||||
GVERBOSE_("%p => %d", self, self->strong_refs);
|
||||
g_signal_emit(self, gbinder_local_object_signals
|
||||
[SIGNAL_STRONG_REFS_CHANGED], 0);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_local_object_handle_release_proc(
|
||||
gpointer local)
|
||||
void
|
||||
gbinder_local_object_acquire_proc(
|
||||
gpointer user_data)
|
||||
{
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
|
||||
GBinderLocalObjectAcquireData* data = user_data;
|
||||
GBinderLocalObject* self = data->object;
|
||||
|
||||
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->acquire(self);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_local_object_acquire_done(
|
||||
gpointer user_data)
|
||||
{
|
||||
GBinderLocalObjectAcquireData* data = user_data;
|
||||
GBinderLocalObject* self = data->object;
|
||||
|
||||
gbinder_driver_acquire_done(self->ipc->driver, self);
|
||||
gbinder_local_object_unref(self);
|
||||
gbinder_buffer_contents_list_free(data->bufs);
|
||||
return gutil_slice_free(data);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_local_object_default_release(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
GASSERT(self->strong_refs > 0);
|
||||
if (self->strong_refs > 0) {
|
||||
self->strong_refs--;
|
||||
GVERBOSE_("%p => %d", self, self->strong_refs);
|
||||
g_signal_emit(self, gbinder_local_object_signals
|
||||
[SIGNAL_STRONG_REFS_CHANGED], 0);
|
||||
return G_SOURCE_REMOVE;
|
||||
gbinder_local_object_unref(self);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_local_object_release_proc(
|
||||
gpointer obj)
|
||||
{
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(obj);
|
||||
|
||||
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->release(self);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
@@ -281,23 +382,66 @@ gbinder_local_object_handle_release_proc(
|
||||
GBinderLocalObject*
|
||||
gbinder_local_object_new(
|
||||
GBinderIpc* ipc,
|
||||
const char* iface,
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data) /* Since 1.0.30 */
|
||||
{
|
||||
return gbinder_local_object_new_with_type(GBINDER_TYPE_LOCAL_OBJECT,
|
||||
ipc, ifaces, txproc, user_data);
|
||||
}
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_local_object_new_with_type(
|
||||
GType type,
|
||||
GBinderIpc* ipc,
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* arg)
|
||||
{
|
||||
if (G_LIKELY(ipc)) {
|
||||
GBinderLocalObject* obj = g_object_new(type, NULL);
|
||||
|
||||
gbinder_local_object_init_base(obj, ipc, ifaces, txproc, arg);
|
||||
gbinder_ipc_register_local_object(ipc, obj);
|
||||
return obj;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_object_init_base(
|
||||
GBinderLocalObject* self,
|
||||
GBinderIpc* ipc,
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data)
|
||||
{
|
||||
/* Should only be called from gbinder_ipc_new_local_local_object() */
|
||||
if (G_LIKELY(ipc)) {
|
||||
GBinderLocalObject* self = g_object_new
|
||||
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
|
||||
GBinderLocalObjectPriv* priv = self->priv;
|
||||
guint i = 0, n = gutil_strv_length((char**)ifaces);
|
||||
gboolean append_base_interface;
|
||||
|
||||
if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
|
||||
append_base_interface = TRUE;
|
||||
n++;
|
||||
} else {
|
||||
append_base_interface = FALSE;
|
||||
}
|
||||
|
||||
priv->ifaces = g_new(char*, n + 1);
|
||||
if (ifaces) {
|
||||
while (*ifaces) {
|
||||
priv->ifaces[i++] = g_strdup(*ifaces++);
|
||||
}
|
||||
}
|
||||
if (append_base_interface) {
|
||||
priv->ifaces[i++] = g_strdup(hidl_base_interface);
|
||||
}
|
||||
priv->ifaces[i] = NULL;
|
||||
|
||||
self->ipc = gbinder_ipc_ref(ipc);
|
||||
self->iface = priv->iface = g_strdup(iface);
|
||||
self->ifaces = (const char**)priv->ifaces;
|
||||
priv->txproc = txproc;
|
||||
priv->user_data = user_data;
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderLocalObject*
|
||||
@@ -326,11 +470,7 @@ gbinder_local_object_drop(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderLocalObjectPriv* priv = self->priv;
|
||||
|
||||
/* Clear the transaction callback */
|
||||
priv->txproc = NULL;
|
||||
priv->user_data = NULL;
|
||||
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->drop(self);
|
||||
g_object_unref(GBINDER_LOCAL_OBJECT(self));
|
||||
}
|
||||
}
|
||||
@@ -424,32 +564,49 @@ void
|
||||
gbinder_local_object_handle_increfs(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
gbinder_local_object_handle_later(self,
|
||||
gbinder_local_object_handle_increfs_proc);
|
||||
gbinder_local_object_handle_later(self, gbinder_local_object_increfs_proc);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_object_handle_decrefs(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
gbinder_local_object_handle_later(self,
|
||||
gbinder_local_object_handle_decrefs_proc);
|
||||
gbinder_local_object_handle_later(self, gbinder_local_object_decrefs_proc);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_object_handle_acquire(
|
||||
GBinderLocalObject* self)
|
||||
GBinderLocalObject* self,
|
||||
GBinderBufferContentsList* bufs)
|
||||
{
|
||||
gbinder_local_object_handle_later(self,
|
||||
gbinder_local_object_handle_acquire_proc);
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderLocalObjectAcquireData* data =
|
||||
g_slice_new(GBinderLocalObjectAcquireData);
|
||||
|
||||
/*
|
||||
* This is a bit complicated :)
|
||||
* GBinderProxyObject derived from GBinderLocalObject acquires a
|
||||
* reference to the remote object in addition to performing the
|
||||
* default GBinderLocalObject action later on the main thread.
|
||||
* We must ensure that remote object doesn't go away before we
|
||||
* acquire our reference to it. One of the references to that
|
||||
* remote object (possibly the last one) may be associated with
|
||||
* the transaction buffer contained in GBinderBufferContentsList.
|
||||
* We don't know exactly which one we need, so we keep all those
|
||||
* buffers alive until we are done with BR_ACQUIRE.
|
||||
*/
|
||||
data->object = gbinder_local_object_ref(self);
|
||||
data->bufs = gbinder_buffer_contents_list_dup(bufs);
|
||||
gbinder_idle_callback_invoke_later(gbinder_local_object_acquire_proc,
|
||||
data, gbinder_local_object_acquire_done);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_object_handle_release(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
gbinder_local_object_handle_later(self,
|
||||
gbinder_local_object_handle_release_proc);
|
||||
gbinder_local_object_handle_later(self, gbinder_local_object_release_proc);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
@@ -464,32 +621,32 @@ gbinder_local_object_init(
|
||||
GBinderLocalObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObjectPriv);
|
||||
|
||||
priv->context = g_main_context_default();
|
||||
self->priv = priv;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_local_object_dispose(
|
||||
GObject* local)
|
||||
GObject* object)
|
||||
{
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(object);
|
||||
|
||||
gbinder_ipc_local_object_disposed(self->ipc, self);
|
||||
G_OBJECT_CLASS(gbinder_local_object_parent_class)->dispose(local);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_local_object_finalize(
|
||||
GObject* local)
|
||||
GObject* object)
|
||||
{
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
|
||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(object);
|
||||
GBinderLocalObjectPriv* priv = self->priv;
|
||||
|
||||
GASSERT(!self->strong_refs);
|
||||
gbinder_ipc_unref(self->ipc);
|
||||
g_free(priv->iface);
|
||||
G_OBJECT_CLASS(gbinder_local_object_parent_class)->finalize(local);
|
||||
g_strfreev(priv->ifaces);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -509,6 +666,9 @@ gbinder_local_object_class_init(
|
||||
gbinder_local_object_default_handle_looper_transaction;
|
||||
klass->can_handle_transaction =
|
||||
gbinder_local_object_default_can_handle_transaction;
|
||||
klass->acquire = gbinder_local_object_default_acquire;
|
||||
klass->release = gbinder_local_object_default_release;
|
||||
klass->drop = gbinder_local_object_default_drop;
|
||||
|
||||
gbinder_local_object_signals[SIGNAL_WEAK_REFS_CHANGED] =
|
||||
g_signal_new(SIGNAL_WEAK_REFS_CHANGED_NAME,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -40,8 +40,9 @@
|
||||
#include <glib-object.h>
|
||||
|
||||
/*
|
||||
* Some if this stuff may become public if we decide to allow the clients
|
||||
* to derive their classes from GBinderLocalObject
|
||||
* Some of this stuff may become public if we decide to allow the clients
|
||||
* to derive their own classes from GBinderLocalObject. For now it's all
|
||||
* private.
|
||||
*/
|
||||
|
||||
typedef
|
||||
@@ -55,7 +56,7 @@ struct gbinder_local_object {
|
||||
GObject object;
|
||||
GBinderLocalObjectPriv* priv;
|
||||
GBinderIpc* ipc;
|
||||
const char* iface;
|
||||
const char* const* ifaces;
|
||||
gint weak_refs;
|
||||
gint strong_refs;
|
||||
};
|
||||
@@ -76,47 +77,66 @@ typedef struct gbinder_local_object_class {
|
||||
GBinderLocalReply* (*handle_looper_transaction)
|
||||
(GBinderLocalObject* self, GBinderRemoteRequest* req, guint code,
|
||||
guint flags, int* status);
|
||||
void (*acquire)(GBinderLocalObject* self);
|
||||
void (*release)(GBinderLocalObject* self);
|
||||
void (*drop)(GBinderLocalObject* self);
|
||||
/* 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))
|
||||
#define GBINDER_LOCAL_OBJECT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
|
||||
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObjectClass)
|
||||
|
||||
#define gbinder_local_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
|
||||
#define gbinder_local_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
|
||||
|
||||
/* Should only be called from gbinder_ipc_new_local_object() */
|
||||
GBinderLocalObject*
|
||||
gbinder_local_object_new(
|
||||
gbinder_local_object_new_with_type(
|
||||
GType type,
|
||||
GBinderIpc* ipc,
|
||||
const char* iface,
|
||||
GBinderLocalTransactFunc handler,
|
||||
void* user_data);
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_local_object_init_base(
|
||||
GBinderLocalObject* self,
|
||||
GBinderIpc* ipc,
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
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(
|
||||
@@ -124,7 +144,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(
|
||||
@@ -132,23 +153,29 @@ 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,
|
||||
GBinderBufferContentsList* bufs)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_local_object_handle_release(
|
||||
GBinderLocalObject* obj);
|
||||
GBinderLocalObject* obj)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_LOCAL_OBJECT_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -43,6 +43,7 @@ struct gbinder_local_reply {
|
||||
gint refcount;
|
||||
GBinderWriterData data;
|
||||
GBinderOutputData out;
|
||||
GBinderBufferContents* contents;
|
||||
};
|
||||
|
||||
GBINDER_INLINE_FUNC
|
||||
@@ -94,15 +95,16 @@ gbinder_local_reply_new(
|
||||
}
|
||||
|
||||
GBinderLocalReply*
|
||||
gbinder_local_reply_new_from_data(
|
||||
gbinder_local_reply_set_contents(
|
||||
GBinderLocalReply* self,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderObjectConverter* convert)
|
||||
{
|
||||
const GBinderIo* io = gbinder_buffer_io(buffer);
|
||||
GBinderLocalReply* self = gbinder_local_reply_new(io);
|
||||
|
||||
if (self) {
|
||||
gbinder_writer_data_set_contents(&self->data, buffer, objects);
|
||||
gbinder_writer_data_set_contents(&self->data, buffer, convert);
|
||||
gbinder_buffer_contents_unref(self->contents);
|
||||
self->contents = gbinder_buffer_contents_ref
|
||||
(gbinder_buffer_contents(buffer));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -117,7 +119,8 @@ gbinder_local_reply_free(
|
||||
gutil_int_array_free(data->offsets, TRUE);
|
||||
g_byte_array_free(data->bytes, TRUE);
|
||||
gbinder_cleanup_free(data->cleanup);
|
||||
g_slice_free(GBinderLocalReply, self);
|
||||
gbinder_buffer_contents_unref(self->contents);
|
||||
gutil_slice_free(self);
|
||||
}
|
||||
|
||||
GBinderLocalReply*
|
||||
@@ -150,6 +153,13 @@ gbinder_local_reply_data(
|
||||
return G_LIKELY(self) ? &self->out : NULL;
|
||||
}
|
||||
|
||||
GBinderBufferContents*
|
||||
gbinder_local_reply_contents(
|
||||
GBinderLocalReply* self)
|
||||
{
|
||||
return G_LIKELY(self) ? self->contents : NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_reply_cleanup(
|
||||
GBinderLocalReply* self,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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,16 +39,25 @@
|
||||
|
||||
GBinderLocalReply*
|
||||
gbinder_local_reply_new(
|
||||
const GBinderIo* io);
|
||||
const GBinderIo* io)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderOutputData*
|
||||
gbinder_local_reply_data(
|
||||
GBinderLocalReply* reply);
|
||||
GBinderLocalReply* reply)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderBufferContents*
|
||||
gbinder_local_reply_contents(
|
||||
GBinderLocalReply* reply)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderLocalReply*
|
||||
gbinder_local_reply_new_from_data(
|
||||
gbinder_local_reply_set_contents(
|
||||
GBinderLocalReply* reply,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
GBinderObjectConverter* convert)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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,6 +31,7 @@
|
||||
*/
|
||||
|
||||
#include "gbinder_local_request_p.h"
|
||||
#include "gbinder_rpc_protocol.h"
|
||||
#include "gbinder_output_data.h"
|
||||
#include "gbinder_writer_p.h"
|
||||
#include "gbinder_buffer_p.h"
|
||||
@@ -44,7 +45,6 @@ struct gbinder_local_request {
|
||||
gint refcount;
|
||||
GBinderWriterData data;
|
||||
GBinderOutputData out;
|
||||
GBinderBufferMemory* memory;
|
||||
};
|
||||
|
||||
GBINDER_INLINE_FUNC
|
||||
@@ -92,6 +92,7 @@ gbinder_local_request_new(
|
||||
if (init) {
|
||||
gsize size;
|
||||
gconstpointer data = g_bytes_get_data(init, &size);
|
||||
|
||||
writer->bytes = g_byte_array_sized_new(size);
|
||||
g_byte_array_append(writer->bytes, data, size);
|
||||
} else {
|
||||
@@ -104,20 +105,49 @@ gbinder_local_request_new(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_new_iface(
|
||||
const GBinderIo* io,
|
||||
const GBinderRpcProtocol* protocol,
|
||||
const char* iface)
|
||||
{
|
||||
GBinderLocalRequest* self = gbinder_local_request_new(io, NULL);
|
||||
|
||||
if (self && G_LIKELY(protocol) && G_LIKELY(iface)) {
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_local_request_init_writer(self, &writer);
|
||||
protocol->write_rpc_header(&writer, iface);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_new_from_data(
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderObjectConverter* convert)
|
||||
{
|
||||
GBinderLocalRequest* self = gbinder_local_request_new
|
||||
(gbinder_buffer_io(buffer), NULL);
|
||||
|
||||
if (self) {
|
||||
gbinder_writer_data_set_contents(&self->data, buffer, objects);
|
||||
gbinder_writer_data_append_contents(&self->data, buffer, 0, convert);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_request_append_contents(
|
||||
GBinderLocalRequest* self,
|
||||
GBinderBuffer* buffer,
|
||||
gsize off,
|
||||
GBinderObjectConverter* convert)
|
||||
{
|
||||
if (self) {
|
||||
gbinder_writer_data_append_contents(&self->data, buffer, off, convert);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_local_request_free(
|
||||
@@ -128,7 +158,6 @@ gbinder_local_request_free(
|
||||
g_byte_array_free(data->bytes, TRUE);
|
||||
gutil_int_array_free(data->offsets, TRUE);
|
||||
gbinder_cleanup_free(data->cleanup);
|
||||
gbinder_buffer_memory_unref(self->memory);
|
||||
g_slice_free(GBinderLocalRequest, self);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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,16 +40,34 @@
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_new(
|
||||
const GBinderIo* io,
|
||||
GBytes* init);
|
||||
GBytes* init)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderOutputData*
|
||||
gbinder_local_request_data(
|
||||
GBinderLocalRequest* req);
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_new_iface(
|
||||
const GBinderIo* io,
|
||||
const GBinderRpcProtocol* protocol,
|
||||
const char* iface)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_new_from_data(
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
GBinderObjectConverter* convert)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderOutputData*
|
||||
gbinder_local_request_data(
|
||||
GBinderLocalRequest* req)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_local_request_append_contents(
|
||||
GBinderLocalRequest* req,
|
||||
GBinderBuffer* buffer,
|
||||
gsize offset,
|
||||
GBinderObjectConverter* convert)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */
|
||||
|
||||
|
||||
62
src/gbinder_log.c
Normal file
62
src/gbinder_log.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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_log.h"
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Log module */
|
||||
GLOG_MODULE_DEFINE("gbinder");
|
||||
|
||||
/* Initializes the default log level at startup */
|
||||
void
|
||||
gbinder_log_init(
|
||||
void)
|
||||
{
|
||||
int level = GLOG_MODULE_NAME.level;
|
||||
|
||||
if (gutil_parse_int(getenv("GBINDER_DEFAULT_LOG_LEVEL"), 0, &level) &&
|
||||
level >= GLOG_LEVEL_INHERIT && level <= GLOG_LEVEL_VERBOSE) {
|
||||
GINFO("Log level %d", level);
|
||||
GLOG_MODULE_NAME.level = level;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -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,11 +33,18 @@
|
||||
#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 */
|
||||
__attribute__((constructor))
|
||||
void
|
||||
gbinder_log_init(
|
||||
void)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_LOG_H */
|
||||
|
||||
/*
|
||||
|
||||
67
src/gbinder_object_converter.h
Normal file
67
src/gbinder_object_converter.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 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_OBJECT_CONVERTER_H
|
||||
#define GBINDER_OBJECT_CONVERTER_H
|
||||
|
||||
#include "gbinder_types_p.h"
|
||||
|
||||
typedef struct gbinder_object_converter_functions {
|
||||
GBinderLocalObject* (*handle_to_local)(GBinderObjectConverter*, guint32);
|
||||
} GBinderObjectConverterFunctions;
|
||||
|
||||
struct gbinder_object_converter {
|
||||
const GBinderObjectConverterFunctions* f;
|
||||
const GBinderIo* io;
|
||||
const GBinderRpcProtocol* protocol;
|
||||
};
|
||||
|
||||
/* Inline wrappers */
|
||||
|
||||
GBINDER_INLINE_FUNC
|
||||
GBinderLocalObject*
|
||||
gbinder_object_converter_handle_to_local(
|
||||
GBinderObjectConverter* convert,
|
||||
guint32 handle)
|
||||
{
|
||||
return convert ? convert->f->handle_to_local(convert, handle) : NULL;
|
||||
}
|
||||
|
||||
#endif /* GBINDER_OBJECT_CONVERTER_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -35,13 +35,19 @@
|
||||
|
||||
#include "gbinder_types_p.h"
|
||||
|
||||
typedef enum gbinder_remote_registry_create {
|
||||
REMOTE_REGISTRY_DONT_CREATE,
|
||||
REMOTE_REGISTRY_CAN_CREATE,
|
||||
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE
|
||||
} REMOTE_REGISTRY_CREATE;
|
||||
|
||||
typedef struct gbinder_object_registry_functions {
|
||||
void (*ref)(GBinderObjectRegistry* reg);
|
||||
void (*unref)(GBinderObjectRegistry* reg);
|
||||
GBinderLocalObject* (*get_local)(GBinderObjectRegistry* reg,
|
||||
void* pointer);
|
||||
GBinderRemoteObject* (*get_remote)(GBinderObjectRegistry* reg,
|
||||
guint32 handle);
|
||||
guint32 handle, REMOTE_REGISTRY_CREATE create);
|
||||
} GBinderObjectRegistryFunctions;
|
||||
|
||||
struct gbinder_object_registry {
|
||||
@@ -81,9 +87,10 @@ GBINDER_INLINE_FUNC
|
||||
GBinderRemoteObject*
|
||||
gbinder_object_registry_get_remote(
|
||||
GBinderObjectRegistry* reg,
|
||||
guint32 handle)
|
||||
guint32 handle,
|
||||
REMOTE_REGISTRY_CREATE create)
|
||||
{
|
||||
return reg ? reg->f->get_remote(reg, handle) : NULL;
|
||||
return reg ? reg->f->get_remote(reg, handle, create) : NULL;
|
||||
}
|
||||
|
||||
#endif /* GBINDER_OBJECT_REGISTRY_H */
|
||||
|
||||
@@ -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
|
||||
|
||||
522
src/gbinder_proxy_object.c
Normal file
522
src/gbinder_proxy_object.c
Normal file
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 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_proxy_object.h"
|
||||
#include "gbinder_local_object_p.h"
|
||||
#include "gbinder_local_request.h"
|
||||
#include "gbinder_local_reply.h"
|
||||
#include "gbinder_remote_object_p.h"
|
||||
#include "gbinder_remote_request_p.h"
|
||||
#include "gbinder_remote_reply_p.h"
|
||||
#include "gbinder_object_converter.h"
|
||||
#include "gbinder_object_registry.h"
|
||||
#include "gbinder_driver.h"
|
||||
#include "gbinder_ipc.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
typedef GBinderLocalObjectClass GBinderProxyObjectClass;
|
||||
typedef struct gbinder_proxy_tx GBinderProxyTx;
|
||||
|
||||
struct gbinder_proxy_tx {
|
||||
GBinderProxyTx* next;
|
||||
GBinderRemoteRequest* req;
|
||||
GBinderProxyObject* proxy;
|
||||
gulong id;
|
||||
};
|
||||
|
||||
struct gbinder_proxy_object_priv {
|
||||
gulong remote_death_id;
|
||||
gboolean dropped;
|
||||
GBinderProxyTx* tx;
|
||||
GMutex mutex; /* Protects the hashtable below */
|
||||
GHashTable* subproxies;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(GBinderProxyObject, gbinder_proxy_object, \
|
||||
GBINDER_TYPE_LOCAL_OBJECT)
|
||||
#define GBINDER_IS_PROXY_OBJECT(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \
|
||||
GBINDER_TYPE_PROXY_OBJECT)
|
||||
|
||||
#define THIS(obj) GBINDER_PROXY_OBJECT(obj)
|
||||
#define THIS_TYPE GBINDER_TYPE_PROXY_OBJECT
|
||||
#define PARENT_CLASS gbinder_proxy_object_parent_class
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_subproxy_gone(
|
||||
gpointer proxy,
|
||||
GObject* subproxy)
|
||||
{
|
||||
GBinderProxyObject* self = THIS(proxy);
|
||||
GBinderProxyObjectPriv* priv = self->priv;
|
||||
|
||||
/* Lock */
|
||||
g_mutex_lock(&priv->mutex);
|
||||
g_hash_table_remove(priv->subproxies, subproxy);
|
||||
if (g_hash_table_size(priv->subproxies) == 0) {
|
||||
g_hash_table_unref(priv->subproxies);
|
||||
priv->subproxies = NULL;
|
||||
}
|
||||
g_mutex_unlock(&priv->mutex);
|
||||
/* Unlock */
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_drop_subproxies(
|
||||
GBinderProxyObject* self)
|
||||
{
|
||||
GBinderProxyObjectPriv* priv = self->priv;
|
||||
GSList* list = NULL;
|
||||
|
||||
/* Lock */
|
||||
g_mutex_lock(&priv->mutex);
|
||||
if (priv->subproxies) {
|
||||
GHashTableIter it;
|
||||
gpointer value;
|
||||
|
||||
g_hash_table_iter_init(&it, priv->subproxies);
|
||||
while (g_hash_table_iter_next(&it, NULL, &value)) {
|
||||
list = g_slist_append(list, gbinder_local_object_ref(value));
|
||||
g_object_weak_unref(G_OBJECT(value),
|
||||
gbinder_proxy_object_subproxy_gone, self);
|
||||
}
|
||||
g_hash_table_destroy(priv->subproxies);
|
||||
priv->subproxies = NULL;
|
||||
}
|
||||
g_mutex_unlock(&priv->mutex);
|
||||
/* Unlock */
|
||||
|
||||
/* Drop (and possibly destroy) the objects outside of the lock */
|
||||
g_slist_free_full(list, (GDestroyNotify) gbinder_local_object_drop);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_remote_death_proc(
|
||||
GBinderRemoteObject* obj,
|
||||
void* proxy)
|
||||
{
|
||||
GBinderProxyObject* self = THIS(proxy);
|
||||
GBinderProxyObjectPriv* priv = self->priv;
|
||||
|
||||
GDEBUG("Remote object %u died on %s", obj->handle, obj->ipc->dev);
|
||||
gbinder_remote_object_remove_handler(obj, priv->remote_death_id);
|
||||
priv->remote_death_id = 0;
|
||||
/* Drop the implicit reference */
|
||||
gbinder_local_object_unref(&self->parent);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Converter
|
||||
*==========================================================================*/
|
||||
|
||||
typedef struct gbinder_proxy_object_converter {
|
||||
GBinderObjectConverter pub;
|
||||
GBinderProxyObject* proxy;
|
||||
GBinderIpc* remote;
|
||||
GBinderIpc* local;
|
||||
} GBinderProxyObjectConverter;
|
||||
|
||||
GBINDER_INLINE_FUNC
|
||||
GBinderProxyObjectConverter*
|
||||
gbinder_proxy_object_converter_cast(
|
||||
GBinderObjectConverter* pub)
|
||||
{
|
||||
return G_CAST(pub, GBinderProxyObjectConverter, pub);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_proxy_object_converter_check(
|
||||
GBinderLocalObject* obj,
|
||||
void* remote)
|
||||
{
|
||||
if (GBINDER_IS_PROXY_OBJECT(obj) && THIS(obj)->remote == remote) {
|
||||
/* Found matching proxy object */
|
||||
return TRUE;
|
||||
}
|
||||
/* Keep looking */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalObject*
|
||||
gbinder_proxy_object_converter_handle_to_local(
|
||||
GBinderObjectConverter* pub,
|
||||
guint32 handle)
|
||||
{
|
||||
GBinderProxyObjectConverter* c = gbinder_proxy_object_converter_cast(pub);
|
||||
GBinderProxyObject* proxy = c->proxy;
|
||||
GBinderProxyObjectPriv* priv = proxy->priv;
|
||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(c->remote);
|
||||
GBinderRemoteObject* remote = gbinder_object_registry_get_remote(reg,
|
||||
handle, REMOTE_REGISTRY_CAN_CREATE /* but don't acquire */);
|
||||
GBinderLocalObject* local = gbinder_ipc_find_local_object(c->local,
|
||||
gbinder_proxy_object_converter_check, remote);
|
||||
|
||||
if (!local && !remote->dead) {
|
||||
/* GBinderProxyObject will reference GBinderRemoteObject */
|
||||
GBinderProxyObject* subp = gbinder_proxy_object_new(c->local, remote);
|
||||
|
||||
/*
|
||||
* Auto-created proxies may get spontaneously destroyed and
|
||||
* not necessarily on the UI thread.
|
||||
*/
|
||||
subp->priv->remote_death_id = gbinder_remote_object_add_death_handler
|
||||
(remote, gbinder_proxy_remote_death_proc, subp);
|
||||
|
||||
/*
|
||||
* Remote keeps an implicit reference to this auto-created
|
||||
* proxy. The reference gets released when the remote object
|
||||
* dies, i.e. by gbinder_proxy_remote_death_proc().
|
||||
*/
|
||||
gbinder_local_object_ref(local = GBINDER_LOCAL_OBJECT(subp));
|
||||
|
||||
/* Lock */
|
||||
g_mutex_lock(&priv->mutex);
|
||||
if (!priv->subproxies) {
|
||||
priv->subproxies = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
}
|
||||
g_hash_table_insert(priv->subproxies, subp, subp);
|
||||
g_object_weak_ref(G_OBJECT(subp),
|
||||
gbinder_proxy_object_subproxy_gone, proxy);
|
||||
g_mutex_unlock(&priv->mutex);
|
||||
/* Unlock */
|
||||
}
|
||||
|
||||
/* Release the reference returned by gbinder_object_registry_get_remote */
|
||||
gbinder_remote_object_unref(remote);
|
||||
return local;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_converter_init(
|
||||
GBinderProxyObjectConverter* convert,
|
||||
GBinderProxyObject* proxy,
|
||||
GBinderIpc* remote,
|
||||
GBinderIpc* local)
|
||||
{
|
||||
static const GBinderObjectConverterFunctions gbinder_converter_fn = {
|
||||
.handle_to_local = gbinder_proxy_object_converter_handle_to_local
|
||||
};
|
||||
|
||||
GBinderObjectConverter* pub = &convert->pub;
|
||||
GBinderIpc* dest = proxy->parent.ipc;
|
||||
|
||||
memset(convert, 0, sizeof(*convert));
|
||||
convert->proxy = proxy;
|
||||
convert->remote = remote;
|
||||
convert->local = local;
|
||||
pub->f = &gbinder_converter_fn;
|
||||
pub->io = gbinder_ipc_io(dest);
|
||||
pub->protocol = gbinder_ipc_protocol(dest);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Implementation
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_tx_dequeue(
|
||||
GBinderProxyTx* tx)
|
||||
{
|
||||
GBinderProxyObject* proxy = tx->proxy;
|
||||
|
||||
if (proxy) {
|
||||
GBinderProxyObjectPriv* priv = proxy->priv;
|
||||
|
||||
if (priv->tx) {
|
||||
if (priv->tx == tx) {
|
||||
priv->tx = tx->next;
|
||||
} else {
|
||||
GBinderProxyTx* prev = priv->tx;
|
||||
|
||||
while (prev->next) {
|
||||
if (prev->next == tx) {
|
||||
prev->next = tx->next;
|
||||
break;
|
||||
}
|
||||
prev = prev->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
tx->next = NULL;
|
||||
tx->proxy = NULL;
|
||||
g_object_unref(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_tx_reply(
|
||||
GBinderIpc* ipc,
|
||||
GBinderRemoteReply* reply,
|
||||
int status,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderProxyTx* tx = user_data;
|
||||
GBinderProxyObject* self = tx->proxy;
|
||||
GBinderProxyObjectConverter convert;
|
||||
GBinderLocalReply* fwd;
|
||||
|
||||
/*
|
||||
* For proxy objects auto-created by the reply, the remote side (the
|
||||
* one sent the reply) will be the remote GBinderIpc and this object's
|
||||
* GBinderIpc will be the local, i.e. those proxies will work in the
|
||||
* same direction as the top level object. The direction gets inverted
|
||||
* twice.
|
||||
*/
|
||||
gbinder_proxy_object_converter_init(&convert, self, ipc, self->parent.ipc);
|
||||
fwd = gbinder_remote_reply_convert_to_local(reply, &convert.pub);
|
||||
tx->id = 0;
|
||||
gbinder_proxy_tx_dequeue(tx);
|
||||
gbinder_remote_request_complete(tx->req, fwd,
|
||||
(status > 0) ? (-EFAULT) : status);
|
||||
if (status == GBINDER_STATUS_DEAD_OBJECT) {
|
||||
/*
|
||||
* Some kernels sometimes don't bother sending us death notifications.
|
||||
* Let's also interpret BR_DEAD_REPLY as an obituary to make sure that
|
||||
* we don't keep dead remote objects around.
|
||||
*/
|
||||
gbinder_remote_object_commit_suicide(self->remote);
|
||||
}
|
||||
gbinder_local_reply_unref(fwd);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_tx_destroy(
|
||||
gpointer user_data)
|
||||
{
|
||||
GBinderProxyTx* tx = user_data;
|
||||
|
||||
gbinder_proxy_tx_dequeue(tx);
|
||||
gbinder_remote_request_unref(tx->req);
|
||||
gutil_slice_free(tx);
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
gbinder_proxy_object_handle_transaction(
|
||||
GBinderLocalObject* object,
|
||||
GBinderRemoteRequest* req,
|
||||
guint code,
|
||||
guint flags,
|
||||
int* status)
|
||||
{
|
||||
GBinderProxyObject* self = THIS(object);
|
||||
GBinderProxyObjectPriv* priv = self->priv;
|
||||
GBinderRemoteObject* remote = self->remote;
|
||||
|
||||
if (!priv->dropped && !gbinder_remote_object_is_dead(remote)) {
|
||||
GBinderLocalRequest* fwd;
|
||||
GBinderProxyTx* tx = g_slice_new0(GBinderProxyTx);
|
||||
GBinderProxyObjectConverter convert;
|
||||
|
||||
g_object_ref(tx->proxy = self);
|
||||
tx->req = gbinder_remote_request_ref(req);
|
||||
tx->next = priv->tx;
|
||||
priv->tx = tx;
|
||||
|
||||
/* Mark the incoming request as pending */
|
||||
gbinder_remote_request_block(req);
|
||||
|
||||
/*
|
||||
* For auto-created proxy objects, this object's GBinderIpc will
|
||||
* become a remote, and the remote's GBinderIpc will become local
|
||||
* because they work in the opposite direction.
|
||||
*/
|
||||
gbinder_proxy_object_converter_init(&convert, self, object->ipc,
|
||||
remote->ipc);
|
||||
|
||||
/* Forward the transaction */
|
||||
fwd = gbinder_remote_request_convert_to_local(req, &convert.pub);
|
||||
tx->id = gbinder_ipc_transact(remote->ipc, remote->handle, code, flags,
|
||||
fwd, gbinder_proxy_tx_reply, gbinder_proxy_tx_destroy, tx);
|
||||
gbinder_local_request_unref(fwd);
|
||||
*status = GBINDER_STATUS_OK;
|
||||
} else {
|
||||
*status = (-EBADMSG);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
GBINDER_LOCAL_TRANSACTION_SUPPORT
|
||||
gbinder_proxy_object_can_handle_transaction(
|
||||
GBinderLocalObject* self,
|
||||
const char* iface,
|
||||
guint code)
|
||||
{
|
||||
/* Process all transactions on the main thread */
|
||||
return GBINDER_LOCAL_TRANSACTION_SUPPORTED;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_acquire(
|
||||
GBinderLocalObject* object)
|
||||
{
|
||||
GBinderProxyObject* self = THIS(object);
|
||||
GBinderProxyObjectPriv* priv = self->priv;
|
||||
|
||||
if (priv->remote_death_id && !object->strong_refs) {
|
||||
GBinderRemoteObject* remote = self->remote;
|
||||
|
||||
/* First strong ref, acquire the attached remote object */
|
||||
gbinder_driver_acquire(remote->ipc->driver, remote->handle);
|
||||
}
|
||||
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->acquire(object);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_release(
|
||||
GBinderLocalObject* object)
|
||||
{
|
||||
GBinderProxyObject* self = THIS(object);
|
||||
GBinderProxyObjectPriv* priv = self->priv;
|
||||
|
||||
if (priv->remote_death_id && object->strong_refs == 1) {
|
||||
GBinderRemoteObject* remote = self->remote;
|
||||
|
||||
/* Last strong ref, release the attached remote object */
|
||||
gbinder_driver_release(remote->ipc->driver, remote->handle);
|
||||
}
|
||||
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->release(object);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_drop(
|
||||
GBinderLocalObject* object)
|
||||
{
|
||||
GBinderProxyObject* self = THIS(object);
|
||||
GBinderProxyObjectPriv* priv = self->priv;
|
||||
|
||||
priv->dropped = TRUE;
|
||||
gbinder_proxy_object_drop_subproxies(self);
|
||||
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->drop(object);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Interface
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderProxyObject*
|
||||
gbinder_proxy_object_new(
|
||||
GBinderIpc* src,
|
||||
GBinderRemoteObject* remote)
|
||||
{
|
||||
if (G_LIKELY(remote)) {
|
||||
/*
|
||||
* We don't need to specify the interface list because all
|
||||
* transactions (including HIDL_GET_DESCRIPTOR_TRANSACTION
|
||||
* and HIDL_DESCRIPTOR_CHAIN_TRANSACTION) are getting forwared
|
||||
* to the remote object.
|
||||
*/
|
||||
GBinderLocalObject* object = gbinder_local_object_new_with_type
|
||||
(THIS_TYPE, src, NULL, NULL, NULL);
|
||||
|
||||
if (object) {
|
||||
GBinderProxyObject* self = THIS(object);
|
||||
|
||||
self->remote = gbinder_remote_object_ref(remote);
|
||||
return self;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internals
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_finalize(
|
||||
GObject* object)
|
||||
{
|
||||
GBinderProxyObject* self = THIS(object);
|
||||
GBinderProxyObjectPriv* priv = self->priv;
|
||||
|
||||
gbinder_proxy_object_drop_subproxies(self);
|
||||
gbinder_remote_object_remove_handler(self->remote, priv->remote_death_id);
|
||||
gbinder_remote_object_unref(self->remote);
|
||||
g_mutex_clear(&priv->mutex);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_init(
|
||||
GBinderProxyObject* self)
|
||||
{
|
||||
GBinderProxyObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
THIS_TYPE, GBinderProxyObjectPriv);
|
||||
|
||||
self->priv = priv;
|
||||
g_mutex_init(&priv->mutex);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_proxy_object_class_init(
|
||||
GBinderProxyObjectClass* klass)
|
||||
{
|
||||
GObjectClass* object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
g_type_class_add_private(klass, sizeof(GBinderProxyObjectPriv));
|
||||
object_class->finalize = gbinder_proxy_object_finalize;
|
||||
klass->can_handle_transaction = gbinder_proxy_object_can_handle_transaction;
|
||||
klass->handle_transaction = gbinder_proxy_object_handle_transaction;
|
||||
klass->acquire = gbinder_proxy_object_acquire;
|
||||
klass->release = gbinder_proxy_object_release;
|
||||
klass->drop = gbinder_proxy_object_drop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
66
src/gbinder_proxy_object.h
Normal file
66
src/gbinder_proxy_object.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 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_PROXY_OBJECT_H
|
||||
#define GBINDER_PROXY_OBJECT_H
|
||||
|
||||
#include "gbinder_local_object_p.h"
|
||||
|
||||
typedef struct gbinder_proxy_object_priv GBinderProxyObjectPriv;
|
||||
|
||||
struct gbinder_proxy_object {
|
||||
GBinderLocalObject parent;
|
||||
GBinderProxyObjectPriv* priv;
|
||||
GBinderRemoteObject* remote;
|
||||
};
|
||||
|
||||
GType gbinder_proxy_object_get_type(void) GBINDER_INTERNAL;
|
||||
#define GBINDER_TYPE_PROXY_OBJECT gbinder_proxy_object_get_type()
|
||||
#define GBINDER_PROXY_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GBINDER_TYPE_PROXY_OBJECT, GBinderProxyObject))
|
||||
|
||||
/* Registers with src and forwards all transactions to the remote */
|
||||
GBinderProxyObject*
|
||||
gbinder_proxy_object_new(
|
||||
GBinderIpc* src,
|
||||
GBinderRemoteObject* remote)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_PROXY_OBJECT_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* 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:
|
||||
*
|
||||
@@ -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,6 +38,9 @@
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
typedef struct gbinder_reader_priv {
|
||||
const guint8* start;
|
||||
const guint8* end;
|
||||
@@ -50,6 +53,8 @@ G_STATIC_ASSERT(sizeof(GBinderReader) >= sizeof(GBinderReaderPriv));
|
||||
|
||||
static inline GBinderReaderPriv* gbinder_reader_cast(GBinderReader* reader)
|
||||
{ return (GBinderReaderPriv*)reader; }
|
||||
static inline const GBinderReaderPriv* gbinder_reader_cast_c
|
||||
(const GBinderReader* reader) { return (GBinderReaderPriv*)reader; }
|
||||
|
||||
void
|
||||
gbinder_reader_init(
|
||||
@@ -81,9 +86,9 @@ gbinder_reader_init(
|
||||
|
||||
gboolean
|
||||
gbinder_reader_at_end(
|
||||
GBinderReader* reader)
|
||||
const GBinderReader* reader)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
|
||||
|
||||
return p->ptr >= p->end;
|
||||
}
|
||||
@@ -229,16 +234,67 @@ gbinder_reader_read_double(
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
gboolean
|
||||
gbinder_reader_can_read_object(
|
||||
GBinderReaderPriv* p)
|
||||
{
|
||||
const GBinderReaderData* data = p->data;
|
||||
|
||||
return data && data->reg &&
|
||||
p->objects && p->objects[0] &&
|
||||
p->ptr == p->objects[0];
|
||||
}
|
||||
|
||||
int
|
||||
gbinder_reader_read_fd(
|
||||
GBinderReader* reader) /* Since 1.0.18 */
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
|
||||
if (gbinder_reader_can_read_object(p)) {
|
||||
int fd;
|
||||
const guint eaten = p->data->reg->io->decode_fd_object(p->ptr,
|
||||
gbinder_reader_bytes_remaining(reader), &fd);
|
||||
|
||||
if (eaten) {
|
||||
GASSERT(fd >= 0);
|
||||
p->ptr += eaten;
|
||||
p->objects++;
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gbinder_reader_read_dup_fd(
|
||||
GBinderReader* reader) /* Since 1.0.18 */
|
||||
{
|
||||
const int fd = gbinder_reader_read_fd(reader);
|
||||
|
||||
if (fd >= 0) {
|
||||
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||
|
||||
if (dupfd >= 0) {
|
||||
return dupfd;
|
||||
} else {
|
||||
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_nullable_object(
|
||||
GBinderReader* reader,
|
||||
GBinderRemoteObject** out)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderData* data = p->data;
|
||||
|
||||
if (data && data->reg && p->objects && p->objects[0] &&
|
||||
p->ptr == p->objects[0]) {
|
||||
if (gbinder_reader_can_read_object(p)) {
|
||||
const GBinderReaderData* data = p->data;
|
||||
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
|
||||
gbinder_reader_bytes_remaining(reader), data->reg, out);
|
||||
|
||||
@@ -264,15 +320,14 @@ gbinder_reader_read_object(
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_reader_read_buffer_impl(
|
||||
gbinder_reader_read_buffer_object(
|
||||
GBinderReader* reader,
|
||||
GBinderBuffer** out)
|
||||
GBinderIoBufferObject* out)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderData* data = p->data;
|
||||
|
||||
if (data && data->reg && p->objects && p->objects[0] &&
|
||||
p->ptr == p->objects[0]) {
|
||||
if (gbinder_reader_can_read_object(p)) {
|
||||
const GBinderReaderData* data = p->data;
|
||||
GBinderBuffer* buf = data->buffer;
|
||||
const GBinderIo* io = data->reg->io;
|
||||
const gsize offset = p->ptr - (guint8*)buf->data;
|
||||
@@ -284,7 +339,6 @@ gbinder_reader_read_buffer_impl(
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if (out) *out = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -292,90 +346,169 @@ GBinderBuffer*
|
||||
gbinder_reader_read_buffer(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
GBinderBuffer* buf = NULL;
|
||||
GBinderIoBufferObject obj;
|
||||
|
||||
gbinder_reader_read_buffer_impl(reader, &buf);
|
||||
return buf;
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj)) {
|
||||
const GBinderReaderData* data = gbinder_reader_cast(reader)->data;
|
||||
GBinderBuffer* buf = data->buffer;
|
||||
|
||||
return gbinder_buffer_new_with_parent(buf, obj.data, obj.size);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_reader_skip_buffer(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
return gbinder_reader_read_buffer_impl(reader, NULL);
|
||||
return gbinder_reader_read_buffer_object(reader, NULL);
|
||||
}
|
||||
|
||||
/* Helper for gbinder_reader_read_hidl_struct() macro */
|
||||
const void*
|
||||
gbinder_reader_read_hidl_struct1(
|
||||
GBinderReader* reader,
|
||||
gsize size) /* Since 1.0.9 */
|
||||
{
|
||||
GBinderIoBufferObject obj;
|
||||
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) && obj.size == size) {
|
||||
return obj.data;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Doesn't copy the data */
|
||||
const void*
|
||||
gbinder_reader_read_hidl_vec(
|
||||
GBinderReader* reader,
|
||||
gsize* count,
|
||||
gsize* elemsize)
|
||||
{
|
||||
GBinderIoBufferObject obj;
|
||||
const void* out = NULL;
|
||||
gsize out_count = 0, out_elemsize = 0;
|
||||
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.data && obj.size == sizeof(GBinderHidlVec)) {
|
||||
const GBinderHidlVec* vec = obj.data;
|
||||
const void* next = vec->data.ptr;
|
||||
|
||||
if (next) {
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.data == next && ((!vec->count && !obj.size) ||
|
||||
(vec->count && obj.size && !(obj.size % vec->count)))) {
|
||||
out_elemsize = vec->count ? (obj.size / vec->count) : 0;
|
||||
out_count = vec->count;
|
||||
out = obj.data;
|
||||
}
|
||||
} else if (!vec->count) {
|
||||
/* Any non-NULL pointer just to indicate success? */
|
||||
out = vec;
|
||||
}
|
||||
}
|
||||
if (elemsize) {
|
||||
*elemsize = out_elemsize;
|
||||
}
|
||||
if (count) {
|
||||
*count = out_count;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Helper for gbinder_reader_read_hidl_struct_vec() macro */
|
||||
const void*
|
||||
gbinder_reader_read_hidl_vec1(
|
||||
GBinderReader* reader,
|
||||
gsize* count,
|
||||
guint expected_elem_size) /* Since 1.0.9 */
|
||||
{
|
||||
gsize actual;
|
||||
const void* data = gbinder_reader_read_hidl_vec(reader, count, &actual);
|
||||
|
||||
/* Actual size will be zero for an empty array */
|
||||
return (data && (actual == expected_elem_size || !actual)) ? data : NULL;
|
||||
}
|
||||
|
||||
const char*
|
||||
gbinder_reader_read_hidl_string_c(
|
||||
GBinderReader* reader) /* Since 1.0.23 */
|
||||
{
|
||||
GBinderIoBufferObject obj;
|
||||
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.data && obj.size == sizeof(GBinderHidlString)) {
|
||||
const GBinderHidlString* str = obj.data;
|
||||
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.has_parent &&
|
||||
obj.parent_offset == GBINDER_HIDL_STRING_BUFFER_OFFSET &&
|
||||
obj.data == str->data.str &&
|
||||
obj.size == str->len + 1 &&
|
||||
str->data.str[str->len] == 0) {
|
||||
return str->data.str;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char*
|
||||
gbinder_reader_read_hidl_string(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
|
||||
char* str = NULL;
|
||||
|
||||
if (buf && buf->size == sizeof(HidlString)) {
|
||||
const HidlString* s = buf->data;
|
||||
GBinderBuffer* sbuf = gbinder_reader_read_buffer(reader);
|
||||
|
||||
if (sbuf && sbuf->size == s->len + 1 &&
|
||||
sbuf->data == s->data.str &&
|
||||
s->data.str[s->len] == 0) {
|
||||
str = g_strdup(s->data.str);
|
||||
}
|
||||
gbinder_buffer_free(sbuf);
|
||||
}
|
||||
gbinder_buffer_free(buf);
|
||||
return str;
|
||||
/* This function should've been called gbinder_reader_dup_hidl_string */
|
||||
return g_strdup(gbinder_reader_read_hidl_string_c(reader));
|
||||
}
|
||||
|
||||
char**
|
||||
gbinder_reader_read_hidl_string_vec(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
|
||||
GBinderIoBufferObject obj;
|
||||
|
||||
/* First buffer contains hidl_vector */
|
||||
if (buf && buf->size == sizeof(HidlVec)) {
|
||||
HidlVec* vec = buf->data;
|
||||
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
obj.data && obj.size == sizeof(GBinderHidlVec)) {
|
||||
GBinderHidlVec* vec = obj.data;
|
||||
const guint n = vec->count;
|
||||
const void* next = vec->data.ptr;
|
||||
|
||||
gbinder_buffer_free(buf);
|
||||
if (!next && !n) {
|
||||
char** out = g_new(char*, 1);
|
||||
|
||||
out[0] = NULL;
|
||||
return out;
|
||||
} else {
|
||||
/* Should this be considered an error? */
|
||||
return g_new0(char*, 1);
|
||||
} else if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||
/* The second buffer (if any) contains n hidl_string's */
|
||||
buf = gbinder_reader_read_buffer(reader);
|
||||
if (buf && buf->data == next && buf->size == sizeof(HidlString)*n) {
|
||||
const HidlString* strings = buf->data;
|
||||
GBinderBuffer* sbuf;
|
||||
GPtrArray* list = g_ptr_array_new();
|
||||
obj.parent_offset == GBINDER_HIDL_VEC_BUFFER_OFFSET &&
|
||||
obj.has_parent &&
|
||||
obj.data == next &&
|
||||
obj.size == (sizeof(GBinderHidlString) * n)) {
|
||||
const GBinderHidlString* strings = obj.data;
|
||||
GPtrArray* list = g_ptr_array_sized_new(n + 1);
|
||||
guint i;
|
||||
|
||||
/* Now we expect n buffers containing the actual data */
|
||||
for (i=0; i<n &&
|
||||
(sbuf = gbinder_reader_read_buffer(reader)); i++) {
|
||||
const HidlString* s = strings + i;
|
||||
if (sbuf->size == s->len + 1 &&
|
||||
sbuf->data == s->data.str &&
|
||||
for (i = 0; i < n &&
|
||||
gbinder_reader_read_buffer_object(reader, &obj); i++) {
|
||||
const GBinderHidlString* s = strings + i;
|
||||
const gsize expected_offset = (i * sizeof(*s)) +
|
||||
GBINDER_HIDL_STRING_BUFFER_OFFSET;
|
||||
if (obj.has_parent &&
|
||||
obj.parent_offset == expected_offset &&
|
||||
obj.data == s->data.str &&
|
||||
obj.size == s->len + 1 &&
|
||||
s->data.str[s->len] == 0) {
|
||||
char* name = g_strdup(s->data.str);
|
||||
|
||||
g_ptr_array_add(list, name);
|
||||
GVERBOSE_("%u. %s", i + 1, name);
|
||||
gbinder_buffer_free(sbuf);
|
||||
} else {
|
||||
GWARN("Unexpected hidl_string buffer %p/%u vs %p/%u",
|
||||
sbuf->data, (guint)sbuf->size, s->data.str, s->len);
|
||||
gbinder_buffer_free(sbuf);
|
||||
obj.data, (guint)obj.size, s->data.str, s->len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == n) {
|
||||
gbinder_buffer_free(buf);
|
||||
g_ptr_array_add(list, NULL);
|
||||
return (char**)g_ptr_array_free(list, FALSE);
|
||||
}
|
||||
@@ -384,9 +517,7 @@ gbinder_reader_read_hidl_string_vec(
|
||||
g_ptr_array_free(list, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
GWARN("Invalid hidl_vec<string>");
|
||||
gbinder_buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -418,6 +549,24 @@ gboolean
|
||||
gbinder_reader_read_nullable_string16(
|
||||
GBinderReader* reader,
|
||||
char** out)
|
||||
{
|
||||
const gunichar2* str;
|
||||
gsize len;
|
||||
|
||||
if (gbinder_reader_read_nullable_string16_utf16(reader, &str, &len)) {
|
||||
if (out) {
|
||||
*out = str ? g_utf16_to_utf8(str, len, NULL, NULL, NULL) : NULL;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_nullable_string16_utf16(
|
||||
GBinderReader* reader,
|
||||
const gunichar2** out,
|
||||
gsize* out_len) /* Since 1.0.17 */
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
|
||||
@@ -431,15 +580,21 @@ gbinder_reader_read_nullable_string16(
|
||||
if (out) {
|
||||
*out = NULL;
|
||||
}
|
||||
if (out_len) {
|
||||
*out_len = 0;
|
||||
}
|
||||
return TRUE;
|
||||
} else if (len >= 0) {
|
||||
const guint32 padded_len = G_ALIGN4((len+1)*2);
|
||||
const gunichar2* utf16 = (const gunichar2*)(p->ptr + 4);
|
||||
const guint32 padded_len = G_ALIGN4((len + 1)*2);
|
||||
const gunichar2* utf16 = (gunichar2*)(p->ptr + 4);
|
||||
|
||||
if ((p->ptr + padded_len + 4) <= p->end) {
|
||||
p->ptr += padded_len + 4;
|
||||
if (out) {
|
||||
*out = g_utf16_to_utf8(utf16, len, NULL, NULL, NULL);
|
||||
*out = utf16;
|
||||
}
|
||||
if (out_len) {
|
||||
*out_len = len;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -448,6 +603,21 @@ gbinder_reader_read_nullable_string16(
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const gunichar2*
|
||||
gbinder_reader_read_string16_utf16(
|
||||
GBinderReader* reader,
|
||||
gsize* len) /* Since 1.0.26 */
|
||||
{
|
||||
const gunichar2* str;
|
||||
|
||||
/*
|
||||
* Use gbinder_reader_read_nullable_string16_utf16 to distinguish
|
||||
* NULL string from a parsing failure.
|
||||
*/
|
||||
return gbinder_reader_read_nullable_string16_utf16(reader, &str, len) ?
|
||||
str : NULL;
|
||||
}
|
||||
|
||||
char*
|
||||
gbinder_reader_read_string16(
|
||||
GBinderReader* reader)
|
||||
@@ -484,24 +654,59 @@ gbinder_reader_skip_string16(
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_read(
|
||||
GBinderReader* reader)
|
||||
const void*
|
||||
gbinder_reader_read_byte_array(
|
||||
GBinderReader* reader,
|
||||
gsize* len) /* Since 1.0.12 */
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const void* data = NULL;
|
||||
const gint32* ptr;
|
||||
*len = 0;
|
||||
|
||||
if (gbinder_reader_can_read(p, sizeof(*ptr))) {
|
||||
ptr = (void*)p->ptr;
|
||||
if (*ptr <= 0) {
|
||||
p->ptr += sizeof(*ptr);
|
||||
/* Any non-NULL pointer just to indicate success */
|
||||
data = p->start;
|
||||
} else if (gbinder_reader_can_read(p, sizeof(*ptr) + *ptr)) {
|
||||
*len = (gsize)*ptr;
|
||||
p->ptr += sizeof(*ptr);
|
||||
data = p->ptr;
|
||||
p->ptr += *len;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_read(
|
||||
const GBinderReader* reader)
|
||||
{
|
||||
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
|
||||
|
||||
return p->ptr - p->start;
|
||||
}
|
||||
|
||||
gsize
|
||||
gbinder_reader_bytes_remaining(
|
||||
GBinderReader* reader)
|
||||
const GBinderReader* reader)
|
||||
{
|
||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
|
||||
|
||||
return p->end - p->ptr;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_reader_copy(
|
||||
GBinderReader* dest,
|
||||
const GBinderReader* src)
|
||||
{
|
||||
/* It's actually quite simple :) */
|
||||
memcpy(dest, src, sizeof(*dest));
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -30,22 +30,26 @@
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "gbinder_driver.h"
|
||||
#include "gbinder_ipc.h"
|
||||
#include "gbinder_remote_object_p.h"
|
||||
#include "gbinder_servicemanager_p.h"
|
||||
#include "gbinder_eventloop_p.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
struct gbinder_remote_object_priv {
|
||||
GMainContext* context;
|
||||
gboolean acquired;
|
||||
};
|
||||
|
||||
typedef GObjectClass GBinderRemoteObjectClass;
|
||||
GType gbinder_remote_object_get_type(void) GBINDER_INTERNAL;
|
||||
G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT)
|
||||
|
||||
GType gbinder_remote_object_get_type(void);
|
||||
#define GBINDER_TYPE_REMOTE_OBJECT (gbinder_remote_object_get_type())
|
||||
#define GBINDER_REMOTE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObject))
|
||||
#define PARENT_CLASS gbinder_remote_object_parent_class
|
||||
#define THIS_TYPE (gbinder_remote_object_get_type())
|
||||
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,THIS_TYPE,GBinderRemoteObject)
|
||||
|
||||
enum gbinder_remote_object_signal {
|
||||
SIGNAL_DEATH,
|
||||
@@ -62,21 +66,99 @@ static guint gbinder_remote_object_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_remote_object_died_on_main_thread(
|
||||
GBinderRemoteObject* self)
|
||||
gbinder_remote_object_handle_death_on_main_thread(
|
||||
gpointer user_data)
|
||||
{
|
||||
GASSERT(!self->dead);
|
||||
GBinderRemoteObject* self = THIS(user_data);
|
||||
|
||||
if (!self->dead) {
|
||||
GBinderIpc* ipc = self->ipc;
|
||||
GBinderDriver* driver = ipc->driver;
|
||||
GBinderRemoteObjectPriv* priv = self->priv;
|
||||
|
||||
self->dead = TRUE;
|
||||
if (priv->acquired) {
|
||||
priv->acquired = FALSE;
|
||||
/* Release the dead node */
|
||||
gbinder_driver_release(driver, self->handle);
|
||||
}
|
||||
/* ServiceManager always has the same handle, and can be reanimated. */
|
||||
if (self->handle != GBINDER_SERVICEMANAGER_HANDLE) {
|
||||
gbinder_ipc_invalidate_remote_handle(ipc, self->handle);
|
||||
}
|
||||
gbinder_driver_dead_binder_done(driver, self);
|
||||
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
/*==========================================================================*
|
||||
* Internal interface
|
||||
*==========================================================================*/
|
||||
|
||||
gboolean
|
||||
gbinder_remote_object_died_handle(
|
||||
gpointer self)
|
||||
gbinder_remote_object_reanimate(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
gbinder_remote_object_died_on_main_thread(GBINDER_REMOTE_OBJECT(self));
|
||||
return G_SOURCE_REMOVE;
|
||||
/*
|
||||
* Don't try to reanimate those who hasn't died yet. Reanimation is
|
||||
* kind of a special case and should only be used for servicemanager
|
||||
* objects.
|
||||
*/
|
||||
if (self->dead) {
|
||||
GBinderIpc* ipc = self->ipc;
|
||||
guint32 handle = self->handle;
|
||||
|
||||
/* Kick the horse */
|
||||
GASSERT(self->handle == GBINDER_SERVICEMANAGER_HANDLE);
|
||||
if (gbinder_ipc_ping_sync(ipc, handle, &gbinder_ipc_sync_main) == 0) {
|
||||
GBinderRemoteObjectPriv* priv = self->priv;
|
||||
GBinderDriver* driver = ipc->driver;
|
||||
|
||||
/* Wow, it's alive! */
|
||||
self->dead = FALSE;
|
||||
priv->acquired = TRUE;
|
||||
gbinder_ipc_looper_check(ipc); /* For death notifications */
|
||||
gbinder_driver_acquire(driver, handle);
|
||||
gbinder_driver_request_death_notification(driver, self);
|
||||
}
|
||||
}
|
||||
return !self->dead;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_object_handle_death_notification(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
/* This function is invoked from the looper thread, the caller has
|
||||
* checked the object pointer */
|
||||
GVERBOSE_("%p %u", self, self->handle);
|
||||
gbinder_idle_callback_invoke_later
|
||||
(gbinder_remote_object_handle_death_on_main_thread,
|
||||
gbinder_remote_object_ref(self), g_object_unref);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_object_commit_suicide(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
/* This function is only invoked by GBinderProxyObject in context of
|
||||
* the main thread, the object pointer is checked by the caller */
|
||||
if (!self->dead) {
|
||||
GBinderIpc* ipc = self->ipc;
|
||||
GBinderDriver* driver = ipc->driver;
|
||||
GBinderRemoteObjectPriv* priv = self->priv;
|
||||
|
||||
self->dead = TRUE;
|
||||
if (priv->acquired) {
|
||||
priv->acquired = FALSE;
|
||||
/* Release the dead node */
|
||||
gbinder_driver_release(driver, self->handle);
|
||||
}
|
||||
GVERBOSE_("%p %u", self, self->handle);
|
||||
gbinder_ipc_invalidate_remote_handle(self->ipc, self->handle);
|
||||
/* Don't submit BC_DEAD_BINDER_DONE because this is a suicide */
|
||||
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
@@ -86,15 +168,32 @@ gbinder_remote_object_died_handle(
|
||||
GBinderRemoteObject*
|
||||
gbinder_remote_object_new(
|
||||
GBinderIpc* ipc,
|
||||
guint32 handle)
|
||||
guint32 handle,
|
||||
REMOTE_OBJECT_CREATE create)
|
||||
{
|
||||
if (G_LIKELY(ipc) && gbinder_driver_acquire(ipc->driver, handle)) {
|
||||
GBinderRemoteObject* self = g_object_new
|
||||
(GBINDER_TYPE_REMOTE_OBJECT, NULL);
|
||||
if (G_LIKELY(ipc)) {
|
||||
GBinderRemoteObject* self = g_object_new(THIS_TYPE, NULL);
|
||||
GBinderRemoteObjectPriv* priv = self->priv;
|
||||
|
||||
self->ipc = gbinder_ipc_ref(ipc);
|
||||
self->handle = handle;
|
||||
switch (create) {
|
||||
case REMOTE_OBJECT_CREATE_DEAD:
|
||||
self->dead = TRUE;
|
||||
break;
|
||||
case REMOTE_OBJECT_CREATE_ACQUIRED:
|
||||
priv->acquired = TRUE;
|
||||
/* fallthrough */
|
||||
case REMOTE_OBJECT_CREATE_ALIVE:
|
||||
break;
|
||||
}
|
||||
if (!self->dead) {
|
||||
gbinder_ipc_looper_check(self->ipc); /* For death notifications */
|
||||
if (priv->acquired) {
|
||||
gbinder_driver_acquire(ipc->driver, handle);
|
||||
}
|
||||
gbinder_driver_request_death_notification(ipc->driver, self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
@@ -105,7 +204,7 @@ gbinder_remote_object_ref(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(GBINDER_REMOTE_OBJECT(self));
|
||||
g_object_ref(THIS(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
@@ -117,10 +216,17 @@ gbinder_remote_object_unref(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(GBINDER_REMOTE_OBJECT(self));
|
||||
g_object_unref(THIS(self));
|
||||
}
|
||||
}
|
||||
|
||||
GBinderIpc*
|
||||
gbinder_remote_object_ipc(
|
||||
GBinderRemoteObject* self) /* Since 1.0.30 */
|
||||
{
|
||||
return G_LIKELY(self) ? self->ipc : NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_remote_object_is_dead(
|
||||
GBinderRemoteObject* self)
|
||||
@@ -152,18 +258,6 @@ gbinder_remote_object_remove_handler(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_object_handle_death_notification(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
/* This function is invoked from the looper thread, the caller has
|
||||
* checked the object pointer */
|
||||
GVERBOSE_("%p %u", self, self->handle);
|
||||
g_main_context_invoke_full(self->priv->context, G_PRIORITY_DEFAULT,
|
||||
gbinder_remote_object_died_handle, gbinder_remote_object_ref(self),
|
||||
g_object_unref);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internals
|
||||
*==========================================================================*/
|
||||
@@ -174,36 +268,40 @@ gbinder_remote_object_init(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
GBinderRemoteObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObjectPriv);
|
||||
THIS_TYPE, GBinderRemoteObjectPriv);
|
||||
|
||||
priv->context = g_main_context_default();
|
||||
self->priv = priv;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_remote_object_dispose(
|
||||
GObject* remote)
|
||||
GObject* object)
|
||||
{
|
||||
GBinderRemoteObject* self = GBINDER_REMOTE_OBJECT(remote);
|
||||
GBinderRemoteObject* self = THIS(object);
|
||||
|
||||
gbinder_ipc_remote_object_disposed(self->ipc, self);
|
||||
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->dispose(remote);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_remote_object_finalize(
|
||||
GObject* remote)
|
||||
GObject* object)
|
||||
{
|
||||
GBinderRemoteObject* self = GBINDER_REMOTE_OBJECT(remote);
|
||||
GBinderRemoteObject* self = THIS(object);
|
||||
GBinderRemoteObjectPriv* priv = self->priv;
|
||||
GBinderIpc* ipc = self->ipc;
|
||||
GBinderDriver* driver = ipc->driver;
|
||||
|
||||
if (!self->dead) {
|
||||
gbinder_driver_clear_death_notification(driver, self);
|
||||
}
|
||||
if (priv->acquired) {
|
||||
gbinder_driver_release(driver, self->handle);
|
||||
}
|
||||
gbinder_ipc_unref(ipc);
|
||||
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->finalize(remote);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||
}
|
||||
|
||||
static
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -51,14 +51,33 @@ struct gbinder_remote_object {
|
||||
#define gbinder_remote_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
|
||||
#define gbinder_remote_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
|
||||
|
||||
typedef enum gbinder_remote_object_create {
|
||||
REMOTE_OBJECT_CREATE_DEAD,
|
||||
REMOTE_OBJECT_CREATE_ALIVE,
|
||||
REMOTE_OBJECT_CREATE_ACQUIRED
|
||||
} REMOTE_OBJECT_CREATE;
|
||||
|
||||
GBinderRemoteObject*
|
||||
gbinder_remote_object_new(
|
||||
GBinderIpc* ipc,
|
||||
guint32 handle);
|
||||
guint32 handle,
|
||||
REMOTE_OBJECT_CREATE create)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
gboolean
|
||||
gbinder_remote_object_reanimate(
|
||||
GBinderRemoteObject* obj)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_remote_object_handle_death_notification(
|
||||
GBinderRemoteObject* obj);
|
||||
GBinderRemoteObject* obj)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_remote_object_commit_suicide(
|
||||
GBinderRemoteObject* self)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_REMOTE_OBJECT_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "gbinder_local_reply_p.h"
|
||||
#include "gbinder_reader_p.h"
|
||||
#include "gbinder_object_registry.h"
|
||||
#include "gbinder_buffer.h"
|
||||
#include "gbinder_buffer_p.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_macros.h>
|
||||
@@ -65,26 +65,22 @@ gbinder_remote_reply_free(
|
||||
|
||||
gbinder_object_registry_unref(data->reg);
|
||||
gbinder_buffer_free(data->buffer);
|
||||
g_free(data->objects);
|
||||
g_slice_free(GBinderRemoteReply, self);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_reply_set_data(
|
||||
GBinderRemoteReply* self,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderBuffer* buffer)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* data = &self->data;
|
||||
|
||||
g_free(data->objects);
|
||||
gbinder_buffer_free(data->buffer);
|
||||
data->buffer = buffer;
|
||||
data->objects = objects;
|
||||
data->objects = gbinder_buffer_objects(buffer);
|
||||
} else {
|
||||
gbinder_buffer_free(buffer);
|
||||
g_free(objects);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,11 +117,23 @@ gbinder_remote_reply_is_empty(
|
||||
GBinderLocalReply*
|
||||
gbinder_remote_reply_copy_to_local(
|
||||
GBinderRemoteReply* self)
|
||||
{
|
||||
return gbinder_remote_reply_convert_to_local(self, NULL);
|
||||
}
|
||||
|
||||
GBinderLocalReply*
|
||||
gbinder_remote_reply_convert_to_local(
|
||||
GBinderRemoteReply* self,
|
||||
GBinderObjectConverter* convert)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* d = &self->data;
|
||||
GBinderObjectRegistry* reg = d->reg;
|
||||
|
||||
return gbinder_local_reply_new_from_data(d->buffer, d->objects);
|
||||
if (reg) {
|
||||
return gbinder_local_reply_set_contents
|
||||
(gbinder_local_reply_new(reg->io), d->buffer, convert);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -39,17 +39,25 @@
|
||||
|
||||
GBinderRemoteReply*
|
||||
gbinder_remote_reply_new(
|
||||
GBinderObjectRegistry* reg);
|
||||
GBinderObjectRegistry* reg)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderLocalReply*
|
||||
gbinder_remote_reply_convert_to_local(
|
||||
GBinderRemoteReply* reply,
|
||||
GBinderObjectConverter* convert)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_remote_reply_set_data(
|
||||
GBinderRemoteReply* reply,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
GBinderBuffer* buffer)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
gboolean
|
||||
gbinder_remote_reply_is_empty(
|
||||
GBinderRemoteReply* reply);
|
||||
GBinderRemoteReply* reply)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_REMOTE_REPLY_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -34,13 +34,18 @@
|
||||
#include "gbinder_reader_p.h"
|
||||
#include "gbinder_rpc_protocol.h"
|
||||
#include "gbinder_local_request_p.h"
|
||||
#include "gbinder_object_converter.h"
|
||||
#include "gbinder_object_registry.h"
|
||||
#include "gbinder_buffer.h"
|
||||
#include "gbinder_buffer_p.h"
|
||||
#include "gbinder_driver.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
struct gbinder_remote_request {
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct gbinder_remote_request_priv {
|
||||
GBinderRemoteRequest pub;
|
||||
gint refcount;
|
||||
pid_t pid;
|
||||
uid_t euid;
|
||||
@@ -49,7 +54,11 @@ struct gbinder_remote_request {
|
||||
char* iface2;
|
||||
gsize header_size;
|
||||
GBinderReaderData data;
|
||||
};
|
||||
} GBinderRemoteRequestPriv;
|
||||
|
||||
GBINDER_INLINE_FUNC GBinderRemoteRequestPriv*
|
||||
gbinder_remote_request_cast(GBinderRemoteRequest* pub)
|
||||
{ return G_LIKELY(pub) ? G_CAST(pub,GBinderRemoteRequestPriv,pub) : NULL; }
|
||||
|
||||
GBinderRemoteRequest*
|
||||
gbinder_remote_request_new(
|
||||
@@ -58,7 +67,7 @@ gbinder_remote_request_new(
|
||||
pid_t pid,
|
||||
uid_t euid)
|
||||
{
|
||||
GBinderRemoteRequest* self = g_slice_new0(GBinderRemoteRequest);
|
||||
GBinderRemoteRequestPriv* self = g_slice_new0(GBinderRemoteRequestPriv);
|
||||
GBinderReaderData* data = &self->data;
|
||||
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
@@ -66,17 +75,45 @@ gbinder_remote_request_new(
|
||||
self->euid = euid;
|
||||
self->protocol = protocol;
|
||||
data->reg = gbinder_object_registry_ref(reg);
|
||||
return self;
|
||||
return &self->pub;
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_remote_request_copy_to_local(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* d = &self->data;
|
||||
|
||||
return gbinder_local_request_new_from_data(d->buffer, d->objects);
|
||||
return gbinder_local_request_new_from_data(d->buffer, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_remote_request_convert_to_local(
|
||||
GBinderRemoteRequest* req,
|
||||
GBinderObjectConverter* convert)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* data = &self->data;
|
||||
|
||||
if (!convert || convert->protocol == self->protocol) {
|
||||
/* The same protocol, the same format of RPC header */
|
||||
return gbinder_local_request_new_from_data(data->buffer, convert);
|
||||
} else {
|
||||
/* Need to translate to another format */
|
||||
GBinderLocalRequest* local = gbinder_local_request_new_iface
|
||||
(convert->io, convert->protocol, self->iface);
|
||||
|
||||
gbinder_local_request_append_contents(local, data->buffer,
|
||||
self->header_size, convert);
|
||||
return local;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -84,22 +121,27 @@ gbinder_remote_request_copy_to_local(
|
||||
static
|
||||
void
|
||||
gbinder_remote_request_free(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequestPriv* self)
|
||||
{
|
||||
GBinderReaderData* data = &self->data;
|
||||
GBinderRemoteRequest* req = &self->pub;
|
||||
|
||||
GASSERT(!req->tx);
|
||||
if (req->tx) {
|
||||
GWARN("Request is dropped without completing the transaction");
|
||||
gbinder_remote_request_complete(req, NULL, -ECANCELED);
|
||||
}
|
||||
gbinder_object_registry_unref(data->reg);
|
||||
gbinder_buffer_free(data->buffer);
|
||||
g_free(data->objects);
|
||||
g_free(self->iface2);
|
||||
g_slice_free(GBinderRemoteRequest, self);
|
||||
g_slice_free(GBinderRemoteRequestPriv, self);
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
gbinder_remote_request_init_reader2(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderRemoteRequestPriv* self,
|
||||
GBinderReader* p)
|
||||
{
|
||||
/* The caller has already checked the request for NULL */
|
||||
@@ -116,53 +158,64 @@ gbinder_remote_request_init_reader2(
|
||||
|
||||
void
|
||||
gbinder_remote_request_set_data(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderRemoteRequest* req,
|
||||
guint32 txcode,
|
||||
GBinderBuffer* buffer)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReaderData* data = &self->data;
|
||||
GBinderReader reader;
|
||||
|
||||
g_free(self->iface2);
|
||||
g_free(data->objects);
|
||||
gbinder_buffer_free(data->buffer);
|
||||
data->buffer = buffer;
|
||||
data->objects = objects;
|
||||
data->objects = gbinder_buffer_objects(buffer);
|
||||
|
||||
/* Parse RPC header */
|
||||
self->header_size = 0;
|
||||
gbinder_remote_request_init_reader2(self, &reader);
|
||||
self->iface = self->protocol->read_rpc_header(&reader, &self->iface2);
|
||||
self->iface = self->protocol->read_rpc_header(&reader, txcode,
|
||||
&self->iface2);
|
||||
if (self->iface) {
|
||||
self->header_size = gbinder_reader_bytes_read(&reader);
|
||||
} else {
|
||||
/* No RPC header */
|
||||
self->header_size = 0;
|
||||
}
|
||||
} else {
|
||||
gbinder_buffer_free(buffer);
|
||||
g_free(objects);
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
gbinder_remote_request_interface(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
return G_LIKELY(self) ? self->iface : NULL;
|
||||
}
|
||||
|
||||
GBinderRemoteRequest*
|
||||
gbinder_remote_request_ref(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GASSERT(self->refcount > 0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
return req;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_request_unref(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GASSERT(self->refcount > 0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
@@ -173,9 +226,11 @@ gbinder_remote_request_unref(
|
||||
|
||||
void
|
||||
gbinder_remote_request_init_reader(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderRemoteRequest* req,
|
||||
GBinderReader* reader)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
gbinder_remote_request_init_reader2(self, reader);
|
||||
} else {
|
||||
@@ -185,15 +240,19 @@ gbinder_remote_request_init_reader(
|
||||
|
||||
pid_t
|
||||
gbinder_remote_request_sender_pid(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
return G_LIKELY(self) ? self->pid : (uid_t)(-1);
|
||||
}
|
||||
|
||||
uid_t
|
||||
gbinder_remote_request_sender_euid(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
return G_LIKELY(self) ? self->euid : (uid_t)(-1);
|
||||
}
|
||||
|
||||
@@ -207,9 +266,11 @@ gbinder_remote_request_read_int32(
|
||||
|
||||
gboolean
|
||||
gbinder_remote_request_read_uint32(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderRemoteRequest* req,
|
||||
guint32* value)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
@@ -229,9 +290,11 @@ gbinder_remote_request_read_int64(
|
||||
|
||||
gboolean
|
||||
gbinder_remote_request_read_uint64(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderRemoteRequest* req,
|
||||
guint64* value)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
@@ -243,8 +306,10 @@ gbinder_remote_request_read_uint64(
|
||||
|
||||
const char*
|
||||
gbinder_remote_request_read_string8(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
@@ -256,8 +321,10 @@ gbinder_remote_request_read_string8(
|
||||
|
||||
char*
|
||||
gbinder_remote_request_read_string16(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
@@ -269,8 +336,10 @@ gbinder_remote_request_read_string16(
|
||||
|
||||
GBinderRemoteObject*
|
||||
gbinder_remote_request_read_object(
|
||||
GBinderRemoteRequest* self)
|
||||
GBinderRemoteRequest* req)
|
||||
{
|
||||
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderReader reader;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -37,18 +37,30 @@
|
||||
|
||||
#include "gbinder_types_p.h"
|
||||
|
||||
struct gbinder_remote_request {
|
||||
GBinderIpcLooperTx* tx;
|
||||
};
|
||||
|
||||
GBinderRemoteRequest*
|
||||
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,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects);
|
||||
guint txcode,
|
||||
GBinderBuffer* buffer)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_remote_request_convert_to_local(
|
||||
GBinderRemoteRequest* req,
|
||||
GBinderObjectConverter* convert)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */
|
||||
|
||||
|
||||
@@ -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,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,47 @@
|
||||
*
|
||||
* 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_rpc_header(
|
||||
gbinder_rpc_protocol_aidl_write_ping(
|
||||
GBinderWriter* writer)
|
||||
{
|
||||
/* No payload */
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_rpc_protocol_aidl_write_rpc_header(
|
||||
GBinderWriter* writer,
|
||||
const char* iface)
|
||||
{
|
||||
@@ -67,11 +101,15 @@ 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)
|
||||
{
|
||||
if (gbinder_reader_read_int32(reader, NULL)) {
|
||||
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)) {
|
||||
*iface = gbinder_reader_read_string16(reader);
|
||||
} else {
|
||||
*iface = NULL;
|
||||
@@ -79,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)
|
||||
{
|
||||
@@ -95,36 +189,146 @@ gbinder_rpc_protocol_hwbinder_write_rpc_header(
|
||||
gbinder_writer_append_string8(writer, iface);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_rpc_protocol_hidl_write_ping(
|
||||
GBinderWriter* 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)
|
||||
{
|
||||
*iface = NULL;
|
||||
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 = {
|
||||
.read_rpc_header = gbinder_rpc_protocol_binder_read_rpc_header,
|
||||
.write_rpc_header = gbinder_rpc_protocol_binder_write_rpc_header
|
||||
};
|
||||
|
||||
const GBinderRpcProtocol gbinder_rpc_protocol_hwbinder = {
|
||||
.read_rpc_header = gbinder_rpc_protocol_hwbinder_read_rpc_header,
|
||||
.write_rpc_header = gbinder_rpc_protocol_hwbinder_write_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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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,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,22 +36,31 @@
|
||||
#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* (*read_rpc_header)(GBinderReader* reader, char** iface);
|
||||
const char* name;
|
||||
guint32 ping_tx;
|
||||
void (*write_ping)(GBinderWriter* writer);
|
||||
void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
|
||||
const char* (*read_rpc_header)(GBinderReader* reader, guint32 txcode,
|
||||
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 */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -14,8 +14,8 @@
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -30,20 +30,90 @@
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#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)
|
||||
|
||||
typedef struct gbinder_servicemanager_watch {
|
||||
char* name;
|
||||
char* detail;
|
||||
GQuark quark;
|
||||
gboolean watched;
|
||||
} GBinderServiceManagerWatch;
|
||||
|
||||
struct gbinder_servicemanager_priv {
|
||||
GHashTable* watch_table;
|
||||
gulong death_id;
|
||||
gboolean present;
|
||||
GBinderEventLoopTimeout* presence_check;
|
||||
guint presence_check_delay_ms;
|
||||
GBinderEventLoopCallback* autorelease_cb;
|
||||
GSList* autorelease;
|
||||
};
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
@@ -51,15 +121,24 @@ 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)
|
||||
#define GBINDER_IS_SERVICEMANAGER_TYPE(klass) \
|
||||
G_TYPE_CHECK_CLASS_TYPE(klass, GBINDER_TYPE_SERVICEMANAGER)
|
||||
|
||||
enum gbinder_servicemanager_signal {
|
||||
SIGNAL_PRESENCE,
|
||||
SIGNAL_REGISTRATION,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
static const char SIGNAL_PRESENCE_NAME[] = "servicemanager-presence";
|
||||
static const char SIGNAL_REGISTRATION_NAME[] = "servicemanager-registration";
|
||||
#define DETAIL_LEN 32
|
||||
|
||||
static guint gbinder_servicemanager_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
/*==========================================================================*
|
||||
* Implementation
|
||||
*==========================================================================*/
|
||||
@@ -81,53 +160,29 @@ gbinder_servicemanager_class_ref(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_servicemanager_new_with_type(
|
||||
GType type,
|
||||
const char* dev)
|
||||
static
|
||||
GBinderServiceManagerWatch*
|
||||
gbinder_servicemanager_watch_new(
|
||||
const char* name)
|
||||
{
|
||||
GBinderServiceManager* self = NULL;
|
||||
GBinderServiceManagerClass* klass = gbinder_servicemanager_class_ref(type);
|
||||
GBinderServiceManagerWatch* watch = g_new0(GBinderServiceManagerWatch, 1);
|
||||
|
||||
if (klass) {
|
||||
GBinderIpc* ipc;
|
||||
watch->name = g_strdup(name);
|
||||
watch->detail = g_compute_checksum_for_string(G_CHECKSUM_MD5, name, -1);
|
||||
watch->quark = g_quark_from_string(watch->detail);
|
||||
return watch;
|
||||
}
|
||||
|
||||
if (!dev) dev = klass->default_device;
|
||||
ipc = gbinder_ipc_new(dev, klass->rpc_protocol);
|
||||
if (ipc) {
|
||||
GBinderRemoteObject* object = gbinder_ipc_get_remote_object
|
||||
(ipc, klass->handle);
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_watch_free(
|
||||
gpointer data)
|
||||
{
|
||||
GBinderServiceManagerWatch* watch = data;
|
||||
|
||||
if (object) {
|
||||
/* Lock */
|
||||
g_mutex_lock(&klass->mutex);
|
||||
if (klass->table) {
|
||||
self = g_hash_table_lookup(klass->table, dev);
|
||||
}
|
||||
if (self) {
|
||||
gbinder_servicemanager_ref(self);
|
||||
} else {
|
||||
char* key = g_strdup(dev); /* Owned by the hashtable */
|
||||
|
||||
GVERBOSE_("%s", dev);
|
||||
self = g_object_new(type, NULL);
|
||||
self->client = gbinder_client_new(object, klass->iface);
|
||||
self->dev = gbinder_remote_object_dev(object);
|
||||
if (!klass->table) {
|
||||
klass->table = g_hash_table_new_full(g_str_hash,
|
||||
g_str_equal, g_free, NULL);
|
||||
}
|
||||
g_hash_table_replace(klass->table, key, self);
|
||||
}
|
||||
g_mutex_unlock(&klass->mutex);
|
||||
/* Unlock */
|
||||
gbinder_remote_object_unref(object);
|
||||
}
|
||||
gbinder_ipc_unref(ipc);
|
||||
}
|
||||
g_type_class_unref(klass);
|
||||
}
|
||||
return self;
|
||||
g_free(watch->name);
|
||||
g_free(watch->detail);
|
||||
g_free(watch);
|
||||
}
|
||||
|
||||
typedef struct gbinder_servicemanager_list_tx_data {
|
||||
@@ -144,7 +199,8 @@ gbinder_servicemanager_list_tx_exec(
|
||||
{
|
||||
GBinderServiceManagerListTxData* data = tx->user_data;
|
||||
|
||||
data->result = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->list(data->sm);
|
||||
data->result = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
|
||||
list(data->sm, &gbinder_ipc_sync_worker);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -157,6 +213,7 @@ gbinder_servicemanager_list_tx_done(
|
||||
if (!data->func(data->sm, data->result, data->user_data)) {
|
||||
g_strfreev(data->result);
|
||||
}
|
||||
data->result = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
@@ -166,6 +223,7 @@ gbinder_servicemanager_list_tx_free(
|
||||
{
|
||||
GBinderServiceManagerListTxData* data = user_data;
|
||||
|
||||
g_strfreev(data->result);
|
||||
gbinder_servicemanager_unref(data->sm);
|
||||
g_slice_free(GBinderServiceManagerListTxData, data);
|
||||
}
|
||||
@@ -186,8 +244,9 @@ gbinder_servicemanager_get_service_tx_exec(
|
||||
{
|
||||
GBinderServiceManagerGetServiceTxData* data = tx->user_data;
|
||||
|
||||
data->obj = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->get_service
|
||||
(data->sm, data->name, &data->status);
|
||||
data->obj = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
|
||||
get_service(data->sm, data->name, &data->status,
|
||||
&gbinder_ipc_sync_worker);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -229,8 +288,8 @@ gbinder_servicemanager_add_service_tx_exec(
|
||||
{
|
||||
GBinderServiceManagerAddServiceTxData* data = tx->user_data;
|
||||
|
||||
data->status = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->add_service
|
||||
(data->sm, data->name, data->obj);
|
||||
data->status = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
|
||||
add_service(data->sm, data->name, data->obj, &gbinder_ipc_sync_worker);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -256,6 +315,302 @@ gbinder_servicemanager_add_service_tx_free(
|
||||
g_slice_free(GBinderServiceManagerAddServiceTxData, data);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_reanimated(
|
||||
GBinderServiceManager* self)
|
||||
{
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
|
||||
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 */
|
||||
if (g_hash_table_size(priv->watch_table) > 0) {
|
||||
gpointer value;
|
||||
GHashTableIter it;
|
||||
GBinderServiceManagerClass* klass =
|
||||
GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
||||
|
||||
g_hash_table_iter_init(&it, priv->watch_table);
|
||||
while (g_hash_table_iter_next(&it, NULL, &value)) {
|
||||
GBinderServiceManagerWatch* watch = value;
|
||||
|
||||
GASSERT(!watch->watched);
|
||||
watch->watched = klass->watch(self, watch->name);
|
||||
if (watch->watched) {
|
||||
GDEBUG("Watching %s", watch->name);
|
||||
} else {
|
||||
GWARN("Failed to watch %s", watch->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
g_signal_emit(self, gbinder_servicemanager_signals[SIGNAL_PRESENCE], 0);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_servicemanager_presense_check_timer(
|
||||
gpointer user_data)
|
||||
{
|
||||
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(user_data);
|
||||
GBinderRemoteObject* remote = self->client->remote;
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
gboolean result;
|
||||
|
||||
GASSERT(remote->dead);
|
||||
gbinder_servicemanager_ref(self);
|
||||
if (gbinder_remote_object_reanimate(remote)) {
|
||||
/* Done */
|
||||
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 =
|
||||
gbinder_timeout_add(priv->presence_check_delay_ms,
|
||||
gbinder_servicemanager_presense_check_timer, self);
|
||||
result = G_SOURCE_REMOVE;
|
||||
} else {
|
||||
result = G_SOURCE_CONTINUE;
|
||||
}
|
||||
gbinder_servicemanager_unref(self);
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_presence_check_start(
|
||||
GBinderServiceManager* self)
|
||||
{
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
|
||||
GASSERT(!priv->presence_check);
|
||||
priv->presence_check_delay_ms = PRESENSE_WAIT_MS_MIN;
|
||||
priv->presence_check = gbinder_timeout_add(PRESENSE_WAIT_MS_MIN,
|
||||
gbinder_servicemanager_presense_check_timer, self);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_died(
|
||||
GBinderRemoteObject* remote,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(user_data);
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
|
||||
GWARN("Service manager %s has died", self->dev);
|
||||
gbinder_servicemanager_presence_check_start(self);
|
||||
|
||||
/* Will re-arm watches after servicemanager gets restarted */
|
||||
if (g_hash_table_size(priv->watch_table) > 0) {
|
||||
gpointer value;
|
||||
GHashTableIter it;
|
||||
GBinderServiceManagerClass* klass =
|
||||
GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
||||
|
||||
g_hash_table_iter_init(&it, priv->watch_table);
|
||||
while (g_hash_table_iter_next(&it, NULL, &value)) {
|
||||
GBinderServiceManagerWatch* watch = value;
|
||||
|
||||
if (watch->watched) {
|
||||
GDEBUG("Unwatching %s", watch->name);
|
||||
watch->watched = FALSE;
|
||||
klass->unwatch(self, watch->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
g_signal_emit(self, gbinder_servicemanager_signals[SIGNAL_PRESENCE], 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_sleep_ms(
|
||||
gulong ms)
|
||||
{
|
||||
struct timespec wait;
|
||||
|
||||
wait.tv_sec = ms/1000; /* seconds */
|
||||
wait.tv_nsec = (ms % 1000) * 1000000; /* nanoseconds */
|
||||
while (nanosleep(&wait, &wait) == -1 && errno == EINTR &&
|
||||
(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
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_servicemanager_new_with_type(
|
||||
GType type,
|
||||
const char* dev)
|
||||
{
|
||||
GBinderServiceManager* self = NULL;
|
||||
GBinderServiceManagerClass* klass = gbinder_servicemanager_class_ref(type);
|
||||
|
||||
if (klass) {
|
||||
GBinderIpc* ipc;
|
||||
|
||||
if (!dev) dev = klass->default_device;
|
||||
ipc = gbinder_ipc_new(dev);
|
||||
if (ipc) {
|
||||
/* Create a (possibly) dead service manager object */
|
||||
GBinderRemoteObject* object = gbinder_ipc_get_service_manager(ipc);
|
||||
|
||||
if (object) {
|
||||
gboolean first_ref;
|
||||
|
||||
/* Lock */
|
||||
g_mutex_lock(&klass->mutex);
|
||||
if (klass->table) {
|
||||
self = g_hash_table_lookup(klass->table, dev);
|
||||
}
|
||||
if (self) {
|
||||
first_ref = FALSE;
|
||||
gbinder_servicemanager_ref(self);
|
||||
} else {
|
||||
char* key = g_strdup(dev); /* Owned by the hashtable */
|
||||
|
||||
first_ref = TRUE;
|
||||
self = g_object_new(type, NULL);
|
||||
self->client = gbinder_client_new(object, klass->iface);
|
||||
self->dev = gbinder_remote_object_dev(object);
|
||||
if (!klass->table) {
|
||||
klass->table = g_hash_table_new_full(g_str_hash,
|
||||
g_str_equal, g_free, NULL);
|
||||
}
|
||||
g_hash_table_replace(klass->table, key, self);
|
||||
}
|
||||
g_mutex_unlock(&klass->mutex);
|
||||
/* Unlock */
|
||||
if (first_ref) {
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
|
||||
priv->death_id =
|
||||
gbinder_remote_object_add_death_handler(object,
|
||||
gbinder_servicemanager_died, self);
|
||||
/* Query the actual state if necessary */
|
||||
gbinder_remote_object_reanimate(object);
|
||||
if (object->dead) {
|
||||
gbinder_servicemanager_presence_check_start(self);
|
||||
}
|
||||
GDEBUG("%s has %sservice manager", dev,
|
||||
object->dead ? "no " : "");
|
||||
}
|
||||
gbinder_remote_object_unref(object);
|
||||
}
|
||||
gbinder_ipc_unref(ipc);
|
||||
}
|
||||
g_type_class_unref(klass);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_servicemanager_service_registered(
|
||||
GBinderServiceManager* self,
|
||||
const char* name)
|
||||
{
|
||||
GBinderServiceManagerClass* klass = GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
GBinderServiceManagerWatch* watch = NULL;
|
||||
const char* normalized_name;
|
||||
char* tmp_name = NULL;
|
||||
|
||||
switch (klass->check_name(self, name)) {
|
||||
case GBINDER_SERVICEMANAGER_NAME_OK:
|
||||
normalized_name = name;
|
||||
break;
|
||||
case GBINDER_SERVICEMANAGER_NAME_NORMALIZE:
|
||||
normalized_name = tmp_name = klass->normalize_name(self, name);
|
||||
break;
|
||||
default:
|
||||
normalized_name = NULL;
|
||||
break;
|
||||
}
|
||||
if (normalized_name) {
|
||||
watch = g_hash_table_lookup(priv->watch_table, normalized_name);
|
||||
}
|
||||
g_free(tmp_name);
|
||||
g_signal_emit(self, gbinder_servicemanager_signals[SIGNAL_REGISTRATION],
|
||||
watch ? watch->quark : 0, name);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Interface
|
||||
*==========================================================================*/
|
||||
@@ -264,11 +619,35 @@ GBinderServiceManager*
|
||||
gbinder_servicemanager_new(
|
||||
const char* dev)
|
||||
{
|
||||
if (!g_strcmp0(dev, GBINDER_DEFAULT_HWBINDER)) {
|
||||
return gbinder_hwservicemanager_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 {
|
||||
return gbinder_defaultservicemanager_new(dev);
|
||||
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*
|
||||
@@ -277,10 +656,25 @@ gbinder_servicemanager_new_local_object(
|
||||
const char* iface,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data)
|
||||
{
|
||||
const char* ifaces[2];
|
||||
|
||||
ifaces[0] = iface;
|
||||
ifaces[1] = NULL;
|
||||
return gbinder_servicemanager_new_local_object2
|
||||
(self, ifaces, txproc, user_data);
|
||||
}
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_servicemanager_new_local_object2(
|
||||
GBinderServiceManager* self,
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
return gbinder_ipc_new_local_object(gbinder_client_ipc(self->client),
|
||||
iface, txproc, user_data);
|
||||
return gbinder_local_object_new(gbinder_client_ipc(self->client),
|
||||
ifaces, txproc, user_data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -304,6 +698,58 @@ gbinder_servicemanager_unref(
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_servicemanager_is_present(
|
||||
GBinderServiceManager* self) /* Since 1.0.25 */
|
||||
{
|
||||
return G_LIKELY(self) && !self->client->remote->dead;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_servicemanager_wait(
|
||||
GBinderServiceManager* self,
|
||||
long max_wait_ms) /* Since 1.0.25 */
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderRemoteObject* remote = self->client->remote;
|
||||
|
||||
if (!remote->dead) {
|
||||
return TRUE;
|
||||
} else if (gbinder_remote_object_reanimate(remote)) {
|
||||
gbinder_servicemanager_reanimated(self);
|
||||
return TRUE;
|
||||
} else if (max_wait_ms != 0) {
|
||||
/* Zero timeout means a singe check and it's already done */
|
||||
long delay_ms = PRESENSE_WAIT_MS_MIN;
|
||||
|
||||
while (max_wait_ms != 0) {
|
||||
if (max_wait_ms > 0) {
|
||||
if (max_wait_ms < delay_ms) {
|
||||
delay_ms = max_wait_ms;
|
||||
max_wait_ms = 0;
|
||||
} else {
|
||||
max_wait_ms -= delay_ms;
|
||||
}
|
||||
}
|
||||
gbinder_servicemanager_sleep_ms(delay_ms);
|
||||
if (gbinder_remote_object_reanimate(remote)) {
|
||||
gbinder_servicemanager_reanimated(self);
|
||||
return TRUE;
|
||||
}
|
||||
if (delay_ms < PRESENSE_WAIT_MS_MAX) {
|
||||
delay_ms += PRESENSE_WAIT_MS_STEP;
|
||||
if (delay_ms > PRESENSE_WAIT_MS_MAX) {
|
||||
delay_ms = PRESENSE_WAIT_MS_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Timeout */
|
||||
GWARN("Timeout waiting for service manager %s", self->dev);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gulong
|
||||
gbinder_servicemanager_list(
|
||||
GBinderServiceManager* self,
|
||||
@@ -331,7 +777,8 @@ gbinder_servicemanager_list_sync(
|
||||
GBinderServiceManager* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->list(self);
|
||||
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->
|
||||
list(self, &gbinder_ipc_sync_main);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -370,12 +817,17 @@ gbinder_servicemanager_get_service_sync(
|
||||
GBinderRemoteObject* obj = NULL;
|
||||
|
||||
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();
|
||||
obj = GBINDER_SERVICEMANAGER_GET_CLASS(self)->
|
||||
get_service(self, name, status, &gbinder_ipc_sync_main);
|
||||
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);
|
||||
}
|
||||
@@ -416,8 +868,8 @@ gbinder_servicemanager_add_service_sync(
|
||||
GBinderLocalObject* obj)
|
||||
{
|
||||
if (G_LIKELY(self) && name && obj) {
|
||||
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->add_service
|
||||
(self, name, obj);
|
||||
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->
|
||||
add_service(self, name, obj, &gbinder_ipc_sync_main);
|
||||
} else {
|
||||
return (-EINVAL);
|
||||
}
|
||||
@@ -433,6 +885,140 @@ gbinder_servicemanager_cancel(
|
||||
}
|
||||
}
|
||||
|
||||
gulong
|
||||
gbinder_servicemanager_add_presence_handler(
|
||||
GBinderServiceManager* self,
|
||||
GBinderServiceManagerFunc func,
|
||||
void* user_data) /* Since 1.0.25 */
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(func)) ? g_signal_connect(self,
|
||||
SIGNAL_PRESENCE_NAME, G_CALLBACK(func), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong
|
||||
gbinder_servicemanager_add_registration_handler(
|
||||
GBinderServiceManager* self,
|
||||
const char* name,
|
||||
GBinderServiceManagerRegistrationFunc func,
|
||||
void* data) /* Since 1.0.13 */
|
||||
{
|
||||
gulong id = 0;
|
||||
|
||||
if (G_LIKELY(self) && G_LIKELY(func)) {
|
||||
char* tmp_name = NULL;
|
||||
GBinderServiceManagerClass* klass =
|
||||
GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
||||
|
||||
switch (klass->check_name(self, name)) {
|
||||
case GBINDER_SERVICEMANAGER_NAME_OK:
|
||||
break;
|
||||
case GBINDER_SERVICEMANAGER_NAME_NORMALIZE:
|
||||
name = tmp_name = klass->normalize_name(self, name);
|
||||
break;
|
||||
default:
|
||||
name = NULL;
|
||||
break;
|
||||
}
|
||||
if (name) {
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
GBinderServiceManagerWatch* watch = NULL;
|
||||
|
||||
watch = g_hash_table_lookup(priv->watch_table, name);
|
||||
if (!watch) {
|
||||
watch = gbinder_servicemanager_watch_new(name);
|
||||
g_hash_table_insert(priv->watch_table, watch->name, watch);
|
||||
}
|
||||
if (!watch->watched && !self->client->remote->dead) {
|
||||
watch->watched = klass->watch(self, watch->name);
|
||||
if (watch->watched) {
|
||||
GDEBUG("Watching %s", watch->name);
|
||||
} else {
|
||||
GWARN("Failed to watch %s", watch->name);
|
||||
}
|
||||
}
|
||||
|
||||
id = g_signal_connect_closure_by_id(self,
|
||||
gbinder_servicemanager_signals[SIGNAL_REGISTRATION],
|
||||
watch->quark, g_cclosure_new(G_CALLBACK(func), data, NULL),
|
||||
FALSE);
|
||||
}
|
||||
g_free(tmp_name);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_servicemanager_remove_handler(
|
||||
GBinderServiceManager* self,
|
||||
gulong id) /* Since 1.0.13 */
|
||||
{
|
||||
gbinder_servicemanager_remove_handlers(self, &id, 1);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_servicemanager_remove_handlers(
|
||||
GBinderServiceManager* self,
|
||||
gulong* ids,
|
||||
guint count) /* Since 1.0.25 */
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(ids) && G_LIKELY(count)) {
|
||||
guint i, disconnected = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (ids[i]) {
|
||||
g_signal_handler_disconnect(self, ids[i]);
|
||||
disconnected++;
|
||||
ids[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (disconnected) {
|
||||
GBinderServiceManagerClass* klass =
|
||||
GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
GHashTableIter it;
|
||||
gpointer value;
|
||||
|
||||
g_hash_table_iter_init(&it, priv->watch_table);
|
||||
while (disconnected && g_hash_table_iter_next(&it, NULL, &value)) {
|
||||
GBinderServiceManagerWatch* watch = value;
|
||||
|
||||
if (watch->watched && !g_signal_has_handler_pending(self,
|
||||
gbinder_servicemanager_signals[SIGNAL_REGISTRATION],
|
||||
watch->quark, TRUE)) {
|
||||
/* This must be one of those we have just removed */
|
||||
GDEBUG("Unwatching %s", watch->name);
|
||||
watch->watched = FALSE;
|
||||
klass->unwatch(self, watch->name);
|
||||
disconnected--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*==========================================================================*/
|
||||
@@ -442,6 +1028,12 @@ void
|
||||
gbinder_servicemanager_init(
|
||||
GBinderServiceManager* self)
|
||||
{
|
||||
GBinderServiceManagerPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
GBINDER_TYPE_SERVICEMANAGER, GBinderServiceManagerPriv);
|
||||
|
||||
self->priv = priv;
|
||||
priv->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
NULL, gbinder_servicemanager_watch_free);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -450,8 +1042,7 @@ gbinder_servicemanager_dispose(
|
||||
GObject* object)
|
||||
{
|
||||
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
|
||||
GBinderServiceManagerClass* klass =
|
||||
GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
||||
GBinderServiceManagerClass* klass = GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
||||
|
||||
GVERBOSE_("%s", self->dev);
|
||||
/* Lock */
|
||||
@@ -493,9 +1084,13 @@ gbinder_servicemanager_finalize(
|
||||
GObject* object)
|
||||
{
|
||||
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
|
||||
GBinderServiceManagerPriv* priv = self->priv;
|
||||
|
||||
gutil_idle_pool_drain(self->pool);
|
||||
gutil_idle_pool_unref(self->pool);
|
||||
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);
|
||||
gbinder_client_unref(self->client);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||
}
|
||||
@@ -506,10 +1101,20 @@ gbinder_servicemanager_class_init(
|
||||
GBinderServiceManagerClass* klass)
|
||||
{
|
||||
GObjectClass* object_class = G_OBJECT_CLASS(klass);
|
||||
GType type = G_OBJECT_CLASS_TYPE(klass);
|
||||
|
||||
g_mutex_init(&klass->mutex);
|
||||
g_type_class_add_private(klass, sizeof(GBinderServiceManagerPriv));
|
||||
object_class->dispose = gbinder_servicemanager_dispose;
|
||||
object_class->finalize = gbinder_servicemanager_finalize;
|
||||
gbinder_servicemanager_signals[SIGNAL_PRESENCE] =
|
||||
g_signal_new(SIGNAL_PRESENCE_NAME, type,
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
gbinder_servicemanager_signals[SIGNAL_REGISTRATION] =
|
||||
g_signal_new(SIGNAL_REGISTRATION_NAME, type,
|
||||
G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_STRING);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
343
src/gbinder_servicemanager_aidl.c
Normal file
343
src/gbinder_servicemanager_aidl.c
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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_client_p.h"
|
||||
#include "gbinder_log.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,
|
||||
const GBinderIpcSyncApi* api)
|
||||
{
|
||||
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_reply2(client,
|
||||
LIST_SERVICES_TRANSACTION, req, NULL, api)) != 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,
|
||||
const GBinderIpcSyncApi* api)
|
||||
{
|
||||
GBinderRemoteObject* obj;
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||
|
||||
gbinder_local_request_append_string16(req, name);
|
||||
reply = gbinder_client_transact_sync_reply2(self->client,
|
||||
CHECK_SERVICE_TRANSACTION, req, status, api);
|
||||
|
||||
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,
|
||||
const GBinderIpcSyncApi* api)
|
||||
{
|
||||
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_reply2(client,
|
||||
ADD_SERVICE_TRANSACTION, req, &status, api);
|
||||
|
||||
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:
|
||||
*/
|
||||
66
src/gbinder_servicemanager_aidl.h
Normal file
66
src/gbinder_servicemanager_aidl.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GBINDER_SERVICEMANAGER_AIDL_H
|
||||
#define GBINDER_SERVICEMANAGER_AIDL_H
|
||||
|
||||
#include "gbinder_servicemanager_p.h"
|
||||
|
||||
typedef struct gbinder_servicemanager_aidl_priv GBinderServiceManagerAidlPriv;
|
||||
typedef struct gbinder_servicemanager_aidl {
|
||||
GBinderServiceManager manager;
|
||||
GBinderServiceManagerAidlPriv* priv;
|
||||
} GBinderServiceManagerAidl;
|
||||
|
||||
typedef struct gbinder_servicemanager_aidl_class {
|
||||
GBinderServiceManagerClass parent;
|
||||
GBinderLocalRequest* (*list_services_req)
|
||||
(GBinderClient* client, gint32 index);
|
||||
GBinderLocalRequest* (*add_service_req)
|
||||
(GBinderClient* client, const char* name, GBinderLocalObject* obj);
|
||||
} GBinderServiceManagerAidlClass;
|
||||
|
||||
#define GBINDER_TYPE_SERVICEMANAGER_AIDL \
|
||||
gbinder_servicemanager_aidl_get_type()
|
||||
#define GBINDER_SERVICEMANAGER_AIDL_CLASS(klass) \
|
||||
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
|
||||
GBinderServiceManagerAidlClass)
|
||||
|
||||
#endif /* GBINDER_SERVICEMANAGER_AIDL_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
102
src/gbinder_servicemanager_aidl2.c
Normal file
102
src/gbinder_servicemanager_aidl2.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Jolla Ltd.
|
||||
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gbinder_servicemanager_aidl.h"
|
||||
|
||||
#include <gbinder_client.h>
|
||||
#include <gbinder_local_request.h>
|
||||
|
||||
/* Variant of AIDL servicemanager appeared in Android 9 (API level 28) */
|
||||
|
||||
typedef GBinderServiceManagerAidl GBinderServiceManagerAidl2;
|
||||
typedef GBinderServiceManagerAidlClass GBinderServiceManagerAidl2Class;
|
||||
|
||||
G_DEFINE_TYPE(GBinderServiceManagerAidl2,
|
||||
gbinder_servicemanager_aidl2,
|
||||
GBINDER_TYPE_SERVICEMANAGER_AIDL)
|
||||
|
||||
#define PARENT_CLASS gbinder_servicemanager_aidl2_parent_class
|
||||
#define DUMP_FLAG_PRIORITY_DEFAULT (0x08)
|
||||
#define DUMP_FLAG_PRIORITY_ALL (0x0f)
|
||||
|
||||
static
|
||||
GBinderLocalRequest*
|
||||
gbinder_servicemanager_aidl2_list_services_req(
|
||||
GBinderClient* client,
|
||||
gint32 index)
|
||||
{
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(client);
|
||||
|
||||
gbinder_local_request_append_int32(req, index);
|
||||
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_ALL);
|
||||
return req;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalRequest*
|
||||
gbinder_servicemanager_aidl2_add_service_req(
|
||||
GBinderClient* client,
|
||||
const char* name,
|
||||
GBinderLocalObject* obj)
|
||||
{
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(client);
|
||||
|
||||
gbinder_local_request_append_string16(req, name);
|
||||
gbinder_local_request_append_local_object(req, obj);
|
||||
gbinder_local_request_append_int32(req, 0);
|
||||
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT);
|
||||
return req;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_aidl2_init(
|
||||
GBinderServiceManagerAidl* self)
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_aidl2_class_init(
|
||||
GBinderServiceManagerAidl2Class* cls)
|
||||
{
|
||||
cls->list_services_req = gbinder_servicemanager_aidl2_list_services_req;
|
||||
cls->add_service_req = gbinder_servicemanager_aidl2_add_service_req;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
393
src/gbinder_servicemanager_hidl.c
Normal file
393
src/gbinder_servicemanager_hidl.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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_client_p.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gbinder_local_object.h>
|
||||
#include <gbinder_local_request.h>
|
||||
#include <gbinder_remote_reply.h>
|
||||
#include <gbinder_remote_request.h>
|
||||
#include <gbinder_reader.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct gbinder_servicemanager_hidl_watch {
|
||||
char* name;
|
||||
GBinderLocalObject* callback;
|
||||
} GBinderServiceManagerHidlWatch;
|
||||
|
||||
typedef GBinderServiceManagerClass GBinderServiceManagerHidlClass;
|
||||
typedef struct gbinder_servicemanager_hidl {
|
||||
GBinderServiceManager manager;
|
||||
GHashTable* watch_table;
|
||||
} GBinderServiceManagerHidl;
|
||||
|
||||
G_DEFINE_TYPE(GBinderServiceManagerHidl,
|
||||
gbinder_servicemanager_hidl,
|
||||
GBINDER_TYPE_SERVICEMANAGER)
|
||||
|
||||
#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_servicemanager_hidl_calls {
|
||||
GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
|
||||
ADD_TRANSACTION,
|
||||
GET_TRANSPORT_TRANSACTION,
|
||||
LIST_TRANSACTION,
|
||||
LIST_BY_INTERFACE_TRANSACTION,
|
||||
REGISTER_FOR_NOTIFICATIONS_TRANSACTION,
|
||||
DEBUG_DUMP_TRANSACTION,
|
||||
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
|
||||
};
|
||||
|
||||
enum gbinder_servicemanager_hidl_notifications {
|
||||
ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION
|
||||
};
|
||||
|
||||
#define SERVICEMANAGER_HIDL_IFACE "android.hidl.manager@1.0::IServiceManager"
|
||||
#define SERVICEMANAGER_HIDL_NOTIFICATION_IFACE \
|
||||
"android.hidl.manager@1.0::IServiceNotification"
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_hidl_handle_registration(
|
||||
GBinderServiceManagerHidl* self,
|
||||
GBinderReader* reader)
|
||||
{
|
||||
char* fqname = gbinder_reader_read_hidl_string(reader);
|
||||
char* name = gbinder_reader_read_hidl_string(reader);
|
||||
gboolean preexisting;
|
||||
|
||||
/* (string fqName, string name, bool preexisting) */
|
||||
if (fqname && name && gbinder_reader_read_bool(reader, &preexisting) &&
|
||||
gbinder_reader_at_end(reader)) {
|
||||
char* full_name = g_strconcat(fqname, "/", name, NULL);
|
||||
|
||||
GDEBUG("%s %s", full_name, preexisting ? "true" : "false");
|
||||
gbinder_servicemanager_service_registered(&self->manager, full_name);
|
||||
g_free(full_name);
|
||||
} else {
|
||||
GWARN("Failed to parse IServiceNotification::onRegistration payload");
|
||||
}
|
||||
g_free(fqname);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
gbinder_servicemanager_hidl_notification(
|
||||
GBinderLocalObject* obj,
|
||||
GBinderRemoteRequest* req,
|
||||
guint code,
|
||||
guint flags,
|
||||
int* status,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(user_data);
|
||||
const char* iface = gbinder_remote_request_interface(req);
|
||||
|
||||
if (!g_strcmp0(iface, SERVICEMANAGER_HIDL_NOTIFICATION_IFACE)) {
|
||||
GBinderReader reader;
|
||||
|
||||
gbinder_remote_request_init_reader(req, &reader);
|
||||
switch (code) {
|
||||
case ON_REGISTRATION_TRANSACTION:
|
||||
GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u onRegistration",
|
||||
code);
|
||||
gbinder_servicemanager_hidl_handle_registration(self, &reader);
|
||||
*status = GBINDER_STATUS_OK;
|
||||
break;
|
||||
default:
|
||||
GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u", code);
|
||||
*status = GBINDER_STATUS_FAILED;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GDEBUG("%s %u", iface, code);
|
||||
*status = GBINDER_STATUS_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
char**
|
||||
gbinder_servicemanager_hidl_list(
|
||||
GBinderServiceManager* self,
|
||||
const GBinderIpcSyncApi* api)
|
||||
{
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply2
|
||||
(self->client, LIST_TRANSACTION, req, NULL, api);
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
if (reply) {
|
||||
GBinderReader reader;
|
||||
char** result = NULL;
|
||||
int status = -1;
|
||||
|
||||
gbinder_remote_reply_init_reader(reply, &reader);
|
||||
|
||||
/* Read status */
|
||||
GVERIFY(gbinder_reader_read_int32(&reader, &status));
|
||||
GASSERT(status == GBINDER_STATUS_OK);
|
||||
|
||||
/* Followed by hidl_vec<string> */
|
||||
result = gbinder_reader_read_hidl_string_vec(&reader);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
return result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderRemoteObject*
|
||||
gbinder_servicemanager_hidl_get_service(
|
||||
GBinderServiceManager* self,
|
||||
const char* fqinstance,
|
||||
int* status,
|
||||
const GBinderIpcSyncApi* api)
|
||||
{
|
||||
/* e.g. "android.hardware.radio@1.1::IRadio/slot1" */
|
||||
const char* sep = strchr(fqinstance, '/');
|
||||
GBinderRemoteObject* obj = NULL;
|
||||
|
||||
if (sep) {
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||
char* fqname = g_strndup(fqinstance, sep - fqinstance);
|
||||
const char* name = sep + 1;
|
||||
|
||||
gbinder_local_request_append_hidl_string(req, fqname);
|
||||
gbinder_local_request_append_hidl_string(req, name);
|
||||
|
||||
reply = gbinder_client_transact_sync_reply2(self->client,
|
||||
GET_TRANSACTION, req, status, api);
|
||||
|
||||
if (reply) {
|
||||
GBinderReader reader;
|
||||
int status = -1;
|
||||
|
||||
gbinder_remote_reply_init_reader(reply, &reader);
|
||||
|
||||
/* Read status */
|
||||
GVERIFY(gbinder_reader_read_int32(&reader, &status));
|
||||
GASSERT(status == GBINDER_STATUS_OK);
|
||||
|
||||
/* Read the object */
|
||||
obj = gbinder_reader_read_object(&reader);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
}
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
g_free(fqname);
|
||||
} else {
|
||||
GERR("Invalid instance \"%s\"", fqinstance);
|
||||
if (status) *status = (-EINVAL);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
gbinder_servicemanager_hidl_add_service(
|
||||
GBinderServiceManager* self,
|
||||
const char* name,
|
||||
GBinderLocalObject* obj,
|
||||
const GBinderIpcSyncApi* api)
|
||||
{
|
||||
int status;
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||
|
||||
/* add(string name, interface service) generates (bool success); */
|
||||
gbinder_local_request_append_hidl_string(req, name);
|
||||
gbinder_local_request_append_local_object(req, obj);
|
||||
|
||||
reply = gbinder_client_transact_sync_reply2(self->client,
|
||||
ADD_TRANSACTION, req, &status, api);
|
||||
|
||||
gbinder_remote_reply_unref(reply);
|
||||
gbinder_local_request_unref(req);
|
||||
return status;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_hidl_watch_free(
|
||||
gpointer data)
|
||||
{
|
||||
GBinderServiceManagerHidlWatch* watch = data;
|
||||
|
||||
g_free(watch->name);
|
||||
gbinder_local_object_drop(watch->callback);
|
||||
g_free(watch);
|
||||
}
|
||||
|
||||
static
|
||||
GBINDER_SERVICEMANAGER_NAME_CHECK
|
||||
gbinder_servicemanager_hidl_check_name(
|
||||
GBinderServiceManager* self,
|
||||
const char* name)
|
||||
{
|
||||
if (name) {
|
||||
const gsize len = strlen(name);
|
||||
static const char allowed_chars[] = "./0123456789:@"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
if (len && strspn(name, allowed_chars) == len) {
|
||||
return strchr(name, '/') ?
|
||||
GBINDER_SERVICEMANAGER_NAME_NORMALIZE :
|
||||
GBINDER_SERVICEMANAGER_NAME_OK;
|
||||
}
|
||||
}
|
||||
return GBINDER_SERVICEMANAGER_NAME_INVALID;
|
||||
}
|
||||
|
||||
static
|
||||
char*
|
||||
gbinder_servicemanager_hidl_normalize_name(
|
||||
GBinderServiceManager* self,
|
||||
const char* name)
|
||||
{
|
||||
/* Slash must be there, see gbinder_servicemanager_hidl_check_name() */
|
||||
return g_strndup(name, strchr(name, '/') - name);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_servicemanager_hidl_watch(
|
||||
GBinderServiceManager* manager,
|
||||
const char* name)
|
||||
{
|
||||
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(manager);
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(manager->client);
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderServiceManagerHidlWatch* watch =
|
||||
g_new0(GBinderServiceManagerHidlWatch, 1);
|
||||
gboolean success = FALSE;
|
||||
int status;
|
||||
|
||||
watch->name = g_strdup(name);
|
||||
watch->callback = gbinder_servicemanager_new_local_object(manager,
|
||||
SERVICEMANAGER_HIDL_NOTIFICATION_IFACE,
|
||||
gbinder_servicemanager_hidl_notification, self);
|
||||
g_hash_table_replace(self->watch_table, watch->name, watch);
|
||||
|
||||
/* registerForNotifications(string fqName, string name,
|
||||
* IServiceNotification callback) generates (bool success); */
|
||||
gbinder_local_request_append_hidl_string(req, name);
|
||||
gbinder_local_request_append_hidl_string(req, "");
|
||||
gbinder_local_request_append_local_object(req, watch->callback);
|
||||
reply = gbinder_client_transact_sync_reply(manager->client,
|
||||
REGISTER_FOR_NOTIFICATIONS_TRANSACTION, req, &status);
|
||||
|
||||
if (status == GBINDER_STATUS_OK && reply) {
|
||||
GBinderReader reader;
|
||||
|
||||
gbinder_remote_reply_init_reader(reply, &reader);
|
||||
if (gbinder_reader_read_int32(&reader, &status) &&
|
||||
status == GBINDER_STATUS_OK) {
|
||||
gbinder_reader_read_bool(&reader, &success);
|
||||
}
|
||||
}
|
||||
gbinder_remote_reply_unref(reply);
|
||||
gbinder_local_request_unref(req);
|
||||
|
||||
if (!success) {
|
||||
/* unwatch() won't be called if we return FALSE */
|
||||
g_hash_table_remove(self->watch_table, watch->name);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_hidl_unwatch(
|
||||
GBinderServiceManager* manager,
|
||||
const char* name)
|
||||
{
|
||||
g_hash_table_remove(GBINDER_SERVICEMANAGER_HIDL(manager)->
|
||||
watch_table, name);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_hidl_init(
|
||||
GBinderServiceManagerHidl* self)
|
||||
{
|
||||
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
NULL, gbinder_servicemanager_hidl_watch_free);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_hidl_finalize(
|
||||
GObject* object)
|
||||
{
|
||||
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(object);
|
||||
|
||||
g_hash_table_destroy(self->watch_table);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicemanager_hidl_class_init(
|
||||
GBinderServiceManagerHidlClass* klass)
|
||||
{
|
||||
klass->iface = SERVICEMANAGER_HIDL_IFACE;
|
||||
klass->default_device = GBINDER_DEFAULT_HWBINDER;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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,39 +39,78 @@
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
typedef struct gbinder_servicemanager_priv GBinderServiceManagerPriv;
|
||||
|
||||
typedef struct gbinder_servicemanager {
|
||||
GObject parent;
|
||||
GBinderServiceManagerPriv* priv;
|
||||
const char* dev;
|
||||
GBinderClient* client;
|
||||
GUtilIdlePool* pool;
|
||||
} GBinderServiceManager;
|
||||
|
||||
typedef enum gbinder_servicemanager_name_check {
|
||||
GBINDER_SERVICEMANAGER_NAME_OK,
|
||||
GBINDER_SERVICEMANAGER_NAME_NORMALIZE,
|
||||
GBINDER_SERVICEMANAGER_NAME_INVALID,
|
||||
} GBINDER_SERVICEMANAGER_NAME_CHECK;
|
||||
|
||||
typedef struct gbinder_servicemanager_class {
|
||||
GObjectClass parent;
|
||||
GMutex mutex;
|
||||
GHashTable* table;
|
||||
|
||||
guint32 handle;
|
||||
const char* iface;
|
||||
const char* default_device;
|
||||
const GBinderRpcProtocol* rpc_protocol;
|
||||
|
||||
/* Methods (synchronous) */
|
||||
char** (*list)(GBinderServiceManager* self);
|
||||
GBinderRemoteObject* (*get_service)
|
||||
(GBinderServiceManager* self, const char* name, int* status);
|
||||
int (*add_service)
|
||||
(GBinderServiceManager* self, const char* name,
|
||||
GBinderLocalObject* obj);
|
||||
char** (*list)(GBinderServiceManager* self, const GBinderIpcSyncApi* api);
|
||||
GBinderRemoteObject* (*get_service)(GBinderServiceManager* self,
|
||||
const char* name, int* status, const GBinderIpcSyncApi* api);
|
||||
int (*add_service)(GBinderServiceManager* self, const char* name,
|
||||
GBinderLocalObject* obj, const GBinderIpcSyncApi* api);
|
||||
|
||||
/* Checking/normalizing watch names */
|
||||
GBINDER_SERVICEMANAGER_NAME_CHECK (*check_name)
|
||||
(GBinderServiceManager* self, const char* name);
|
||||
char* (*normalize_name)(GBinderServiceManager* self, const char* name);
|
||||
|
||||
/* If watch() returns FALSE, unwatch() is not called */
|
||||
gboolean (*watch)(GBinderServiceManager* self, const char* name);
|
||||
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)
|
||||
|
||||
#define gbinder_servicemanager_ipc(sm) gbinder_client_ipc(sm->client)
|
||||
|
||||
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)
|
||||
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 */
|
||||
|
||||
|
||||
205
src/gbinder_servicename.c
Normal file
205
src/gbinder_servicename.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2021 Jolla Ltd.
|
||||
* Copyright (C) 2019-2021 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_types_p.h"
|
||||
#include "gbinder_eventloop_p.h"
|
||||
#include "gbinder_servicename.h"
|
||||
#include "gbinder_servicemanager.h"
|
||||
#include "gbinder_local_object.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
/* Since 1.0.26 */
|
||||
|
||||
#define GBINDER_SERVICENAME_RETRY_INTERVAL_MS (500)
|
||||
|
||||
typedef struct gbinder_servicename_priv {
|
||||
GBinderServiceName pub;
|
||||
gint refcount;
|
||||
char* name;
|
||||
GBinderLocalObject* object;
|
||||
GBinderServiceManager* sm;
|
||||
GBinderEventLoopTimeout* retry_timer;
|
||||
gulong presence_id;
|
||||
gulong add_call_id;
|
||||
} GBinderServiceNamePriv;
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicename_add_service(
|
||||
GBinderServiceNamePriv* priv);
|
||||
|
||||
GBINDER_INLINE_FUNC GBinderServiceNamePriv*
|
||||
gbinder_servicename_cast(GBinderServiceName* pub)
|
||||
{ return G_CAST(pub, GBinderServiceNamePriv, pub); }
|
||||
|
||||
/*==========================================================================*
|
||||
* Implementation
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_servicename_add_service_retry(
|
||||
gpointer user_data)
|
||||
{
|
||||
GBinderServiceNamePriv* priv = user_data;
|
||||
|
||||
priv->retry_timer = NULL;
|
||||
gbinder_servicename_add_service(priv);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicename_add_service_done(
|
||||
GBinderServiceManager* sm,
|
||||
int status,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderServiceNamePriv* priv = user_data;
|
||||
|
||||
GASSERT(priv->add_call_id);
|
||||
priv->add_call_id = 0;
|
||||
if (status) {
|
||||
GWARN("Error %d adding name \"%s\"", status, priv->name);
|
||||
gbinder_timeout_remove(priv->retry_timer);
|
||||
priv->retry_timer =
|
||||
gbinder_timeout_add(GBINDER_SERVICENAME_RETRY_INTERVAL_MS,
|
||||
gbinder_servicename_add_service_retry, priv);
|
||||
} else {
|
||||
GDEBUG("Service \"%s\" has been registered", priv->name);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicename_add_service(
|
||||
GBinderServiceNamePriv* priv)
|
||||
{
|
||||
GDEBUG("Adding service \"%s\"", priv->name);
|
||||
gbinder_servicemanager_cancel(priv->sm, priv->add_call_id);
|
||||
priv->add_call_id = gbinder_servicemanager_add_service(priv->sm,
|
||||
priv->name, priv->object, gbinder_servicename_add_service_done, priv);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicename_presence_handler(
|
||||
GBinderServiceManager* sm,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderServiceNamePriv* priv = user_data;
|
||||
|
||||
if (gbinder_servicemanager_is_present(sm)) {
|
||||
gbinder_servicename_add_service(priv);
|
||||
} else {
|
||||
if (priv->add_call_id) {
|
||||
gbinder_servicemanager_cancel(priv->sm, priv->add_call_id);
|
||||
priv->add_call_id = 0;
|
||||
}
|
||||
if (priv->retry_timer) {
|
||||
gbinder_timeout_remove(priv->retry_timer);
|
||||
priv->retry_timer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Interface
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderServiceName*
|
||||
gbinder_servicename_new(
|
||||
GBinderServiceManager* sm,
|
||||
GBinderLocalObject* object,
|
||||
const char* name)
|
||||
{
|
||||
if (G_LIKELY(sm) && G_LIKELY(object) && G_LIKELY(name)) {
|
||||
GBinderServiceNamePriv* priv = g_slice_new0(GBinderServiceNamePriv);
|
||||
GBinderServiceName* self = &priv->pub;
|
||||
|
||||
g_atomic_int_set(&priv->refcount, 1);
|
||||
priv->object = gbinder_local_object_ref(object);
|
||||
priv->sm = gbinder_servicemanager_ref(sm);
|
||||
self->name = priv->name = g_strdup(name);
|
||||
priv->presence_id = gbinder_servicemanager_add_presence_handler(sm,
|
||||
gbinder_servicename_presence_handler, priv);
|
||||
if (gbinder_servicemanager_is_present(sm)) {
|
||||
gbinder_servicename_add_service(priv);
|
||||
}
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GBinderServiceName*
|
||||
gbinder_servicename_ref(
|
||||
GBinderServiceName* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderServiceNamePriv* priv = gbinder_servicename_cast(self);
|
||||
|
||||
GASSERT(priv->refcount > 0);
|
||||
g_atomic_int_inc(&priv->refcount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_servicename_unref(
|
||||
GBinderServiceName* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
GBinderServiceNamePriv* priv = gbinder_servicename_cast(self);
|
||||
|
||||
GASSERT(priv->refcount > 0);
|
||||
if (g_atomic_int_dec_and_test(&priv->refcount)) {
|
||||
gbinder_servicemanager_cancel(priv->sm, priv->add_call_id);
|
||||
gbinder_servicemanager_remove_handler(priv->sm, priv->presence_id);
|
||||
gbinder_servicemanager_unref(priv->sm);
|
||||
gbinder_local_object_unref(priv->object);
|
||||
gbinder_timeout_remove(priv->retry_timer);
|
||||
g_free(priv->name);
|
||||
gutil_slice_free(priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
269
src/gbinder_servicepoll.c
Normal file
269
src/gbinder_servicepoll.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "gbinder_servicepoll.h"
|
||||
#include "gbinder_servicemanager.h"
|
||||
#include "gbinder_eventloop_p.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
/* This is configurable mostly so that unit testing doesn't take too long */
|
||||
guint gbinder_servicepoll_interval_ms = 2000;
|
||||
|
||||
typedef GObjectClass GBinderServicePollClass;
|
||||
struct gbinder_servicepoll {
|
||||
GObject object;
|
||||
GBinderServiceManager* manager;
|
||||
char** list;
|
||||
gulong list_id;
|
||||
GBinderEventLoopTimeout* timer;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(GBinderServicePoll, gbinder_servicepoll, G_TYPE_OBJECT)
|
||||
#define GBINDER_TYPE_SERVICEPOLL (gbinder_servicepoll_get_type())
|
||||
#define GBINDER_SERVICEPOLL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
GBINDER_TYPE_SERVICEPOLL, GBinderServicePoll))
|
||||
|
||||
enum gbinder_servicepoll_signal {
|
||||
SIGNAL_NAME_ADDED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
static const char SIGNAL_NAME_ADDED_NAME[] = "servicepoll-name-added";
|
||||
|
||||
static guint gbinder_servicepoll_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
/*==========================================================================*
|
||||
* Implementation
|
||||
*==========================================================================*/
|
||||
|
||||
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
|
||||
* list, otherwise the caller will deallocate it. */
|
||||
gboolean
|
||||
gbinder_servicepoll_list(
|
||||
GBinderServiceManager* sm,
|
||||
char** services,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderServicePoll* self = GBINDER_SERVICEPOLL(user_data);
|
||||
|
||||
gbinder_servicepoll_ref(self);
|
||||
self->list_id = 0;
|
||||
if (services) {
|
||||
const GStrV* ptr_new;
|
||||
|
||||
ptr_new = services = gutil_strv_sort(services, TRUE);
|
||||
if (self->list) {
|
||||
const GStrV* ptr_old = self->list;
|
||||
|
||||
while (*ptr_new && *ptr_old) {
|
||||
const int i = gutil_strv_find(ptr_old, *ptr_new);
|
||||
|
||||
if (i < 0) {
|
||||
/* New name */
|
||||
g_signal_emit(self, gbinder_servicepoll_signals
|
||||
[SIGNAL_NAME_ADDED], 0, *ptr_new);
|
||||
} else {
|
||||
int k;
|
||||
|
||||
/* If some names have disappeared, then i may be > 0 */
|
||||
for (k = 0; k < i; k ++) ptr_old++;
|
||||
ptr_old++;
|
||||
}
|
||||
ptr_new++;
|
||||
}
|
||||
}
|
||||
while (*ptr_new) {
|
||||
g_signal_emit(self, gbinder_servicepoll_signals
|
||||
[SIGNAL_NAME_ADDED], 0, *ptr_new);
|
||||
ptr_new++;
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev(self->list);
|
||||
self->list = services;
|
||||
gbinder_servicepoll_unref(self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
gbinder_servicepoll_timer(
|
||||
gpointer user_data)
|
||||
{
|
||||
GBinderServicePoll* self = GBINDER_SERVICEPOLL(user_data);
|
||||
|
||||
if (!self->list_id) {
|
||||
self->list_id = gbinder_servicemanager_list(self->manager,
|
||||
gbinder_servicepoll_list, self);
|
||||
}
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderServicePoll*
|
||||
gbinder_servicepoll_create(
|
||||
GBinderServiceManager* manager)
|
||||
{
|
||||
GBinderServicePoll* self = g_object_new(GBINDER_TYPE_SERVICEPOLL, NULL);
|
||||
|
||||
self->manager = gbinder_servicemanager_ref(manager);
|
||||
self->list_id = gbinder_servicemanager_list(manager,
|
||||
gbinder_servicepoll_list, self);
|
||||
return self;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderServicePoll*
|
||||
gbinder_servicepoll_new(
|
||||
GBinderServiceManager* manager,
|
||||
GBinderServicePoll** weakptr)
|
||||
{
|
||||
if (weakptr) {
|
||||
if (*weakptr) {
|
||||
gbinder_servicepoll_ref(*weakptr);
|
||||
} else {
|
||||
*weakptr = gbinder_servicepoll_create(manager);
|
||||
g_object_add_weak_pointer(G_OBJECT(*weakptr), (gpointer*)weakptr);
|
||||
}
|
||||
return *weakptr;
|
||||
} else {
|
||||
return gbinder_servicepoll_create(manager);
|
||||
}
|
||||
}
|
||||
|
||||
GBinderServicePoll*
|
||||
gbinder_servicepoll_ref(
|
||||
GBinderServicePoll* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(GBINDER_SERVICEPOLL(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_servicepoll_unref(
|
||||
GBinderServicePoll* self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(GBINDER_SERVICEPOLL(self));
|
||||
}
|
||||
}
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_servicepoll_manager(
|
||||
GBinderServicePoll* self)
|
||||
{
|
||||
return G_LIKELY(self) ? self->manager : NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_servicepoll_is_known_name(
|
||||
GBinderServicePoll* self,
|
||||
const char* name)
|
||||
{
|
||||
return G_LIKELY(self) && gutil_strv_contains(self->list, name);
|
||||
}
|
||||
|
||||
gulong
|
||||
gbinder_servicepoll_add_handler(
|
||||
GBinderServicePoll* self,
|
||||
GBinderServicePollFunc fn,
|
||||
void* user_data)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(fn)) ? g_signal_connect(self,
|
||||
SIGNAL_NAME_ADDED_NAME, G_CALLBACK(fn), user_data) : 0;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_servicepoll_remove_handler(
|
||||
GBinderServicePoll* self,
|
||||
gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internals
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicepoll_init(
|
||||
GBinderServicePoll* self)
|
||||
{
|
||||
self->timer = gbinder_timeout_add(gbinder_servicepoll_interval_ms,
|
||||
gbinder_servicepoll_timer, self);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicepoll_finalize(
|
||||
GObject* object)
|
||||
{
|
||||
GBinderServicePoll* self = GBINDER_SERVICEPOLL(object);
|
||||
|
||||
gbinder_timeout_remove(self->timer);
|
||||
gbinder_servicemanager_cancel(self->manager, self->list_id);
|
||||
gbinder_servicemanager_unref(self->manager);
|
||||
g_strfreev(self->list);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_servicepoll_class_init(
|
||||
GBinderServicePollClass* klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = gbinder_servicepoll_finalize;
|
||||
gbinder_servicepoll_signals[SIGNAL_NAME_ADDED] =
|
||||
g_signal_new(SIGNAL_NAME_ADDED_NAME, G_OBJECT_CLASS_TYPE(klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
|
||||
1, G_TYPE_STRING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
95
src/gbinder_servicepoll.h
Normal file
95
src/gbinder_servicepoll.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef GBINDER_SERVICEPOLL_H
|
||||
#define GBINDER_SERVICEPOLL_H
|
||||
|
||||
#include "gbinder_types_p.h"
|
||||
|
||||
extern guint gbinder_servicepoll_interval_ms GBINDER_INTERNAL;
|
||||
|
||||
typedef
|
||||
void
|
||||
(*GBinderServicePollFunc)(
|
||||
GBinderServicePoll* poll,
|
||||
const char* name_added,
|
||||
void* user_data);
|
||||
|
||||
GBinderServicePoll*
|
||||
gbinder_servicepoll_new(
|
||||
GBinderServiceManager* manager,
|
||||
GBinderServicePoll** weakptr)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderServicePoll*
|
||||
gbinder_servicepoll_ref(
|
||||
GBinderServicePoll* poll)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_servicepoll_unref(
|
||||
GBinderServicePoll* poll)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_servicepoll_manager(
|
||||
GBinderServicePoll* poll)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
gboolean
|
||||
gbinder_servicepoll_is_known_name(
|
||||
GBinderServicePoll* poll,
|
||||
const char* name)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
gulong
|
||||
gbinder_servicepoll_add_handler(
|
||||
GBinderServicePoll* poll,
|
||||
GBinderServicePollFunc func,
|
||||
void* user_data)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_servicepoll_remove_handler(
|
||||
GBinderServicePoll* poll,
|
||||
gulong id)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
#endif /* GBINDER_SERVICEPOLL_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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,7 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
@@ -58,7 +59,10 @@ gbinder_system_ioctl(
|
||||
int request,
|
||||
void* data)
|
||||
{
|
||||
return ioctl(fd, request, data);
|
||||
int ret;
|
||||
|
||||
while ((ret = ioctl(fd, request, data)) < 0 && errno == EINTR);
|
||||
return ret >= 0 ? 0 : -errno;
|
||||
}
|
||||
|
||||
void*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
@@ -14,8 +14,8 @@
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -35,39 +35,24 @@
|
||||
|
||||
#include <gbinder_types.h>
|
||||
|
||||
typedef struct gbinder_buffer_memory GBinderBufferMemory;
|
||||
typedef struct gbinder_buffer_contents GBinderBufferContents;
|
||||
typedef struct gbinder_buffer_contents_list GBinderBufferContentsList;
|
||||
typedef struct gbinder_cleanup GBinderCleanup;
|
||||
typedef struct gbinder_driver GBinderDriver;
|
||||
typedef struct gbinder_handler GBinderHandler;
|
||||
typedef struct gbinder_io GBinderIo;
|
||||
typedef struct gbinder_ipc GBinderIpc;
|
||||
typedef struct gbinder_object_converter GBinderObjectConverter;
|
||||
typedef struct gbinder_object_registry GBinderObjectRegistry;
|
||||
typedef struct gbinder_output_data GBinderOutputData;
|
||||
typedef struct gbinder_proxy_object GBinderProxyObject;
|
||||
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;
|
||||
|
||||
typedef struct hidl_vec {
|
||||
union {
|
||||
guint64 value;
|
||||
const void* ptr;
|
||||
} data;
|
||||
guint32 count;
|
||||
guint32 owns_buffer;
|
||||
} HidlVec;
|
||||
|
||||
#define HIDL_VEC_BUFFER_OFFSET (0)
|
||||
|
||||
typedef struct hidl_string {
|
||||
union {
|
||||
guint64 value;
|
||||
const char* str;
|
||||
} data;
|
||||
guint32 len;
|
||||
guint32 owns_buffer;
|
||||
} HidlString;
|
||||
|
||||
#define HIDL_STRING_BUFFER_OFFSET (0)
|
||||
typedef struct gbinder_servicepoll GBinderServicePoll;
|
||||
typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
|
||||
typedef struct gbinder_ipc_sync_api GBinderIpcSyncApi;
|
||||
|
||||
#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')
|
||||
@@ -89,6 +74,9 @@ typedef struct hidl_string {
|
||||
#define HIDL_DEBUG_TRANSACTION HIDL_FOURCC('D','B','G')
|
||||
#define HIDL_HASH_CHAIN_TRANSACTION HIDL_FOURCC('H','S','H')
|
||||
|
||||
/* As a special case, ServiceManager's handle is zero */
|
||||
#define GBINDER_SERVICEMANAGER_HANDLE (0)
|
||||
|
||||
#endif /* GBINDER_TYPES_PRIVATE_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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
|
||||
@@ -32,14 +32,20 @@
|
||||
|
||||
#include "gbinder_writer_p.h"
|
||||
#include "gbinder_buffer_p.h"
|
||||
#include "gbinder_local_object.h"
|
||||
#include "gbinder_object_converter.h"
|
||||
#include "gbinder_io.h"
|
||||
#include "gbinder_log.h"
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
typedef struct gbinder_writer_priv {
|
||||
GBinderWriterData* data;
|
||||
@@ -52,49 +58,87 @@ GBINDER_INLINE_FUNC GBinderWriterPriv* gbinder_writer_cast(GBinderWriter* pub)
|
||||
GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub)
|
||||
{ return G_LIKELY(pub) ? gbinder_writer_cast(pub)->data : NULL; }
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_memory_cleanup(
|
||||
gpointer memory)
|
||||
{
|
||||
gbinder_buffer_memory_unref(memory);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_data_set_contents(
|
||||
GBinderWriterData* data,
|
||||
GBinderBuffer* buffer,
|
||||
void** objects)
|
||||
GBinderObjectConverter* convert)
|
||||
{
|
||||
gsize bufsize;
|
||||
const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize);
|
||||
const GBinderIo* io = gbinder_buffer_io(buffer);
|
||||
GBinderBufferMemory* mem = gbinder_buffer_memory(buffer);
|
||||
|
||||
GASSERT(data->io == io);
|
||||
g_byte_array_set_size(data->bytes, 0);
|
||||
gutil_int_array_set_count(data->offsets, 0);
|
||||
data->buffers_size = 0;
|
||||
gbinder_cleanup_reset(data->cleanup);
|
||||
gbinder_writer_data_append_contents(data, buffer, 0, convert);
|
||||
}
|
||||
|
||||
g_byte_array_append(data->bytes, bufdata, bufsize);
|
||||
if (mem) {
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup,
|
||||
gbinder_writer_data_memory_cleanup,
|
||||
gbinder_buffer_memory_ref(mem));
|
||||
}
|
||||
void
|
||||
gbinder_writer_data_append_contents(
|
||||
GBinderWriterData* data,
|
||||
GBinderBuffer* buffer,
|
||||
gsize off,
|
||||
GBinderObjectConverter* convert)
|
||||
{
|
||||
GBinderBufferContents* contents = gbinder_buffer_contents(buffer);
|
||||
|
||||
if (contents) {
|
||||
gsize bufsize;
|
||||
GByteArray* dest = data->bytes;
|
||||
const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize);
|
||||
void** objects = gbinder_buffer_objects(buffer);
|
||||
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, (GDestroyNotify)
|
||||
gbinder_buffer_contents_unref,
|
||||
gbinder_buffer_contents_ref(contents));
|
||||
if (objects && *objects) {
|
||||
const GBinderIo* io = gbinder_buffer_io(buffer);
|
||||
|
||||
/* GBinderIo must be the same because it's defined by the kernel */
|
||||
GASSERT(io == data->io);
|
||||
if (!data->offsets) {
|
||||
data->offsets = gutil_int_array_new();
|
||||
}
|
||||
while (*objects) {
|
||||
const guint8* obj = *objects++;
|
||||
gsize offset = obj - bufdata;
|
||||
gsize objsize = io->object_data_size(obj);
|
||||
gsize objsize, offset = obj - bufdata;
|
||||
GBinderLocalObject* local;
|
||||
guint32 handle;
|
||||
|
||||
GASSERT(offset >= off && offset < bufsize);
|
||||
if (offset > off) {
|
||||
/* Copy serialized data preceeding this object */
|
||||
g_byte_array_append(dest, bufdata + off, offset - off);
|
||||
off = offset;
|
||||
}
|
||||
/* Offset in the destination buffer */
|
||||
gutil_int_array_append(data->offsets, dest->len);
|
||||
|
||||
/* Convert remote object into local if necessary */
|
||||
if (convert && io->decode_binder_handle(obj, &handle) &&
|
||||
(local = gbinder_object_converter_handle_to_local
|
||||
(convert, handle))) {
|
||||
const guint pos = dest->len;
|
||||
|
||||
g_byte_array_set_size(dest, pos +
|
||||
GBINDER_MAX_BINDER_OBJECT_SIZE);
|
||||
objsize = io->encode_local_object(dest->data + pos, local);
|
||||
g_byte_array_set_size(dest, pos + objsize);
|
||||
|
||||
/* Keep the reference */
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup,
|
||||
(GDestroyNotify) gbinder_local_object_unref, local);
|
||||
} else {
|
||||
objsize = io->object_size(obj);
|
||||
g_byte_array_append(dest, obj, objsize);
|
||||
}
|
||||
|
||||
GASSERT(offset > 0 && offset < bufsize);
|
||||
gutil_int_array_append(data->offsets, (int)offset);
|
||||
/* Size of each buffer has to be 8-byte aligned */
|
||||
data->buffers_size += G_ALIGN8(objsize);
|
||||
data->buffers_size += G_ALIGN8(io->object_data_size(obj));
|
||||
off += objsize;
|
||||
}
|
||||
}
|
||||
if (off < bufsize) {
|
||||
/* Copy remaining data */
|
||||
g_byte_array_append(dest, bufdata + off, bufsize - off);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,30 +155,6 @@ gbinder_writer_data_record_offset(
|
||||
gutil_int_array_append(data->offsets, offset);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_write_buffer_object(
|
||||
GBinderWriterData* data,
|
||||
const void* ptr,
|
||||
gsize size,
|
||||
const GBinderParent* parent)
|
||||
{
|
||||
GByteArray* dest = data->bytes;
|
||||
const guint offset = dest->len;
|
||||
guint n;
|
||||
|
||||
/* Preallocate enough space */
|
||||
g_byte_array_set_size(dest, offset + GBINDER_MAX_BUFFER_OBJECT_SIZE);
|
||||
/* Write the object */
|
||||
n = data->io->encode_buffer_object(dest->data + offset, ptr, size, parent);
|
||||
/* Fix the data size */
|
||||
g_byte_array_set_size(dest, offset + n);
|
||||
/* Record the offset */
|
||||
gbinder_writer_data_record_offset(data, offset);
|
||||
/* The driver seems to require each buffer to be 8-byte aligned */
|
||||
data->buffers_size += G_ALIGN8(size);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_init(
|
||||
GBinderWriter* self,
|
||||
@@ -144,6 +164,14 @@ gbinder_writer_init(
|
||||
gbinder_writer_cast(self)->data = data;
|
||||
}
|
||||
|
||||
gsize
|
||||
gbinder_writer_bytes_written(
|
||||
GBinderWriter* self) /* since 1.0.21 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
return data->bytes->len;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_bool(
|
||||
GBinderWriter* self,
|
||||
@@ -165,7 +193,7 @@ gbinder_writer_data_append_bool(
|
||||
|
||||
/* Boolean values are padded to 4-byte boundary */
|
||||
padded[0] = (value != FALSE);
|
||||
padded[1] = padded[2] = padded[3] = 0xff;
|
||||
padded[1] = padded[2] = padded[3] = 0;
|
||||
g_byte_array_append(data->bytes, padded, sizeof(padded));
|
||||
}
|
||||
|
||||
@@ -186,13 +214,34 @@ gbinder_writer_data_append_int32(
|
||||
GBinderWriterData* data,
|
||||
guint32 value)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
guint32* ptr;
|
||||
|
||||
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
|
||||
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
|
||||
g_byte_array_set_size(buf, buf->len + sizeof(*ptr));
|
||||
ptr = (void*)(buf->data + (buf->len - sizeof(*ptr)));
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_overwrite_int32(
|
||||
GBinderWriter* self,
|
||||
gsize offset,
|
||||
gint32 value) /* since 1.0.21 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
GByteArray* buf = data->bytes;
|
||||
|
||||
if (buf->len >= offset + sizeof(gint32)) {
|
||||
*((gint32*)(buf->data + offset)) = value;
|
||||
} else {
|
||||
GWARN("Can't overwrite at %lu as buffer is only %u bytes long",
|
||||
(gulong)offset, buf->len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_int64(
|
||||
GBinderWriter* self,
|
||||
@@ -210,10 +259,11 @@ gbinder_writer_data_append_int64(
|
||||
GBinderWriterData* data,
|
||||
guint64 value)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
guint64* ptr;
|
||||
|
||||
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
|
||||
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
|
||||
g_byte_array_set_size(buf, buf->len + sizeof(*ptr));
|
||||
ptr = (void*)(buf->data + (buf->len - sizeof(*ptr)));
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
@@ -234,10 +284,11 @@ gbinder_writer_data_append_float(
|
||||
GBinderWriterData* data,
|
||||
gfloat value)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
gfloat* ptr;
|
||||
|
||||
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
|
||||
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
|
||||
g_byte_array_set_size(buf, buf->len + sizeof(*ptr));
|
||||
ptr = (void*)(buf->data + (buf->len - sizeof(*ptr)));
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
@@ -258,10 +309,11 @@ gbinder_writer_data_append_double(
|
||||
GBinderWriterData* data,
|
||||
gdouble value)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
gdouble* ptr;
|
||||
|
||||
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
|
||||
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
|
||||
g_byte_array_set_size(buf, buf->len + sizeof(*ptr));
|
||||
ptr = (void*)(buf->data + (buf->len - sizeof(*ptr)));
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
@@ -301,15 +353,16 @@ gbinder_writer_data_append_string8_len(
|
||||
gsize len)
|
||||
{
|
||||
if (G_LIKELY(str)) {
|
||||
const gsize old_size = data->bytes->len;
|
||||
GByteArray* buf = data->bytes;
|
||||
const gsize old_size = buf->len;
|
||||
gsize padded_len = G_ALIGN4(len + 1);
|
||||
guint32* dest;
|
||||
|
||||
/* Preallocate space */
|
||||
g_byte_array_set_size(data->bytes, old_size + padded_len);
|
||||
g_byte_array_set_size(buf, old_size + padded_len);
|
||||
|
||||
/* Zero the last word */
|
||||
dest = (guint32*)(data->bytes->data + old_size);
|
||||
dest = (guint32*)(buf->data + old_size);
|
||||
dest[padded_len/4 - 1] = 0;
|
||||
|
||||
/* Copy the data */
|
||||
@@ -346,14 +399,36 @@ gbinder_writer_data_append_string16(
|
||||
gbinder_writer_data_append_string16_len(data, utf8, utf8? strlen(utf8) : 0);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_append_string16_null(
|
||||
GBinderWriterData* data)
|
||||
{
|
||||
/* NULL string */
|
||||
gbinder_writer_data_append_int32(data, -1);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_append_string16_empty(
|
||||
GBinderWriterData* data)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
const gsize old_size = buf->len;
|
||||
guint16* ptr16;
|
||||
|
||||
/* Empty string */
|
||||
g_byte_array_set_size(buf, old_size + 8);
|
||||
ptr16 = (guint16*)(buf->data + old_size);
|
||||
ptr16[0] = ptr16[1] = ptr16[2] = 0; ptr16[3] = 0xffff;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_data_append_string16_len(
|
||||
GBinderWriterData* data,
|
||||
const char* utf8,
|
||||
gssize num_bytes)
|
||||
{
|
||||
const gsize old_size = data->bytes->len;
|
||||
|
||||
if (utf8) {
|
||||
const char* end = utf8;
|
||||
|
||||
@@ -364,14 +439,16 @@ gbinder_writer_data_append_string16_len(
|
||||
}
|
||||
|
||||
if (num_bytes > 0) {
|
||||
GByteArray* buf = data->bytes;
|
||||
const gsize old_size = buf->len;
|
||||
glong len = g_utf8_strlen(utf8, num_bytes);
|
||||
gsize padded_len = G_ALIGN4((len+1)*2);
|
||||
guint32* len_ptr;
|
||||
gunichar2* utf16_ptr;
|
||||
|
||||
/* Preallocate space */
|
||||
g_byte_array_set_size(data->bytes, old_size + padded_len + 4);
|
||||
len_ptr = (guint32*)(data->bytes->data + old_size);
|
||||
g_byte_array_set_size(buf, old_size + padded_len + 4);
|
||||
len_ptr = (guint32*)(buf->data + old_size);
|
||||
utf16_ptr = (gunichar2*)(len_ptr + 1);
|
||||
|
||||
/* TODO: this could be optimized for ASCII strings, i.e. if
|
||||
@@ -398,17 +475,72 @@ gbinder_writer_data_append_string16_len(
|
||||
}
|
||||
|
||||
/* Correct the packet size if necessaary */
|
||||
g_byte_array_set_size(data->bytes, old_size + padded_len + 4);
|
||||
g_byte_array_set_size(buf, old_size + padded_len + 4);
|
||||
} else if (utf8) {
|
||||
/* Empty string */
|
||||
guint16* ptr16;
|
||||
|
||||
g_byte_array_set_size(data->bytes, old_size + 8);
|
||||
ptr16 = (guint16*)(data->bytes->data + old_size);
|
||||
ptr16[0] = ptr16[1] = ptr16[2] = 0; ptr16[3] = 0xffff;
|
||||
gbinder_writer_data_append_string16_empty(data);
|
||||
} else {
|
||||
/* NULL string */
|
||||
gbinder_writer_data_append_int32(data, -1);
|
||||
gbinder_writer_data_append_string16_null(data);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_append_string16_utf16(
|
||||
GBinderWriterData* data,
|
||||
const gunichar2* utf16,
|
||||
gssize length)
|
||||
{
|
||||
if (length < 0) {
|
||||
length = 0;
|
||||
if (utf16) {
|
||||
const guint16* ptr;
|
||||
|
||||
/* Assume NULL terminated string */
|
||||
for (ptr = utf16; *ptr; ptr++);
|
||||
length = ptr - utf16;
|
||||
}
|
||||
}
|
||||
if (length > 0) {
|
||||
GByteArray* buf = data->bytes;
|
||||
const gsize old_size = buf->len;
|
||||
const gsize padded_size = G_ALIGN4((length + 1) * 2);
|
||||
guint32* len_ptr;
|
||||
gunichar2* utf16_ptr;
|
||||
|
||||
/* Preallocate space */
|
||||
g_byte_array_set_size(buf, old_size + padded_size + 4);
|
||||
len_ptr = (guint32*)(buf->data + old_size);
|
||||
utf16_ptr = (gunichar2*)(len_ptr + 1);
|
||||
|
||||
/* Actual length */
|
||||
*len_ptr = length;
|
||||
|
||||
/* Characters */
|
||||
memcpy(utf16_ptr, utf16, 2 * length);
|
||||
|
||||
/* Zero padding */
|
||||
memset(utf16_ptr + length, 0, padded_size - 2 * length);
|
||||
} else if (utf16) {
|
||||
/* Empty string */
|
||||
gbinder_writer_data_append_string16_empty(data);
|
||||
} else {
|
||||
/* NULL string */
|
||||
gbinder_writer_data_append_string16_null(data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_string16_utf16(
|
||||
GBinderWriter* self,
|
||||
const gunichar2* utf16,
|
||||
gssize length) /* Since 1.0.17 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
gbinder_writer_data_append_string16_utf16(data, utf16, length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,14 +558,57 @@ gbinder_writer_append_bytes(
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
gbinder_writer_data_prepare(
|
||||
GBinderWriterData* data)
|
||||
void
|
||||
gbinder_writer_data_close_fd(
|
||||
gpointer data)
|
||||
{
|
||||
if (!data->offsets) {
|
||||
data->offsets = gutil_int_array_new();
|
||||
const int fd = GPOINTER_TO_INT(data);
|
||||
|
||||
if (close(fd) < 0) {
|
||||
GWARN("Error closing fd %d: %s", fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_writer_data_append_fd(
|
||||
GBinderWriterData* data,
|
||||
int fd)
|
||||
{
|
||||
GByteArray* buf = data->bytes;
|
||||
const guint offset = buf->len;
|
||||
/* Duplicate the descriptor so that caller can do whatever with
|
||||
* the one it passed in. */
|
||||
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||
guint written;
|
||||
|
||||
/* Preallocate enough space */
|
||||
g_byte_array_set_size(buf, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
|
||||
/* Write the original fd if we failed to dup it */
|
||||
if (dupfd < 0) {
|
||||
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
|
||||
written = data->io->encode_fd_object(buf->data + offset, fd);
|
||||
} else {
|
||||
written = data->io->encode_fd_object(buf->data + offset, dupfd);
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup,
|
||||
gbinder_writer_data_close_fd, GINT_TO_POINTER(dupfd));
|
||||
}
|
||||
/* Fix the data size */
|
||||
g_byte_array_set_size(buf, offset + written);
|
||||
/* Record the offset */
|
||||
gbinder_writer_data_record_offset(data, offset);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_fd(
|
||||
GBinderWriter* self,
|
||||
int fd) /* Since 1.0.18 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
gbinder_writer_data_append_fd(data, fd);
|
||||
}
|
||||
return data->offsets->count;
|
||||
}
|
||||
|
||||
guint
|
||||
@@ -472,9 +647,21 @@ gbinder_writer_data_append_buffer_object(
|
||||
gsize size,
|
||||
const GBinderParent* parent)
|
||||
{
|
||||
guint index = gbinder_writer_data_prepare(data);
|
||||
const guint index = data->offsets ? data->offsets->count : 0;
|
||||
GByteArray* buf = data->bytes;
|
||||
const guint offset = buf->len;
|
||||
guint n;
|
||||
|
||||
gbinder_writer_data_write_buffer_object(data, ptr, size, parent);
|
||||
/* Preallocate enough space */
|
||||
g_byte_array_set_size(buf, offset + GBINDER_MAX_BUFFER_OBJECT_SIZE);
|
||||
/* Write the object */
|
||||
n = data->io->encode_buffer_object(buf->data + offset, ptr, size, parent);
|
||||
/* Fix the data size */
|
||||
g_byte_array_set_size(buf, offset + n);
|
||||
/* Record the offset */
|
||||
gbinder_writer_data_record_offset(data, offset);
|
||||
/* The driver seems to require each buffer to be 8-byte aligned */
|
||||
data->buffers_size += G_ALIGN8(size);
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -490,19 +677,72 @@ gbinder_writer_append_hidl_string(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_hidl_string_copy(
|
||||
GBinderWriter* self,
|
||||
const char* str) /* Since 1.1.13 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
static const char empty[] = "";
|
||||
|
||||
gbinder_writer_data_append_hidl_string(data, str ? (str[0] ?
|
||||
gbinder_writer_strdup(self, str) : empty) : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_data_append_hidl_vec(
|
||||
GBinderWriterData* data,
|
||||
const void* base,
|
||||
guint count,
|
||||
guint elemsize)
|
||||
{
|
||||
GBinderParent vec_parent;
|
||||
GBinderHidlVec* vec = g_new0(GBinderHidlVec, 1);
|
||||
const gsize total = count * elemsize;
|
||||
void* buf = gutil_memdup(base, total);
|
||||
|
||||
/* Fill in the vector descriptor */
|
||||
if (buf) {
|
||||
vec->data.ptr = buf;
|
||||
vec->count = count;
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, buf);
|
||||
}
|
||||
vec->owns_buffer = TRUE;
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, vec);
|
||||
|
||||
/* Every vector, even the one without data, requires two buffer objects */
|
||||
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
|
||||
vec_parent.index = gbinder_writer_data_append_buffer_object(data,
|
||||
vec, sizeof(*vec), NULL);
|
||||
gbinder_writer_data_append_buffer_object(data, buf, total, &vec_parent);
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_hidl_vec(
|
||||
GBinderWriter* self,
|
||||
const void* base,
|
||||
guint count,
|
||||
guint elemsize)
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
gbinder_writer_data_append_hidl_vec(data, base, count, elemsize);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_data_append_hidl_string(
|
||||
GBinderWriterData* data,
|
||||
const char* str)
|
||||
{
|
||||
GBinderParent str_parent;
|
||||
HidlString* hidl_string = g_new0(HidlString, 1);
|
||||
GBinderHidlString* hidl_string = g_new0(GBinderHidlString, 1);
|
||||
const gsize len = str ? strlen(str) : 0;
|
||||
|
||||
/* Prepare parent descriptor for the string data */
|
||||
str_parent.index = gbinder_writer_data_prepare(data);
|
||||
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
|
||||
|
||||
/* Fill in the string descriptor and store it */
|
||||
hidl_string->data.str = str;
|
||||
hidl_string->len = len;
|
||||
@@ -510,16 +750,18 @@ gbinder_writer_data_append_hidl_string(
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, hidl_string);
|
||||
|
||||
/* Write the buffer object pointing to the string descriptor */
|
||||
gbinder_writer_data_write_buffer_object(data, hidl_string,
|
||||
sizeof(*hidl_string), NULL);
|
||||
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
|
||||
str_parent.index = gbinder_writer_data_append_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);
|
||||
gbinder_writer_data_append_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_append_buffer_object(data, NULL, 0, &str_parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,8 +785,8 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
gssize count)
|
||||
{
|
||||
GBinderParent vec_parent;
|
||||
HidlVec* vec = g_new0(HidlVec, 1);
|
||||
HidlString* strings = NULL;
|
||||
GBinderHidlVec* vec = g_new0(GBinderHidlVec, 1);
|
||||
GBinderHidlString* strings = NULL;
|
||||
int i;
|
||||
|
||||
if (count < 0) {
|
||||
@@ -552,13 +794,9 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
count = gutil_strv_length((char**)strv);
|
||||
}
|
||||
|
||||
/* Prepare parent descriptor for the vector data */
|
||||
vec_parent.index = gbinder_writer_data_prepare(data);
|
||||
vec_parent.offset = HIDL_VEC_BUFFER_OFFSET;
|
||||
|
||||
/* Fill in the vector descriptor */
|
||||
if (count > 0) {
|
||||
strings = g_new0(HidlString, count);
|
||||
strings = g_new0(GBinderHidlString, count);
|
||||
vec->data.ptr = strings;
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, strings);
|
||||
}
|
||||
@@ -569,7 +807,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
/* Fill in string descriptors */
|
||||
for (i = 0; i < count; i++) {
|
||||
const char* str = strv[i];
|
||||
HidlString* hidl_str = strings + i;
|
||||
GBinderHidlString* hidl_str = strings + i;
|
||||
|
||||
if ((hidl_str->data.str = str) != NULL) {
|
||||
hidl_str->len = strlen(str);
|
||||
@@ -578,31 +816,41 @@ gbinder_writer_data_append_hidl_string_vec(
|
||||
}
|
||||
|
||||
/* Write the vector object */
|
||||
gbinder_writer_data_write_buffer_object(data, vec, sizeof(*vec), NULL);
|
||||
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
|
||||
vec_parent.index = gbinder_writer_data_append_buffer_object(data,
|
||||
vec, sizeof(*vec), NULL);
|
||||
|
||||
if (strings) {
|
||||
GBinderParent str_parent;
|
||||
|
||||
/* Prepare parent descriptor for the string data */
|
||||
str_parent.index = data->offsets->count;
|
||||
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
|
||||
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
|
||||
|
||||
/* Write the vector data (it's parent for the string data) */
|
||||
gbinder_writer_data_write_buffer_object(data, strings,
|
||||
gbinder_writer_data_append_buffer_object(data, strings,
|
||||
sizeof(*strings) * count, &vec_parent);
|
||||
|
||||
/* Write the string data */
|
||||
for (i = 0; i < count; i++) {
|
||||
HidlString* hidl_str = strings + i;
|
||||
GBinderHidlString* hidl_str = strings + i;
|
||||
|
||||
if (hidl_str->data.str) {
|
||||
gbinder_writer_data_write_buffer_object(data,
|
||||
gbinder_writer_data_append_buffer_object(data,
|
||||
hidl_str->data.str, hidl_str->len + 1, &str_parent);
|
||||
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_append_buffer_object(data, NULL, 0,
|
||||
&str_parent);
|
||||
}
|
||||
str_parent.offset += sizeof(HidlString);
|
||||
str_parent.offset += sizeof(GBinderHidlString);
|
||||
}
|
||||
} else {
|
||||
gbinder_writer_data_append_buffer_object(data, NULL, 0, &vec_parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,16 +871,16 @@ gbinder_writer_data_append_local_object(
|
||||
GBinderWriterData* data,
|
||||
GBinderLocalObject* obj)
|
||||
{
|
||||
GByteArray* dest = data->bytes;
|
||||
const guint offset = dest->len;
|
||||
GByteArray* buf = data->bytes;
|
||||
const guint offset = buf->len;
|
||||
guint n;
|
||||
|
||||
/* Preallocate enough space */
|
||||
g_byte_array_set_size(dest, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
|
||||
g_byte_array_set_size(buf, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
|
||||
/* Write the object */
|
||||
n = data->io->encode_local_object(dest->data + offset, obj);
|
||||
n = data->io->encode_local_object(buf->data + offset, obj);
|
||||
/* Fix the data size */
|
||||
g_byte_array_set_size(dest, offset + n);
|
||||
g_byte_array_set_size(buf, offset + n);
|
||||
/* Record the offset */
|
||||
gbinder_writer_data_record_offset(data, offset);
|
||||
}
|
||||
@@ -649,25 +897,130 @@ gbinder_writer_append_remote_object(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_byte_array(
|
||||
GBinderWriter* self,
|
||||
const void* byte_array,
|
||||
gint32 len) /* since 1.0.12 */
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
GASSERT(len >= 0);
|
||||
if (G_LIKELY(data)) {
|
||||
GByteArray* buf = data->bytes;
|
||||
void* ptr;
|
||||
|
||||
if (!byte_array) {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
g_byte_array_set_size(buf, buf->len + sizeof(len) + len);
|
||||
ptr = buf->data + (buf->len - sizeof(len) - len);
|
||||
|
||||
if (len > 0) {
|
||||
*((gint32*)ptr) = len;
|
||||
ptr += sizeof(len);
|
||||
memcpy(ptr, byte_array, len);
|
||||
} else {
|
||||
*((gint32*)ptr) = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_data_append_remote_object(
|
||||
GBinderWriterData* data,
|
||||
GBinderRemoteObject* obj)
|
||||
{
|
||||
GByteArray* dest = data->bytes;
|
||||
const guint offset = dest->len;
|
||||
GByteArray* buf = data->bytes;
|
||||
const guint offset = buf->len;
|
||||
guint n;
|
||||
|
||||
/* Preallocate enough space */
|
||||
g_byte_array_set_size(dest, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
|
||||
g_byte_array_set_size(buf, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
|
||||
/* Write the object */
|
||||
n = data->io->encode_remote_object(dest->data + offset, obj);
|
||||
n = data->io->encode_remote_object(buf->data + offset, obj);
|
||||
/* Fix the data size */
|
||||
g_byte_array_set_size(dest, offset + n);
|
||||
g_byte_array_set_size(buf, offset + n);
|
||||
/* Record the offset */
|
||||
gbinder_writer_data_record_offset(data, offset);
|
||||
}
|
||||
|
||||
static
|
||||
void*
|
||||
gbinder_writer_alloc(
|
||||
GBinderWriter* self,
|
||||
gsize size,
|
||||
gpointer (*alloc)(gsize),
|
||||
void (*dealloc)())
|
||||
{
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
void* ptr = alloc(size);
|
||||
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, dealloc, ptr);
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void*
|
||||
gbinder_writer_malloc(
|
||||
GBinderWriter* self,
|
||||
gsize size) /* since 1.0.19 */
|
||||
{
|
||||
return gbinder_writer_alloc(self, size, g_malloc, g_free);
|
||||
}
|
||||
|
||||
void*
|
||||
gbinder_writer_malloc0(
|
||||
GBinderWriter* self,
|
||||
gsize size) /* since 1.0.19 */
|
||||
{
|
||||
return gbinder_writer_alloc(self, size, g_malloc0, g_free);
|
||||
}
|
||||
|
||||
char*
|
||||
gbinder_writer_strdup(
|
||||
GBinderWriter* writer,
|
||||
const char* str) /* since 1.1.13 */
|
||||
{
|
||||
return str ? gbinder_writer_memdup(writer, str, strlen(str) + 1) : NULL;
|
||||
}
|
||||
|
||||
void*
|
||||
gbinder_writer_memdup(
|
||||
GBinderWriter* self,
|
||||
const void* buf,
|
||||
gsize size) /* since 1.0.19 */
|
||||
{
|
||||
if (buf) {
|
||||
void* ptr = gbinder_writer_malloc(self, size);
|
||||
|
||||
if (ptr) {
|
||||
memcpy(ptr, buf, size);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_add_cleanup(
|
||||
GBinderWriter* self,
|
||||
GDestroyNotify destroy,
|
||||
gpointer ptr) /* since 1.0.19 */
|
||||
{
|
||||
if (G_LIKELY(destroy)) {
|
||||
GBinderWriterData* data = gbinder_writer_data(self);
|
||||
|
||||
if (G_LIKELY(data)) {
|
||||
data->cleanup = gbinder_cleanup_add(data->cleanup, destroy, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 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,88 +48,120 @@ 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,
|
||||
void** objects);
|
||||
GBinderObjectConverter* convert)
|
||||
GBINDER_INTERNAL;
|
||||
|
||||
void
|
||||
gbinder_writer_data_append_contents(
|
||||
GBinderWriterData* data,
|
||||
GBinderBuffer* buffer,
|
||||
gsize data_offset,
|
||||
GBinderObjectConverter* convert)
|
||||
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)
|
||||
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 */
|
||||
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
all:
|
||||
%:
|
||||
@$(MAKE) -C binder-bridge $*
|
||||
@$(MAKE) -C binder-client $*
|
||||
@$(MAKE) -C binder-dump $*
|
||||
@$(MAKE) -C binder-list $*
|
||||
@$(MAKE) -C binder-ping $*
|
||||
@$(MAKE) -C binder-service $*
|
||||
@$(MAKE) -C binder-call $*
|
||||
@$(MAKE) -C rild-card-status $*
|
||||
|
||||
140
test/ashmem-test/Makefile
Normal file
140
test/ashmem-test/Makefile
Normal file
@@ -0,0 +1,140 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
.PHONY: all debug release clean cleaner
|
||||
.PHONY: libgbinder-release libgbinder-debug
|
||||
|
||||
#
|
||||
# Required packages
|
||||
#
|
||||
|
||||
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
|
||||
|
||||
#
|
||||
# Default target
|
||||
#
|
||||
|
||||
all: debug release
|
||||
|
||||
#
|
||||
# Executable
|
||||
#
|
||||
|
||||
EXE = ashmem-test
|
||||
|
||||
#
|
||||
# Sources
|
||||
#
|
||||
|
||||
SRC = $(EXE).c
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
SRC_DIR = .
|
||||
BUILD_DIR = build
|
||||
LIB_DIR = ../..
|
||||
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
|
||||
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
|
||||
|
||||
#
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
LD = $(CC)
|
||||
WARNINGS = -Wall
|
||||
INCLUDES = -I$(LIB_DIR)/include
|
||||
BASE_FLAGS = -fPIC
|
||||
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
|
||||
$(shell pkg-config --cflags $(PKGS))
|
||||
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
|
||||
QUIET_MAKE = make --no-print-directory
|
||||
DEBUG_FLAGS = -g
|
||||
RELEASE_FLAGS =
|
||||
|
||||
ifndef KEEP_SYMBOLS
|
||||
KEEP_SYMBOLS = 0
|
||||
endif
|
||||
|
||||
ifneq ($(KEEP_SYMBOLS),0)
|
||||
RELEASE_FLAGS += -g
|
||||
SUBMAKE_OPTS += KEEP_SYMBOLS=1
|
||||
endif
|
||||
|
||||
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
|
||||
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
|
||||
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
|
||||
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
|
||||
|
||||
#
|
||||
# Files
|
||||
#
|
||||
|
||||
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
|
||||
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
|
||||
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
|
||||
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
|
||||
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
|
||||
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
|
||||
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
|
||||
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
|
||||
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(strip $(DEPS)),)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
|
||||
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
|
||||
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
|
||||
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
|
||||
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
|
||||
|
||||
debug: libgbinder-debug $(DEBUG_EXE)
|
||||
|
||||
release: libgbinder-release $(RELEASE_EXE)
|
||||
|
||||
clean:
|
||||
rm -f *~
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
cleaner: clean
|
||||
@make -C $(LIB_DIR) clean
|
||||
|
||||
$(DEBUG_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(RELEASE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
|
||||
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
|
||||
|
||||
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
|
||||
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
|
||||
ifeq ($(KEEP_SYMBOLS),0)
|
||||
strip $@
|
||||
endif
|
||||
|
||||
libgbinder-debug:
|
||||
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
|
||||
|
||||
libgbinder-release:
|
||||
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
|
||||
260
test/ashmem-test/ashmem-test.c
Normal file
260
test/ashmem-test/ashmem-test.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 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.h>
|
||||
|
||||
#include <gutil_misc.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define RET_OK (0)
|
||||
#define RET_NOTFOUND (1)
|
||||
#define RET_INVARG (2)
|
||||
#define RET_ERR (3)
|
||||
|
||||
#define DEFAULT_BINDER GBINDER_DEFAULT_HWBINDER
|
||||
#define ALLOCATOR_IFACE "android.hidl.allocator@1.0::IAllocator"
|
||||
#define DEFAULT_FQNAME ALLOCATOR_IFACE "/ashmem"
|
||||
#define TX_ALLOCATE GBINDER_FIRST_CALL_TRANSACTION
|
||||
|
||||
typedef struct app_options {
|
||||
const char* fqname;
|
||||
char* dev;
|
||||
gsize size;
|
||||
} AppOptions;
|
||||
|
||||
static
|
||||
void
|
||||
app_dumpmem(
|
||||
const GBinderHidlMemory* mem)
|
||||
{
|
||||
const GBinderFds* fds = mem->data.fds;
|
||||
|
||||
GDEBUG("Name: %s", mem->name.data.str);
|
||||
GDEBUG("Size: %" G_GUINT64_FORMAT " bytes", mem->size);
|
||||
|
||||
GASSERT(fds->version == GBINDER_HIDL_FDS_VERSION);
|
||||
GDEBUG("Contains %u fd(s)", fds->num_fds);
|
||||
if (fds->num_fds) {
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < fds->num_fds; i++) {
|
||||
int fd = gbinder_fds_get_fd(fds, i);
|
||||
guint8* ptr = mmap(NULL, mem->size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
|
||||
if (ptr) {
|
||||
gsize off = 0;
|
||||
|
||||
GDEBUG("fd %d => %p", fd, ptr);
|
||||
while (off < mem->size) {
|
||||
char line[GUTIL_HEXDUMP_BUFSIZE];
|
||||
guint n = gutil_hexdump(line, ptr + off, mem->size - off);
|
||||
|
||||
GDEBUG("%04X: %s", (uint) off, line);
|
||||
off += n;
|
||||
}
|
||||
munmap(ptr, mem->size);
|
||||
} else {
|
||||
GDEBUG("fd %d", fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
app_allocate(
|
||||
const AppOptions* opt,
|
||||
GBinderClient* client)
|
||||
{
|
||||
GBinderLocalRequest* request = gbinder_client_new_request(client);
|
||||
GBinderRemoteReply* reply;
|
||||
int status, ret;
|
||||
|
||||
gbinder_local_request_append_int64(request, opt->size);
|
||||
reply = gbinder_client_transact_sync_reply(client, TX_ALLOCATE,
|
||||
request, &status);
|
||||
|
||||
if (reply) {
|
||||
GBinderReader reader;
|
||||
gint32 tx_status;
|
||||
gboolean success;
|
||||
|
||||
gbinder_remote_reply_init_reader(reply, &reader);
|
||||
if (gbinder_reader_read_int32(&reader, &tx_status) &&
|
||||
gbinder_reader_read_bool(&reader, &success) &&
|
||||
tx_status == GBINDER_STATUS_OK &&
|
||||
success) {
|
||||
const GBinderHidlMemory* mem = gbinder_reader_read_hidl_struct
|
||||
(&reader, GBinderHidlMemory);
|
||||
|
||||
if (mem) {
|
||||
GINFO("OK");
|
||||
app_dumpmem(mem);
|
||||
} else {
|
||||
GINFO("OOPS");
|
||||
}
|
||||
} else {
|
||||
GINFO("FAILED");
|
||||
}
|
||||
ret = RET_OK;
|
||||
} else {
|
||||
GERR("Call failed (%d)", status);
|
||||
ret = RET_ERR;
|
||||
}
|
||||
|
||||
gbinder_local_request_unref(request);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
app_run(
|
||||
const AppOptions* opt)
|
||||
{
|
||||
int ret = RET_NOTFOUND;
|
||||
GBinderServiceManager* sm = gbinder_servicemanager_new(opt->dev);
|
||||
|
||||
if (sm) {
|
||||
int status = 0;
|
||||
GBinderRemoteObject* remote = gbinder_servicemanager_get_service_sync
|
||||
(sm, opt->fqname, &status);
|
||||
|
||||
if (remote) {
|
||||
GBinderClient* client = gbinder_client_new(remote, ALLOCATOR_IFACE);
|
||||
|
||||
ret = app_allocate(opt, client);
|
||||
gbinder_client_unref(client);
|
||||
} else {
|
||||
GERR("%s not found", opt->fqname);
|
||||
}
|
||||
gbinder_servicemanager_unref(sm);
|
||||
} else {
|
||||
GERR("No servicemanager at %s", opt->dev);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_verbose(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_VERBOSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_quiet(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_NONE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_init(
|
||||
AppOptions* opt,
|
||||
int argc,
|
||||
char* argv[])
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
GOptionEntry entries[] = {
|
||||
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_verbose, "Enable verbose output", NULL },
|
||||
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_quiet, "Be quiet", NULL },
|
||||
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
|
||||
"Binder device [" DEFAULT_BINDER "]", "DEVICE" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
GError* error = NULL;
|
||||
GOptionContext* options = g_option_context_new("[FQNAME]");
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
|
||||
|
||||
g_option_context_add_main_entries(options, entries, NULL);
|
||||
if (g_option_context_parse(options, &argc, &argv, &error)) {
|
||||
if (!opt->dev || !opt->dev[0]) {
|
||||
opt->dev = g_strdup(DEFAULT_BINDER);
|
||||
}
|
||||
if (argc < 3) {
|
||||
opt->fqname = ((argc == 2) ? argv[1] : DEFAULT_FQNAME);
|
||||
opt->size = 64;
|
||||
ok = TRUE;
|
||||
} else {
|
||||
char* help = g_option_context_get_help(options, TRUE, NULL);
|
||||
|
||||
fprintf(stderr, "%s", help);
|
||||
g_free(help);
|
||||
}
|
||||
} else {
|
||||
GERR("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
g_option_context_free(options);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
AppOptions opt;
|
||||
int ret = RET_INVARG;
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
if (app_init(&opt, argc, argv)) {
|
||||
ret = app_run(&opt);
|
||||
}
|
||||
g_free(opt.dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
154
test/binder-bridge/Makefile
Normal file
154
test/binder-bridge/Makefile
Normal file
@@ -0,0 +1,154 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
.PHONY: all debug release clean cleaner
|
||||
.PHONY: libgbinder-release libgbinder-debug
|
||||
|
||||
#
|
||||
# Required packages
|
||||
#
|
||||
|
||||
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
|
||||
|
||||
#
|
||||
# Default target
|
||||
#
|
||||
|
||||
all: debug release
|
||||
|
||||
#
|
||||
# Executable
|
||||
#
|
||||
|
||||
EXE = binder-bridge
|
||||
|
||||
#
|
||||
# Sources
|
||||
#
|
||||
|
||||
SRC = $(EXE).c
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
SRC_DIR = .
|
||||
BUILD_DIR = build
|
||||
LIB_DIR = ../..
|
||||
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
|
||||
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
|
||||
|
||||
#
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
LD = $(CC)
|
||||
WARNINGS = -Wall
|
||||
INCLUDES = -I$(LIB_DIR)/include
|
||||
BASE_FLAGS = -fPIC
|
||||
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
|
||||
$(shell pkg-config --cflags $(PKGS))
|
||||
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
|
||||
QUIET_MAKE = make --no-print-directory
|
||||
DEBUG_FLAGS = -g
|
||||
RELEASE_FLAGS =
|
||||
|
||||
ifndef KEEP_SYMBOLS
|
||||
KEEP_SYMBOLS = 0
|
||||
endif
|
||||
|
||||
ifneq ($(KEEP_SYMBOLS),0)
|
||||
RELEASE_FLAGS += -g
|
||||
SUBMAKE_OPTS += KEEP_SYMBOLS=1
|
||||
endif
|
||||
|
||||
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
|
||||
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
|
||||
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
|
||||
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
|
||||
|
||||
#
|
||||
# Files
|
||||
#
|
||||
|
||||
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
|
||||
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
|
||||
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
|
||||
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
|
||||
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
|
||||
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
|
||||
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
|
||||
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
|
||||
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(strip $(DEPS)),)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
|
||||
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
|
||||
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
|
||||
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
|
||||
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
|
||||
|
||||
debug: libgbinder-debug $(DEBUG_EXE)
|
||||
|
||||
release: libgbinder-release $(RELEASE_EXE)
|
||||
|
||||
clean:
|
||||
rm -f *~
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
cleaner: clean
|
||||
@make -C $(LIB_DIR) clean
|
||||
|
||||
$(DEBUG_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(RELEASE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
|
||||
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
|
||||
|
||||
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
|
||||
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
|
||||
ifeq ($(KEEP_SYMBOLS),0)
|
||||
strip $@
|
||||
endif
|
||||
|
||||
libgbinder-debug:
|
||||
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
|
||||
|
||||
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 $@
|
||||
196
test/binder-bridge/binder-bridge.c
Normal file
196
test/binder-bridge/binder-bridge.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 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.h>
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include <glib-unix.h>
|
||||
|
||||
#define RET_OK (0)
|
||||
#define RET_NODEV (1)
|
||||
#define RET_INVARG (2)
|
||||
|
||||
typedef struct app_options {
|
||||
const char* src;
|
||||
const char* dest;
|
||||
char* src_name;
|
||||
const char* dest_name;
|
||||
const char** ifaces;
|
||||
} AppOptions;
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_signal(
|
||||
gpointer loop)
|
||||
{
|
||||
GINFO("Caught signal, shutting down...");
|
||||
g_main_loop_quit(loop);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
app_run(
|
||||
const AppOptions* opt)
|
||||
{
|
||||
int ret = RET_NODEV;
|
||||
GBinderServiceManager* src = gbinder_servicemanager_new(opt->src);
|
||||
|
||||
if (src) {
|
||||
GBinderServiceManager* dest = gbinder_servicemanager_new(opt->dest);
|
||||
|
||||
if (dest) {
|
||||
GMainLoop* loop = g_main_loop_new(NULL, TRUE);
|
||||
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, loop);
|
||||
guint sigint = g_unix_signal_add(SIGINT, app_signal, loop);
|
||||
GBinderBridge* bridge = gbinder_bridge_new2
|
||||
(opt->src_name, opt->dest_name, opt->ifaces, src, dest);
|
||||
|
||||
g_main_loop_run(loop);
|
||||
|
||||
if (sigtrm) g_source_remove(sigtrm);
|
||||
if (sigint) g_source_remove(sigint);
|
||||
g_main_loop_unref(loop);
|
||||
gbinder_bridge_free(bridge);
|
||||
gbinder_servicemanager_unref(dest);
|
||||
ret = RET_OK;
|
||||
} else {
|
||||
GERR("No servicemanager at %s", opt->dest);
|
||||
}
|
||||
gbinder_servicemanager_unref(src);
|
||||
} else {
|
||||
GERR("No servicemanager at %s", opt->src);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_verbose(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_VERBOSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_quiet(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_NONE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_init(
|
||||
AppOptions* opt,
|
||||
int argc,
|
||||
char* argv[])
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
GOptionEntry entries[] = {
|
||||
{ "source", 's', 0, G_OPTION_ARG_STRING, &opt->src_name,
|
||||
"Register a different name on source", "NAME" },
|
||||
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_verbose, "Enable verbose output", NULL },
|
||||
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_quiet, "Be quiet", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
GError* error = NULL;
|
||||
GOptionContext* options = g_option_context_new("SRC DST NAME IFACES...");
|
||||
|
||||
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
|
||||
|
||||
g_option_context_add_main_entries(options, entries, NULL);
|
||||
g_option_context_set_summary(options,
|
||||
"Forwards calls from device SRC to device DST.");
|
||||
|
||||
if (g_option_context_parse(options, &argc, &argv, &error)) {
|
||||
if (argc >= 5) {
|
||||
int i;
|
||||
const int first_iface = 4;
|
||||
|
||||
opt->src = argv[1];
|
||||
opt->dest = argv[2];
|
||||
opt->dest_name = argv[3];
|
||||
opt->ifaces = g_new(const char*, argc - first_iface + 1);
|
||||
for (i = first_iface; i < argc; i++) {
|
||||
opt->ifaces[i - first_iface] = argv[i];
|
||||
}
|
||||
opt->ifaces[i - first_iface] = NULL;
|
||||
ok = TRUE;
|
||||
} else {
|
||||
char* help = g_option_context_get_help(options, TRUE, NULL);
|
||||
|
||||
fprintf(stderr, "%s", help);
|
||||
g_free(help);
|
||||
}
|
||||
} else {
|
||||
GERR("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
g_option_context_free(options);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
AppOptions opt;
|
||||
int ret = RET_INVARG;
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
if (app_init(&opt, argc, argv)) {
|
||||
ret = app_run(&opt);
|
||||
}
|
||||
g_free(opt.src_name);
|
||||
g_free(opt.ifaces);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
178
test/binder-call/Makefile
Normal file
178
test/binder-call/Makefile
Normal file
@@ -0,0 +1,178 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
.PHONY: all debug release install clean cleaner
|
||||
.PHONY: libgbinder-release libgbinder-debug
|
||||
|
||||
#
|
||||
# Required packages
|
||||
#
|
||||
|
||||
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
|
||||
|
||||
#
|
||||
# Default target
|
||||
#
|
||||
|
||||
all: debug release
|
||||
|
||||
#
|
||||
# Executable
|
||||
#
|
||||
|
||||
EXE = binder-call
|
||||
|
||||
#
|
||||
# Sources
|
||||
#
|
||||
|
||||
SRC = $(EXE).c
|
||||
GEN_SRC = \
|
||||
cmdline.tab.c \
|
||||
lex.cmdline.c
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
SRC_DIR = .
|
||||
BUILD_DIR = build
|
||||
GEN_DIR = $(BUILD_DIR)
|
||||
LIB_DIR = ../..
|
||||
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
|
||||
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
|
||||
|
||||
#
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
LD = $(CC)
|
||||
WARNINGS = -Wall
|
||||
INCLUDES = -I$(LIB_DIR)/include -I$(GEN_DIR) -I$(SRC_DIR)
|
||||
BASE_FLAGS = -fPIC
|
||||
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
|
||||
$(shell pkg-config --cflags $(PKGS))
|
||||
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
|
||||
QUIET_MAKE = make --no-print-directory
|
||||
DEBUG_FLAGS = -g
|
||||
RELEASE_FLAGS =
|
||||
|
||||
KEEP_SYMBOLS ?= 0
|
||||
ifneq ($(KEEP_SYMBOLS),0)
|
||||
RELEASE_FLAGS += -g
|
||||
SUBMAKE_OPTS += KEEP_SYMBOLS=1
|
||||
endif
|
||||
|
||||
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
|
||||
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
|
||||
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
|
||||
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
|
||||
|
||||
#
|
||||
# Files
|
||||
#
|
||||
|
||||
DEBUG_OBJS = \
|
||||
$(GEN_SRC:%.c=$(DEBUG_BUILD_DIR)/%.o) \
|
||||
$(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
|
||||
RELEASE_OBJS = \
|
||||
$(GEN_SRC:%.c=$(RELEASE_BUILD_DIR)/%.o) \
|
||||
$(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
|
||||
|
||||
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
|
||||
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
|
||||
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
|
||||
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
|
||||
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
|
||||
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
|
||||
GEN_FILES = $(GEN_SRC:%=$(GEN_DIR)/%)
|
||||
.PRECIOUS: $(GEN_FILES)
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
|
||||
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(strip $(DEPS)),)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(GEN_FILES): | $(GEN_DIR)
|
||||
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
|
||||
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
|
||||
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
|
||||
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
|
||||
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
|
||||
|
||||
debug: libgbinder-debug $(DEBUG_EXE)
|
||||
|
||||
release: libgbinder-release $(RELEASE_EXE)
|
||||
|
||||
clean:
|
||||
rm -f *~
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
cleaner: clean
|
||||
@make -C $(LIB_DIR) clean
|
||||
|
||||
$(DEBUG_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(RELEASE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(GEN_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(GEN_DIR)/%.tab.c : $(SRC_DIR)/%.y
|
||||
bison -pcmdline -bcmdline -d -o $@ $<
|
||||
|
||||
$(GEN_DIR)/lex.%.c : $(SRC_DIR)/%.l
|
||||
flex -o $@ $<
|
||||
|
||||
$(DEBUG_BUILD_DIR)/%.o : $(GEN_DIR)/%.c
|
||||
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(RELEASE_BUILD_DIR)/%.o : $(GEN_DIR)/%.c
|
||||
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
|
||||
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
|
||||
|
||||
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
|
||||
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
|
||||
ifeq ($(KEEP_SYMBOLS),0)
|
||||
strip $@
|
||||
endif
|
||||
|
||||
libgbinder-debug:
|
||||
@$(MAKE) $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
|
||||
|
||||
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 $@
|
||||
814
test/binder-call/binder-call.c
Normal file
814
test/binder-call/binder-call.c
Normal file
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Franz-Josef Haider <franz.haider@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.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <binder-call.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define RET_OK (0)
|
||||
#define RET_NOTFOUND (1)
|
||||
#define RET_INVARG (2)
|
||||
#define RET_ERR (3)
|
||||
|
||||
#define DEFAULT_DEVICE GBINDER_DEFAULT_BINDER
|
||||
|
||||
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
|
||||
#define GBINDER_INTERFACE_TRANSACTION GBINDER_TRANSACTION('N','T','F')
|
||||
|
||||
static const char pname[] = "binder-call";
|
||||
|
||||
struct transaction_and_reply* ast;
|
||||
|
||||
enum transaction_pass {
|
||||
COMPUTE_SIZES = 0,
|
||||
FILL_BUFFERS,
|
||||
BUILD_TRANSACTION
|
||||
};
|
||||
|
||||
enum reply_pass {
|
||||
PRINT_REPLY = 0,
|
||||
COMPUTE_SIZES_REPLY
|
||||
};
|
||||
|
||||
static
|
||||
int
|
||||
go_through_transaction_ast(
|
||||
App* app,
|
||||
GList* node_list,
|
||||
int parent_idx,
|
||||
void* buf,
|
||||
enum transaction_pass cur_pass,
|
||||
int cont_offset)
|
||||
{
|
||||
GList* l;
|
||||
int offset = cont_offset;
|
||||
|
||||
for (l = node_list; l; l = l->next) {
|
||||
struct value_info* v = l->data;
|
||||
|
||||
switch(v->type) {
|
||||
case INT8_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("int8");
|
||||
if (parent_idx == -1) {
|
||||
gbinder_writer_append_int32(&app->writer, *((int*)v->value));
|
||||
} else if (cur_pass == FILL_BUFFERS) {
|
||||
*((unsigned char*)(((char*)buf)+offset)) =
|
||||
*((unsigned char*)v->value);
|
||||
}
|
||||
offset++;
|
||||
break;
|
||||
|
||||
case INT32_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("int32");
|
||||
if (parent_idx == -1) {
|
||||
gbinder_writer_append_int32(&app->writer, *((int*)v->value));
|
||||
} else if (cur_pass == FILL_BUFFERS) {
|
||||
*((int*)(((char*)buf)+offset)) = *((int*)v->value);
|
||||
}
|
||||
offset += sizeof(gint32);
|
||||
break;
|
||||
|
||||
case INT64_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("int64");
|
||||
if (parent_idx == -1) {
|
||||
gbinder_writer_append_int64(&app->writer, *((gint64*)v->value));
|
||||
} else if (cur_pass == FILL_BUFFERS) {
|
||||
*((gint64*)(((char*)buf)+offset)) = *((gint64*)v->value);
|
||||
}
|
||||
offset += sizeof(gint64);
|
||||
break;
|
||||
|
||||
case FLOAT_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("float");
|
||||
if (parent_idx == -1) {
|
||||
gbinder_writer_append_float(&app->writer, *((float*)v->value));
|
||||
} else if (cur_pass == FILL_BUFFERS) {
|
||||
*((float*)(((char*)buf)+offset)) = *((float*)v->value);
|
||||
}
|
||||
offset += sizeof(float);
|
||||
break;
|
||||
case DOUBLE_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("double");
|
||||
if (parent_idx == -1) {
|
||||
gbinder_writer_append_double(&app->writer,*((double*)v->value));
|
||||
} else if (cur_pass == FILL_BUFFERS) {
|
||||
*((double*)(((char*)buf)+offset)) = *((double*)v->value);
|
||||
}
|
||||
offset += sizeof(double);
|
||||
break;
|
||||
|
||||
case STRING8_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("string8");
|
||||
gbinder_writer_append_string8(&app->writer, v->value);
|
||||
/* offset not incremented since it only makes sense for hidl */
|
||||
break;
|
||||
|
||||
case STRING16_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("string16");
|
||||
gbinder_writer_append_string16(&app->writer, v->value);
|
||||
/* offset not incremented since it only makes sense for hidl */
|
||||
break;
|
||||
|
||||
case HSTRING_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("hstring");
|
||||
if (parent_idx == -1) {
|
||||
gbinder_writer_append_hidl_string(&app->writer, v->value);
|
||||
} else {
|
||||
GBinderHidlString* hidl_str = (GBinderHidlString*)
|
||||
(((char*)buf)+offset);
|
||||
|
||||
if (cur_pass == FILL_BUFFERS) {
|
||||
hidl_str->data.str = v->value;
|
||||
hidl_str->len = strlen(v->value);
|
||||
hidl_str->owns_buffer = TRUE;
|
||||
} else if (cur_pass == BUILD_TRANSACTION) {
|
||||
GBinderParent p;
|
||||
|
||||
p.index = parent_idx;
|
||||
p.offset = offset;
|
||||
gbinder_writer_append_buffer_object_with_parent
|
||||
(&app->writer, hidl_str->data.str, hidl_str->len+1, &p);
|
||||
}
|
||||
}
|
||||
offset += sizeof(GBinderHidlString);
|
||||
break;
|
||||
|
||||
case STRUCT_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("struct");
|
||||
if (!app->opt->aidl) {
|
||||
if (parent_idx == -1) {
|
||||
int s = go_through_transaction_ast(app, v->value, 0,
|
||||
NULL, COMPUTE_SIZES, 0);
|
||||
void* new_buf = gbinder_writer_malloc(&app->writer, s);
|
||||
int new_parent_idx;
|
||||
|
||||
go_through_transaction_ast(app, v->value, 0, new_buf,
|
||||
FILL_BUFFERS, 0);
|
||||
new_parent_idx = gbinder_writer_append_buffer_object
|
||||
(&app->writer, new_buf, s);
|
||||
/*
|
||||
* if parent_idx == -1 there is no need to update the
|
||||
* offset, since we are processing the argument list
|
||||
* and are not inside an argument.
|
||||
*/
|
||||
go_through_transaction_ast(app, v->value,
|
||||
new_parent_idx, new_buf, BUILD_TRANSACTION, 0);
|
||||
} else {
|
||||
if (cur_pass == FILL_BUFFERS) {
|
||||
/* fill struct mode */
|
||||
offset += go_through_transaction_ast(app,
|
||||
v->value, 0, ((char*)buf)+offset, cur_pass, 0);
|
||||
} else if (cur_pass == BUILD_TRANSACTION) {
|
||||
int s = go_through_transaction_ast(app,
|
||||
v->value, 0, NULL, COMPUTE_SIZES, 0);
|
||||
|
||||
go_through_transaction_ast(app, v->value, 0,
|
||||
buf, FILL_BUFFERS, offset);
|
||||
go_through_transaction_ast(app, v->value, parent_idx,
|
||||
buf, BUILD_TRANSACTION, offset);
|
||||
offset += s;
|
||||
} else if (cur_pass == COMPUTE_SIZES) {
|
||||
offset += go_through_transaction_ast(app,
|
||||
v->value, 0, NULL, cur_pass, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
go_through_transaction_ast(app, v->value, -1, NULL,
|
||||
cur_pass, 0);
|
||||
}
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("structend");
|
||||
break;
|
||||
|
||||
case VECTOR_TYPE:
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("vector");
|
||||
if (!app->opt->aidl) {
|
||||
if (parent_idx == -1) {
|
||||
GBinderHidlVec* vec;
|
||||
int vs = go_through_transaction_ast(app,
|
||||
v->value, 0, NULL, COMPUTE_SIZES, 0);
|
||||
int es = go_through_transaction_ast(app,
|
||||
g_list_last(v->value), 0, NULL, COMPUTE_SIZES, 0);
|
||||
void* new_buf = gbinder_writer_malloc(&app->writer, vs);
|
||||
int new_parent_idx;
|
||||
GBinderParent vec_parent;
|
||||
|
||||
go_through_transaction_ast(app, v->value, 0, new_buf,
|
||||
FILL_BUFFERS, 0);
|
||||
vec = gbinder_writer_new0(&app->writer, GBinderHidlVec);
|
||||
vec->data.ptr = new_buf;
|
||||
vec->count = vs / es;
|
||||
if (vec->count != g_list_length(v->value)) {
|
||||
GERR("SEMANTIC ERROR VECTOR");
|
||||
abort();
|
||||
}
|
||||
vec_parent.index = gbinder_writer_append_buffer_object
|
||||
(&app->writer, vec, sizeof(*vec));
|
||||
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
|
||||
new_parent_idx =
|
||||
gbinder_writer_append_buffer_object_with_parent
|
||||
(&app->writer, new_buf, vs, &vec_parent);
|
||||
go_through_transaction_ast(app, v->value,
|
||||
new_parent_idx, new_buf, BUILD_TRANSACTION, 0);
|
||||
} else {
|
||||
if (cur_pass == FILL_BUFFERS) {
|
||||
/* fill struct mode */
|
||||
int sl = go_through_transaction_ast(app,
|
||||
v->value, 0, NULL, COMPUTE_SIZES, 0);
|
||||
int es = go_through_transaction_ast(app,
|
||||
g_list_last(v->value), 0, NULL, COMPUTE_SIZES, 0);
|
||||
void* new_buf = gbinder_writer_malloc(&app->writer, sl);
|
||||
GBinderHidlVec* vec = (GBinderHidlVec*)
|
||||
(((char*)buf)+offset);
|
||||
|
||||
vec->data.ptr = new_buf;
|
||||
vec->count = sl / es;
|
||||
} else if (cur_pass == BUILD_TRANSACTION) {
|
||||
int new_parent_idx;
|
||||
int sl = go_through_transaction_ast(app,
|
||||
v->value, 0, NULL, COMPUTE_SIZES, 0);
|
||||
GBinderHidlVec* vec = (GBinderHidlVec*)
|
||||
(((char*)buf)+offset);
|
||||
GBinderParent p;
|
||||
void* new_buf = (void*)vec->data.ptr;
|
||||
|
||||
go_through_transaction_ast(app, v->value, 0,
|
||||
new_buf, FILL_BUFFERS, 0);
|
||||
if (vec->count != g_list_length(v->value)) {
|
||||
GERR("SEMANTIC ERROR VECTOR");
|
||||
abort();
|
||||
}
|
||||
p.index = parent_idx;
|
||||
p.offset = offset;
|
||||
new_parent_idx =
|
||||
gbinder_writer_append_buffer_object_with_parent
|
||||
(&app->writer, new_buf, sl, &p);
|
||||
go_through_transaction_ast(app, v->value,
|
||||
new_parent_idx, new_buf, BUILD_TRANSACTION, 0);
|
||||
}
|
||||
offset += sizeof(GBinderHidlVec);
|
||||
}
|
||||
} else {
|
||||
int vl = g_list_length(v->value);
|
||||
|
||||
gbinder_writer_append_int32(&app->writer, vl);
|
||||
go_through_transaction_ast(app, v->value, -1, NULL,
|
||||
cur_pass, 0);
|
||||
}
|
||||
if (cur_pass == BUILD_TRANSACTION) GDEBUG("vectorend");
|
||||
break;
|
||||
default:
|
||||
GERR("unknown type: %d\n", v->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int
|
||||
go_through_reply_ast(
|
||||
App* app,
|
||||
GList* node_list,
|
||||
struct type_info* tt,
|
||||
const void* buf,
|
||||
enum reply_pass cur_pass)
|
||||
{
|
||||
GList* l;
|
||||
int offset = 0;
|
||||
|
||||
for (l = node_list; l || tt; l = l->next) {
|
||||
struct type_info* t = node_list ? l->data : tt;
|
||||
|
||||
switch(t->type) {
|
||||
case INT8_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("int8");
|
||||
if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
int val;
|
||||
|
||||
if (!buf) {
|
||||
gbinder_reader_read_int32(&app->reader, &val);
|
||||
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
val = *((unsigned char*)(((char*)buf)+offset));
|
||||
}
|
||||
printf("%d:8 ", val);
|
||||
}
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case INT32_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("int32");
|
||||
if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
gint32 val;
|
||||
|
||||
if (!buf) {
|
||||
gbinder_reader_read_int32(&app->reader, &val);
|
||||
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
val = *((gint32*)(((char*)buf)+offset));
|
||||
}
|
||||
printf("%" G_GINT32_FORMAT " ", val);
|
||||
}
|
||||
offset += sizeof(gint32);
|
||||
break;
|
||||
|
||||
case INT64_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("int64");
|
||||
if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
gint64 val;
|
||||
|
||||
if (!buf) {
|
||||
gbinder_reader_read_int64(&app->reader, &val);
|
||||
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
val = *((gint64*)(((char*)buf)+offset));
|
||||
}
|
||||
printf("%" G_GINT64_FORMAT " ", val);
|
||||
}
|
||||
offset += sizeof(gint64);
|
||||
break;
|
||||
|
||||
case FLOAT_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("float");
|
||||
if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
float val;
|
||||
|
||||
if (!buf) {
|
||||
gbinder_reader_read_float(&app->reader, &val);
|
||||
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
val = *((float*)(((char*)buf)+offset));
|
||||
}
|
||||
printf("%f ", val);
|
||||
}
|
||||
offset += sizeof(float);
|
||||
break;
|
||||
|
||||
case DOUBLE_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("double");
|
||||
if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
double val;
|
||||
|
||||
if (!buf) {
|
||||
gbinder_reader_read_double(&app->reader, &val);
|
||||
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
val = *((double*)(((char*)buf)+offset));
|
||||
}
|
||||
printf("%lfL ", val);
|
||||
}
|
||||
offset += sizeof(double);
|
||||
break;
|
||||
|
||||
case STRING8_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("string8");
|
||||
printf("\"%s\" ", gbinder_reader_read_string8(&app->reader));
|
||||
/* offset not incremented since it only makes sense for hidl */
|
||||
break;
|
||||
|
||||
case STRING16_TYPE: {
|
||||
char* val = gbinder_reader_read_string16(&app->reader);
|
||||
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("string16");
|
||||
printf("\"%s\"U ", val);
|
||||
g_free(val);
|
||||
/* offset not incremented since it only makes sense for hidl */
|
||||
break;
|
||||
}
|
||||
case HSTRING_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("hstring");
|
||||
if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
char* val = NULL;
|
||||
|
||||
if (!buf) {
|
||||
val = gbinder_reader_read_hidl_string(&app->reader);
|
||||
} else {
|
||||
GBinderHidlString* hidl_str = (GBinderHidlString*)
|
||||
(((char*)buf)+offset);
|
||||
|
||||
val = strdup(hidl_str->data.str);
|
||||
}
|
||||
printf("\"%s\"H ", val);
|
||||
g_free(val);
|
||||
}
|
||||
offset += sizeof(GBinderHidlString);
|
||||
break;
|
||||
|
||||
case STRUCT_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("struct");
|
||||
if (!app->opt->aidl) {
|
||||
if (cur_pass == COMPUTE_SIZES_REPLY) {
|
||||
offset += go_through_reply_ast(app, t->data, NULL, NULL,
|
||||
COMPUTE_SIZES_REPLY);
|
||||
} else {
|
||||
printf("{ ");
|
||||
if (!buf) {
|
||||
int sl = go_through_reply_ast(app, t->data, NULL, NULL,
|
||||
COMPUTE_SIZES_REPLY);
|
||||
|
||||
offset += go_through_reply_ast(app, t->data, NULL,
|
||||
gbinder_reader_read_hidl_struct1(&app->reader, sl),
|
||||
PRINT_REPLY);
|
||||
} else {
|
||||
offset += go_through_reply_ast(app, t->data, NULL,
|
||||
((char*)buf) + offset, PRINT_REPLY);
|
||||
}
|
||||
printf("} ");
|
||||
}
|
||||
} else {
|
||||
go_through_reply_ast(app, t->data, NULL, NULL, cur_pass);
|
||||
}
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("structend");
|
||||
break;
|
||||
|
||||
case VECTOR_TYPE:
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("vector");
|
||||
if (!app->opt->aidl) {
|
||||
if (cur_pass != COMPUTE_SIZES_REPLY) {
|
||||
if (!buf) {
|
||||
guint i;
|
||||
gsize count, elemsize;
|
||||
const void* new_buf = gbinder_reader_read_hidl_vec
|
||||
(&app->reader, &count, &elemsize);
|
||||
|
||||
printf("[ ");
|
||||
for (i = 0; i < count; i++) {
|
||||
/* TODO: validate elemsize somehow? */
|
||||
go_through_reply_ast(app, NULL, t->data,
|
||||
new_buf + elemsize*i, cur_pass);
|
||||
}
|
||||
printf("] ");
|
||||
} else {
|
||||
guint i;
|
||||
gsize count;
|
||||
GBinderHidlVec* vec = (GBinderHidlVec*)
|
||||
(((char*)buf) + offset);
|
||||
int off;
|
||||
|
||||
count = vec->count;
|
||||
printf("[ ");
|
||||
off = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
off += go_through_reply_ast(app, NULL, t->data,
|
||||
vec->data.ptr + off, cur_pass);
|
||||
}
|
||||
printf("] ");
|
||||
}
|
||||
}
|
||||
offset += sizeof(GBinderHidlVec);
|
||||
} else {
|
||||
guint i;
|
||||
gint32 vl;
|
||||
|
||||
gbinder_reader_read_int32(&app->reader, &vl);
|
||||
printf("[ ");
|
||||
for (i = 0; i < vl; i++) {
|
||||
go_through_reply_ast(app, NULL, t->data, NULL, cur_pass);
|
||||
}
|
||||
printf("] ");
|
||||
}
|
||||
if (cur_pass == PRINT_REPLY) GDEBUG("vectorend");
|
||||
break;
|
||||
|
||||
default:
|
||||
GERR("unknown type: %d\n", t->type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tt) break;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
go_through_ast(
|
||||
App* app,
|
||||
struct transaction_and_reply* ast,
|
||||
gboolean transaction)
|
||||
{
|
||||
if (ast) {
|
||||
if (transaction && ast->tree_transaction) {
|
||||
go_through_transaction_ast(app, ast->tree_transaction, -1, NULL,
|
||||
BUILD_TRANSACTION, 0);
|
||||
} else if (!transaction && ast->tree_reply) {
|
||||
GDEBUG("REPLY:");
|
||||
go_through_reply_ast(app, ast->tree_reply, NULL, NULL, PRINT_REPLY);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
free_ast_transaction_tree(
|
||||
gpointer data)
|
||||
{
|
||||
struct value_info* v = data;
|
||||
|
||||
if (v->type == STRUCT_TYPE || v->type == VECTOR_TYPE) {
|
||||
g_list_free_full(v->value, free_ast_transaction_tree);
|
||||
} else {
|
||||
g_free(v->value);
|
||||
}
|
||||
|
||||
g_free(v);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
free_ast_reply_tree(
|
||||
gpointer data)
|
||||
{
|
||||
struct type_info* t = data;
|
||||
|
||||
if (t->type == VECTOR_TYPE) {
|
||||
free_ast_reply_tree(t->data);
|
||||
} else if (t->type == STRUCT_TYPE) {
|
||||
g_list_free_full(t->data, free_ast_reply_tree);
|
||||
}
|
||||
|
||||
g_free(t);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
free_ast(
|
||||
struct transaction_and_reply* ast)
|
||||
{
|
||||
if (ast) {
|
||||
g_list_free_full(ast->tree_transaction, free_ast_transaction_tree);
|
||||
g_list_free_full(ast->tree_reply, free_ast_reply_tree);
|
||||
g_free(ast);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
app_run(
|
||||
App* app)
|
||||
{
|
||||
const AppOptions* opt = app->opt;
|
||||
char* iface = opt->iface ? g_strdup(opt->iface) : NULL;
|
||||
int status = 0;
|
||||
int rargc = 1;
|
||||
char* service = opt->argv[rargc++];
|
||||
int code = atoi(opt->argv[rargc++]);
|
||||
GBinderClient* client;
|
||||
GBinderLocalRequest* req;
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderRemoteObject* obj;
|
||||
|
||||
if (!code) {
|
||||
GERR("Transaction code must be > GBINDER_FIRST_CALL_TRANSACTION(=1).");
|
||||
return;
|
||||
}
|
||||
|
||||
obj = gbinder_servicemanager_get_service_sync(app->sm,
|
||||
service, &status);
|
||||
if (!obj) {
|
||||
GERR("No such service: %s", service);
|
||||
g_free(iface);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strstr(service, "/") != NULL) {
|
||||
iface = g_strndup(service, strchr(service, '/') - service);
|
||||
} else {
|
||||
GBinderReader reader;
|
||||
|
||||
client = gbinder_client_new(obj, NULL);
|
||||
req = gbinder_client_new_request(client);
|
||||
reply = gbinder_client_transact_sync_reply(client,
|
||||
GBINDER_INTERFACE_TRANSACTION, req, &status);
|
||||
gbinder_remote_reply_init_reader(reply, &reader);
|
||||
iface = gbinder_reader_read_string16(&reader);
|
||||
gbinder_local_request_unref(req);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
gbinder_client_unref(client);
|
||||
}
|
||||
|
||||
if (!iface) {
|
||||
GERR("Failed to get interface");
|
||||
return;
|
||||
}
|
||||
|
||||
GDEBUG("Got iface: %s", iface);
|
||||
|
||||
client = gbinder_client_new(obj, iface);
|
||||
g_free(iface);
|
||||
|
||||
req = gbinder_client_new_request(client);
|
||||
|
||||
app->rargc = rargc;
|
||||
app->code = code;
|
||||
|
||||
cmdline_parse(app);
|
||||
|
||||
gbinder_local_request_init_writer(req, &app->writer);
|
||||
go_through_ast(app, ast, TRUE);
|
||||
|
||||
if (opt->oneway) {
|
||||
gbinder_client_transact_sync_oneway(client, code, req);
|
||||
reply = NULL;
|
||||
} else {
|
||||
reply = gbinder_client_transact_sync_reply(client, code, req, &status);
|
||||
}
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
|
||||
if (!reply) {
|
||||
printf("NO REPLY\n");
|
||||
} else {
|
||||
if (ast && !ast->tree_reply) {
|
||||
guchar b;
|
||||
|
||||
gbinder_remote_reply_init_reader(reply, &app->reader);
|
||||
printf("TRANSACTION BUFFER: 0x");
|
||||
while (gbinder_reader_read_byte(&app->reader, &b)) {
|
||||
printf("%02X", b);
|
||||
}
|
||||
printf("\n");
|
||||
} else {
|
||||
gbinder_remote_reply_init_reader(reply, &app->reader);
|
||||
go_through_ast(app, ast, FALSE);
|
||||
}
|
||||
gbinder_remote_reply_unref(reply);
|
||||
}
|
||||
gbinder_client_unref(client);
|
||||
free_ast(ast);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_verbose(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = (gutil_log_default.level < GLOG_LEVEL_DEBUG) ?
|
||||
GLOG_LEVEL_DEBUG : GLOG_LEVEL_VERBOSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_quiet(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_ERR;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_init(
|
||||
AppOptions* opt,
|
||||
int argc,
|
||||
char* argv[])
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
GOptionEntry entries[] = {
|
||||
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_verbose, "Enable verbose output", NULL },
|
||||
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_quiet, "Be quiet", NULL },
|
||||
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
|
||||
"Binder device [" DEFAULT_DEVICE "]", "DEVICE" },
|
||||
{ "oneway", 'o', 0, G_OPTION_ARG_NONE, &opt->oneway,
|
||||
"Use a oneway transaction", NULL },
|
||||
{ "aidl", 'a', 0, G_OPTION_ARG_NONE, &opt->aidl,
|
||||
"Treat types as aidl types (default: hidl)", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
GError* error = NULL;
|
||||
GOptionContext* options = g_option_context_new("NAME CODE [[VALUE1] [VALUE2] ...] [reply [TYPE1] [TYPE2] ...]");
|
||||
g_option_context_set_description(options,
|
||||
"Performs binder transactions from the command line.\n\n"
|
||||
"NAME is the name of the object to call, registered with servicemanager.\n"
|
||||
"For example \"android.hardware.sensors@1.0::ISensors/default\".\n\n"
|
||||
"CODE is the transaction id (must be >=1).\n\n"
|
||||
"Optional transaction arguments follow the transaction code.\n"
|
||||
"Possible arguments are:\n\n"
|
||||
"\t[0-9]*:8 for an 8-bit integer\n"
|
||||
"\t[0-9]* for a 32-bit integer\n"
|
||||
"\t[0-9]*L for an 64-bit integer\n"
|
||||
"\t[0-9]*.[0-9]* for a 32-bit float\n"
|
||||
"\t[0-9]*.[0-9]*L for a 64-bit double\n"
|
||||
"\t\"[.*]\" for an 8-bit aidl string\n"
|
||||
"\t\"[.*]\"L for an utf16 aidl string\n"
|
||||
"\t\"[.*]\"h for an 8-bit hidl string\n"
|
||||
"\t{ VALUE1 VALUE2 ... VALUEN } for a struct containing VALUE1, VALUE2, etc., where\n"
|
||||
"\t all of these values can be any of the possible values described here.\n"
|
||||
"\t[ VALUE1 VALUE2 ... VALUEN ] for a vector of length N containing VALUE1, VALUE2, etc., where\n"
|
||||
"\t all of these values can be one of the possible VALUES described here.\n"
|
||||
"\t They must be of the same type.\n\n"
|
||||
"The structure of the reply follows the \"reply\" keyword.\n"
|
||||
"The following types are accepted:\n\n"
|
||||
"\ti8 for an 8-bit integer\n"
|
||||
"\ti32 for a 32-bit integer\n"
|
||||
"\ti64 for a 64-bit integer\n"
|
||||
"\ts8 for an 8-bit aidl string\n"
|
||||
"\ts16 for an utf16 aidl string\n"
|
||||
"\thstr for an 8-bit hidl string\n"
|
||||
"\tf|float for a 32-bit float\n"
|
||||
"\td|double for a 64-bit double\n"
|
||||
"\t[ TYPE ] for a vector<TYPE> where TYPE can be any of the possible types decribed here\n"
|
||||
"\t{ TYPE1 TYPE2 ... TYPEN } for a struct containing TYPE1, TYPE2, etc. where\n"
|
||||
"\t all of the types can be any of the possible types decribed here.\n\n"
|
||||
"The following example calls getSensorsList method on \"android.hardware.sensors@1.0::ISensors/default\"\n"
|
||||
"service:\n\n"
|
||||
"\tbinder-call -d /dev/hwbinder android.hardware.sensors@1.0::ISensors/default 1 reply i32 \"[ { i32 i32 hstr hstr i32 i32 hstr f f f i32 i32 i32 hstr i32 i32 } ]\"\n");
|
||||
|
||||
g_option_context_add_main_entries(options, entries, NULL);
|
||||
|
||||
memset(opt, 0, sizeof(*opt));
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_set_type(GLOG_TYPE_STDERR, pname);
|
||||
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
|
||||
|
||||
if (g_option_context_parse(options, &argc, &argv, &error)) {
|
||||
char* help;
|
||||
|
||||
if (argc > 2) {
|
||||
opt->argc = argc;
|
||||
opt->argv = argv;
|
||||
ok = TRUE;
|
||||
} else {
|
||||
help = g_option_context_get_help(options, TRUE, NULL);
|
||||
fprintf(stderr, "%s", help);
|
||||
g_free(help);
|
||||
}
|
||||
} else {
|
||||
GERR("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
g_option_context_free(options);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
App app;
|
||||
AppOptions opt;
|
||||
|
||||
memset(&app, 0, sizeof(app));
|
||||
app.ret = RET_INVARG;
|
||||
app.opt = &opt;
|
||||
if (app_init(&opt, argc, argv)) {
|
||||
app.sm = gbinder_servicemanager_new(opt.dev);
|
||||
if (app.sm) {
|
||||
app_run(&app);
|
||||
gbinder_servicemanager_unref(app.sm);
|
||||
} else {
|
||||
GERR("servicemanager seems to be missing");
|
||||
}
|
||||
}
|
||||
g_free(opt.iface);
|
||||
g_free(opt.dev);
|
||||
return app.ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
97
test/binder-call/binder-call.h
Normal file
97
test/binder-call/binder-call.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BINDER_CALL_H__
|
||||
#define BINDER_CALL_H__
|
||||
|
||||
#include <gbinder.h>
|
||||
|
||||
typedef struct app_options {
|
||||
char* dev;
|
||||
char* iface;
|
||||
gboolean oneway;
|
||||
gboolean aidl;
|
||||
gint transaction;
|
||||
int argc;
|
||||
char** argv;
|
||||
} AppOptions;
|
||||
|
||||
typedef struct app {
|
||||
const AppOptions* opt;
|
||||
GMainLoop* loop;
|
||||
GBinderServiceManager* sm;
|
||||
GBinderWriter writer;
|
||||
GBinderReader reader;
|
||||
int code;
|
||||
int rargc;
|
||||
int ret;
|
||||
} App;
|
||||
|
||||
enum TYPE_INFO {
|
||||
INT8_TYPE = 0,
|
||||
INT32_TYPE,
|
||||
INT64_TYPE,
|
||||
FLOAT_TYPE,
|
||||
DOUBLE_TYPE,
|
||||
STRING8_TYPE,
|
||||
STRING16_TYPE,
|
||||
HSTRING_TYPE,
|
||||
STRUCT_TYPE,
|
||||
VECTOR_TYPE
|
||||
};
|
||||
|
||||
struct type_info {
|
||||
enum TYPE_INFO type;
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct value_info {
|
||||
enum TYPE_INFO type;
|
||||
void* value;
|
||||
};
|
||||
|
||||
struct transaction_and_reply {
|
||||
GList* tree_transaction;
|
||||
GList* tree_reply;
|
||||
};
|
||||
|
||||
int
|
||||
cmdline_parse(
|
||||
App* app);
|
||||
|
||||
int
|
||||
cmdlinelex(
|
||||
void* args);
|
||||
|
||||
extern struct transaction_and_reply* ast;
|
||||
|
||||
#endif
|
||||
|
||||
98
test/binder-call/cmdline.l
Normal file
98
test/binder-call/cmdline.l
Normal file
@@ -0,0 +1,98 @@
|
||||
D [0-9]
|
||||
l "l"
|
||||
L "L"
|
||||
u "u"
|
||||
U "U"
|
||||
h "h"
|
||||
H "H"
|
||||
COLON ":"
|
||||
EIGHT "8"
|
||||
|
||||
INT8_SUFFIX {COLON}{EIGHT}
|
||||
INT64_SUFFIX [lL]
|
||||
UTF16_SUFFIX [uU]
|
||||
HSTRING_SUFFIX [hH]
|
||||
|
||||
%{
|
||||
#include <glib.h>
|
||||
#include "cmdline.tab.h"
|
||||
#include "binder-call.h"
|
||||
|
||||
#define YY_SKIP_YYWRAP
|
||||
int cmdlinewrap(App* app);
|
||||
#undef yywrap
|
||||
#define yywrap() cmdlinewrap( (App*) args )
|
||||
#define YY_DECL int cmdlinelex( void* args )
|
||||
|
||||
char* handle_str(char* text) {
|
||||
// extract str from "str"X
|
||||
char* str = g_strndup(text + 1, strlen(text) - 3);
|
||||
return str;
|
||||
}
|
||||
|
||||
char* handle_str8(char* text) {
|
||||
// extract str from "str"
|
||||
char* str = g_strndup(text + 1, strlen(text) - 2);
|
||||
return str;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%option never-interactive noinput nounput
|
||||
|
||||
%%
|
||||
"i8" { return(INT8); }
|
||||
"i32" { return(INT32); }
|
||||
"i64" { return(INT64); }
|
||||
"s8" { return(STRING8); }
|
||||
"s16" { return(STRING16); }
|
||||
"float" { return(FLOAT); }
|
||||
"double" { return(DOUBLE); }
|
||||
"f" { return(FLOAT); }
|
||||
"d" { return(DOUBLE); }
|
||||
"hstr" { return(HSTRING); }
|
||||
"{" { return('{'); }
|
||||
"}" { return('}'); }
|
||||
"[" { return('['); }
|
||||
"]" { return(']'); }
|
||||
{D}*{INT8_SUFFIX} { cmdlinelval.int8_value = atoi(yytext); return(INT8_VALUE); }
|
||||
{D}*{INT64_SUFFIX} { cmdlinelval.int64_value = atol(yytext); return(INT64_VALUE); }
|
||||
{D}* { cmdlinelval.int32_value = atoi(yytext); return(INT32_VALUE); }
|
||||
{D}+"."{D}*{INT64_SUFFIX} { cmdlinelval.double_value = atof(yytext); return(DOUBLE_VALUE); }
|
||||
{D}+"."{D}* { cmdlinelval.float_value = atof(yytext); return(FLOAT_VALUE); }
|
||||
"reply" { return(REPLY); }
|
||||
\".*\"{HSTRING_SUFFIX} { cmdlinelval.hstring_value = handle_str(yytext); return(HSTRING_VALUE); }
|
||||
\".*\"{UTF16_SUFFIX} { cmdlinelval.string16_value = handle_str(yytext); return(STRING16_VALUE); }
|
||||
\".*\" { cmdlinelval.string8_value = handle_str8(yytext); return(STRING8_VALUE); }
|
||||
" " { /* eat */ }
|
||||
. { fprintf(stderr, "Unrecognized character: '%c'\n", yytext[0]); }
|
||||
|
||||
%%
|
||||
|
||||
#include "binder-call.h"
|
||||
|
||||
int cmdlinewrap(App* app)
|
||||
{
|
||||
if (YY_CURRENT_BUFFER) {
|
||||
yy_delete_buffer( YY_CURRENT_BUFFER );
|
||||
}
|
||||
|
||||
if (app->rargc == app->opt->argc) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
yy_scan_string(app->opt->argv[app->rargc++]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmdline_parse(App* app) {
|
||||
if (app->opt->argc > app->rargc) {
|
||||
cmdlinewrap(app);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return cmdlineparse (app);
|
||||
}
|
||||
|
||||
399
test/binder-call/cmdline.y
Normal file
399
test/binder-call/cmdline.y
Normal file
@@ -0,0 +1,399 @@
|
||||
%{
|
||||
#include <glib.h>
|
||||
#include "binder-call.h"
|
||||
|
||||
struct transaction_and_reply* make_transaction_and_reply(GList* transaction, GList* reply);
|
||||
struct value_info* handle_int8(App* app, int value);
|
||||
struct value_info* handle_int32(App* app, int value);
|
||||
struct value_info* handle_int64(App* app, long value);
|
||||
struct value_info* handle_float(App* app, float value);
|
||||
struct value_info* handle_double(App* app, double value);
|
||||
struct value_info* handle_string8(App* app, char* value);
|
||||
struct value_info* handle_string16(App* app, char* value);
|
||||
struct value_info* handle_hstring(App* app, char* value);
|
||||
struct value_info* handle_vector(App* app, GList* values);
|
||||
struct value_info* handle_struct(App* app, GList* values);
|
||||
|
||||
void cmdlineerror(App* app, char const* s);
|
||||
|
||||
struct type_info* handle_type_int8(App* app);
|
||||
struct type_info* handle_type_int32(App* app);
|
||||
struct type_info* handle_type_int64(App* app);
|
||||
struct type_info* handle_type_float(App* app);
|
||||
struct type_info* handle_type_double(App* app);
|
||||
struct type_info* handle_type_string8(App* app);
|
||||
struct type_info* handle_type_string16(App* app);
|
||||
struct type_info* handle_type_hstring(App* app);
|
||||
|
||||
|
||||
struct type_info* handle_type_vector(App* app, struct type_info* t);
|
||||
struct type_info* handle_type_struct(App* app, GList* l);
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
union {
|
||||
int int8_value;
|
||||
int int32_value;
|
||||
long int64_value;
|
||||
float float_value;
|
||||
double double_value;
|
||||
char* string8_value;
|
||||
char* string16_value;
|
||||
char* hstring_value;
|
||||
};
|
||||
struct value_info* value;
|
||||
struct type_info* type;
|
||||
GList* value_list;
|
||||
GList* type_list;
|
||||
GList* struct_type_list;
|
||||
struct transaction_and_reply* trans_and_reply;
|
||||
}
|
||||
|
||||
%parse-param { void* args }
|
||||
%lex-param { void* args }
|
||||
|
||||
%token INT8 INT32 INT64 FLOAT DOUBLE STRING8 STRING16 HSTRING
|
||||
|
||||
%token INT8_VALUE INT32_VALUE INT64_VALUE FLOAT_VALUE DOUBLE_VALUE STRING8_VALUE STRING16_VALUE HSTRING_VALUE
|
||||
%type <value> values
|
||||
|
||||
%type <value> struct_values
|
||||
%type <value> vec_values
|
||||
%type <value> value_specifiers
|
||||
%type <trans_and_reply> translation_unit
|
||||
|
||||
%type <value_list> values_list
|
||||
%type <type_list> specifiers_list
|
||||
|
||||
%type <type> specifiers
|
||||
%type <type> type_specifier
|
||||
%type <type> vec_specifier
|
||||
%type <type> struct_specifier
|
||||
%type <struct_type_list> struct_declaration_list
|
||||
|
||||
%token REPLY
|
||||
|
||||
%start translation_unit
|
||||
%%
|
||||
|
||||
type_specifier
|
||||
: INT8 { $$ = handle_type_int8(args); }
|
||||
| INT32 { $$ = handle_type_int32(args); }
|
||||
| INT64 { $$ = handle_type_int64(args); }
|
||||
| STRING8 { $$ = handle_type_string8(args); }
|
||||
| STRING16 { $$ = handle_type_string16(args); }
|
||||
| FLOAT { $$ = handle_type_float(args); }
|
||||
| DOUBLE { $$ = handle_type_double(args); }
|
||||
| HSTRING { $$ = handle_type_hstring(args); }
|
||||
;
|
||||
|
||||
values
|
||||
: INT8_VALUE { $$ = handle_int8(args, cmdlinelval.int8_value); }
|
||||
| INT32_VALUE { $$ = handle_int32(args, cmdlinelval.int32_value); }
|
||||
| INT64_VALUE { $$ = handle_int64(args, cmdlinelval.int64_value); }
|
||||
| STRING8_VALUE { $$ = handle_string8(args, cmdlinelval.string8_value); }
|
||||
| STRING16_VALUE { $$ = handle_string16(args, cmdlinelval.string16_value); }
|
||||
| HSTRING_VALUE { $$ = handle_hstring(args, cmdlinelval.hstring_value); }
|
||||
| FLOAT_VALUE { $$ = handle_float(args, cmdlinelval.float_value); }
|
||||
| DOUBLE_VALUE { $$ = handle_double(args, cmdlinelval.double_value); }
|
||||
;
|
||||
|
||||
struct
|
||||
: '{'
|
||||
;
|
||||
|
||||
struct_end
|
||||
: '}'
|
||||
;
|
||||
|
||||
vec
|
||||
: '['
|
||||
;
|
||||
|
||||
vec_end
|
||||
: ']'
|
||||
;
|
||||
|
||||
struct_specifier
|
||||
: struct struct_declaration_list struct_end { $$ = handle_type_struct(args, $2); }
|
||||
;
|
||||
|
||||
vec_specifier
|
||||
: vec specifiers vec_end { $$ = handle_type_vector(args, $2); }
|
||||
;
|
||||
|
||||
struct_declaration_list
|
||||
: specifiers { $$ = NULL; $$ = g_list_append($$, $1); }
|
||||
| struct_declaration_list specifiers { $$ = g_list_append($$, $2); }
|
||||
;
|
||||
|
||||
specifiers
|
||||
: type_specifier
|
||||
| struct_specifier
|
||||
| vec_specifier
|
||||
;
|
||||
|
||||
specifiers_list
|
||||
: specifiers { $$ = NULL; $$ = g_list_append($$, $1); }
|
||||
| specifiers_list specifiers { $$ = g_list_append($$, $2); }
|
||||
;
|
||||
|
||||
struct_values
|
||||
: struct values_list struct_end { $$ = handle_struct(args, $2); }
|
||||
;
|
||||
|
||||
vec_values
|
||||
: vec values_list vec_end { $$ = handle_vector(args, $2); }
|
||||
;
|
||||
|
||||
value_specifiers
|
||||
: values
|
||||
| struct_values
|
||||
| vec_values
|
||||
;
|
||||
|
||||
values_list
|
||||
: value_specifiers { $$ = NULL; $$ = g_list_append($$, $1); }
|
||||
| values_list value_specifiers { $$ = g_list_append($$, $2); }
|
||||
;
|
||||
|
||||
reply
|
||||
: REPLY
|
||||
;
|
||||
|
||||
translation_unit
|
||||
: values_list reply specifiers_list { $$ = make_transaction_and_reply($1, $3); ast = $$; }
|
||||
| values_list { $$ = make_transaction_and_reply($1, 0); ast = $$; }
|
||||
| reply specifiers_list { $$ = make_transaction_and_reply(0, $2); ast = $$; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
#include <gutil_log.h>
|
||||
#include <binder-call.h>
|
||||
|
||||
extern char yytext[];
|
||||
|
||||
struct value_info* handle_int8(App* app, int value)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = INT8_TYPE;
|
||||
v->value = g_new0(unsigned char, 1);
|
||||
* ((unsigned char*)v->value) = value;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_int32(App* app, int value)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = INT32_TYPE;
|
||||
v->value = g_new0(int, 1);
|
||||
* ((int*)v->value) = value;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_int64(App* app, long value)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = INT64_TYPE;
|
||||
v->value = g_new0(long, 1);
|
||||
* ((long*)v->value) = value;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_float(App* app, float value)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = FLOAT_TYPE;
|
||||
v->value = g_new0(float, 1);
|
||||
* ((float*)v->value) = value;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_double(App* app, double value)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = DOUBLE_TYPE;
|
||||
v->value = g_new0(double, 1);
|
||||
* ((double*)v->value) = value;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_string8(App* app, char* value)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = STRING8_TYPE;
|
||||
v->value = value;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_string16(App* app, char* value)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = STRING16_TYPE;
|
||||
v->value = value;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_hstring(App* app, char* value)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = HSTRING_TYPE;
|
||||
v->value = value;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_vector(App* app, GList* values)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = VECTOR_TYPE;
|
||||
v->value = values;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct value_info* handle_struct(App* app, GList* values)
|
||||
{
|
||||
struct value_info* v = g_new0(struct value_info, 1);
|
||||
|
||||
v->type = STRUCT_TYPE;
|
||||
v->value = values;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_int8(App* app)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = INT8_TYPE;
|
||||
info->data = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_int32(App* app)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = INT32_TYPE;
|
||||
info->data = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_int64(App* app)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = INT64_TYPE;
|
||||
info->data = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_float(App* app)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = FLOAT_TYPE;
|
||||
info->data = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_double(App* app)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = DOUBLE_TYPE;
|
||||
info->data = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_string8(App* app)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = STRING8_TYPE;
|
||||
info->data = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_string16(App* app)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = STRING16_TYPE;
|
||||
info->data = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_hstring(App* app)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = HSTRING_TYPE;
|
||||
info->data = 0;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_vector(App* app, struct type_info* t)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = VECTOR_TYPE;
|
||||
info->data = t;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct type_info* handle_type_struct(App* app, GList* l)
|
||||
{
|
||||
struct type_info* info = g_new0(struct type_info, 1);
|
||||
|
||||
info->type = STRUCT_TYPE;
|
||||
info->data = l;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct transaction_and_reply* make_transaction_and_reply(GList* transaction, GList* reply)
|
||||
{
|
||||
struct transaction_and_reply* tar = g_new0(struct transaction_and_reply, 1);
|
||||
|
||||
tar->tree_transaction = transaction;
|
||||
tar->tree_reply = reply;
|
||||
|
||||
return tar;
|
||||
}
|
||||
|
||||
void cmdlineerror(App* app, char const* s)
|
||||
{
|
||||
fprintf(stderr, "@%d %s: %s\n", app->rargc - 1, s, app->opt->argv[app->rargc - 1]);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ RELEASE_BUILD_DIR = $(BUILD_DIR)/release
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
LD = $(CC)
|
||||
WARNINGS = -Wall
|
||||
INCLUDES = -I$(LIB_DIR)/include
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
||||
* Copyright (C) 2018 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
|
||||
@@ -54,10 +54,15 @@ typedef struct app_options {
|
||||
|
||||
typedef struct app {
|
||||
const AppOptions* opt;
|
||||
char* fqname;
|
||||
GMainLoop* loop;
|
||||
GBinderServiceManager* sm;
|
||||
GBinderLocalObject* local;
|
||||
GBinderRemoteObject* remote;
|
||||
gulong wait_id;
|
||||
gulong death_id;
|
||||
GBinderClient* client;
|
||||
GThread* thread;
|
||||
int ret;
|
||||
} App;
|
||||
|
||||
@@ -171,46 +176,80 @@ app_input_thread(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_connect_remote(
|
||||
App* app)
|
||||
{
|
||||
app->remote = gbinder_servicemanager_get_service_sync(app->sm,
|
||||
app->fqname, NULL); /* autoreleased pointer */
|
||||
|
||||
if (app->remote) {
|
||||
const AppOptions* opt = app->opt;
|
||||
|
||||
GINFO("Connected to %s", app->fqname);
|
||||
gbinder_remote_object_ref(app->remote);
|
||||
app->client = gbinder_client_new(app->remote, opt->iface);
|
||||
app->death_id = gbinder_remote_object_add_death_handler(app->remote,
|
||||
app_remote_died, app);
|
||||
app->thread = g_thread_new("input", app_input_thread, app);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
app_registration_handler(
|
||||
GBinderServiceManager* sm,
|
||||
const char* name,
|
||||
void* user_data)
|
||||
{
|
||||
App* app = user_data;
|
||||
|
||||
GDEBUG("\"%s\" appeared", name);
|
||||
if (!strcmp(name, app->fqname) && app_connect_remote(app)) {
|
||||
gbinder_servicemanager_remove_handler(app->sm, app->wait_id);
|
||||
app->wait_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
app_run(
|
||||
App* app)
|
||||
{
|
||||
const AppOptions* opt = app->opt;
|
||||
char* fqname = opt->fqname ? g_strdup(opt->fqname) :
|
||||
strchr(opt->name, '/') ? g_strdup(opt->name) :
|
||||
g_strconcat(opt->iface, "/", opt->name, NULL);
|
||||
int status = 0;
|
||||
GBinderRemoteObject* remote = gbinder_remote_object_ref
|
||||
(gbinder_servicemanager_get_service_sync(app->sm, fqname, &status));
|
||||
if (remote) {
|
||||
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
|
||||
guint sigint = g_unix_signal_add(SIGINT, app_signal, app);
|
||||
gulong death_id = gbinder_remote_object_add_death_handler
|
||||
(remote, app_remote_died, app);
|
||||
GThread* thread = g_thread_new("input", app_input_thread, app);
|
||||
|
||||
GINFO("Connected to %s\n", fqname);
|
||||
app->fqname = opt->fqname ? g_strdup(opt->fqname) :
|
||||
strchr(opt->name, '/') ? g_strdup(opt->name) :
|
||||
g_strconcat(opt->iface, "/", opt->name, NULL);
|
||||
|
||||
if (!app_connect_remote(app)) {
|
||||
GINFO("Waiting for %s", app->fqname);
|
||||
app->wait_id = gbinder_servicemanager_add_registration_handler(app->sm,
|
||||
app->fqname, app_registration_handler, app);
|
||||
}
|
||||
|
||||
app->client = gbinder_client_new(remote, opt->iface);
|
||||
app->ret = RET_OK;
|
||||
app->loop = g_main_loop_new(NULL, TRUE);
|
||||
app->ret = RET_OK;
|
||||
g_main_loop_run(app->loop);
|
||||
|
||||
g_source_remove(sigtrm);
|
||||
g_source_remove(sigint);
|
||||
g_main_loop_unref(app->loop);
|
||||
|
||||
gbinder_remote_object_remove_handler(remote, death_id);
|
||||
gbinder_remote_object_unref(remote);
|
||||
|
||||
/* Not the cleanest exit, just dropping the thread... */
|
||||
g_thread_unref(thread);
|
||||
app->loop = NULL;
|
||||
} else {
|
||||
GERR("No such service: %s (%d)", fqname, status);
|
||||
if (app->thread) {
|
||||
/* Not the cleanest of exits, just dropping the thread... */
|
||||
g_thread_unref(app->thread);
|
||||
}
|
||||
g_free(fqname);
|
||||
gbinder_remote_object_remove_handler(app->remote, app->death_id);
|
||||
gbinder_remote_object_unref(app->remote);
|
||||
gbinder_local_object_drop(app->local);
|
||||
gbinder_client_unref(app->client);
|
||||
g_free(app->fqname);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -311,8 +350,6 @@ int main(int argc, char* argv[])
|
||||
app.local = gbinder_servicemanager_new_local_object(app.sm,
|
||||
NULL, NULL, NULL);
|
||||
app_run(&app);
|
||||
gbinder_local_object_unref(app.local);
|
||||
gbinder_client_unref(app.client);
|
||||
gbinder_servicemanager_unref(app.sm);
|
||||
}
|
||||
}
|
||||
|
||||
140
test/binder-dump/Makefile
Normal file
140
test/binder-dump/Makefile
Normal file
@@ -0,0 +1,140 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
.PHONY: all debug release clean cleaner
|
||||
.PHONY: libgbinder-release libgbinder-debug
|
||||
|
||||
#
|
||||
# Required packages
|
||||
#
|
||||
|
||||
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
|
||||
|
||||
#
|
||||
# Default target
|
||||
#
|
||||
|
||||
all: debug release
|
||||
|
||||
#
|
||||
# Executable
|
||||
#
|
||||
|
||||
EXE = binder-dump
|
||||
|
||||
#
|
||||
# Sources
|
||||
#
|
||||
|
||||
SRC = $(EXE).c
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
SRC_DIR = .
|
||||
BUILD_DIR = build
|
||||
LIB_DIR = ../..
|
||||
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
|
||||
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
|
||||
|
||||
#
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
LD = $(CC)
|
||||
WARNINGS = -Wall
|
||||
INCLUDES = -I$(LIB_DIR)/include
|
||||
BASE_FLAGS = -fPIC
|
||||
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
|
||||
$(shell pkg-config --cflags $(PKGS))
|
||||
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
|
||||
QUIET_MAKE = make --no-print-directory
|
||||
DEBUG_FLAGS = -g
|
||||
RELEASE_FLAGS =
|
||||
|
||||
ifndef KEEP_SYMBOLS
|
||||
KEEP_SYMBOLS = 0
|
||||
endif
|
||||
|
||||
ifneq ($(KEEP_SYMBOLS),0)
|
||||
RELEASE_FLAGS += -g
|
||||
SUBMAKE_OPTS += KEEP_SYMBOLS=1
|
||||
endif
|
||||
|
||||
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
|
||||
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
|
||||
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
|
||||
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
|
||||
|
||||
#
|
||||
# Files
|
||||
#
|
||||
|
||||
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
|
||||
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
|
||||
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
|
||||
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
|
||||
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
|
||||
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
|
||||
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
|
||||
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
|
||||
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(strip $(DEPS)),)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
|
||||
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
|
||||
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
|
||||
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
|
||||
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
|
||||
|
||||
debug: libgbinder-debug $(DEBUG_EXE)
|
||||
|
||||
release: libgbinder-release $(RELEASE_EXE)
|
||||
|
||||
clean:
|
||||
rm -f *~
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
cleaner: clean
|
||||
@make -C $(LIB_DIR) clean
|
||||
|
||||
$(DEBUG_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(RELEASE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
|
||||
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
|
||||
|
||||
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
|
||||
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
|
||||
ifeq ($(KEEP_SYMBOLS),0)
|
||||
strip $@
|
||||
endif
|
||||
|
||||
libgbinder-debug:
|
||||
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
|
||||
|
||||
libgbinder-release:
|
||||
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
|
||||
237
test/binder-dump/binder-dump.c
Normal file
237
test/binder-dump/binder-dump.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018 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.h>
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define RET_OK (0)
|
||||
#define RET_NOTFOUND (1)
|
||||
#define RET_INVARG (2)
|
||||
#define RET_ERR (3)
|
||||
|
||||
#define DEV_DEFAULT GBINDER_DEFAULT_BINDER
|
||||
|
||||
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
|
||||
#define GBINDER_DUMP_TRANSACTION GBINDER_TRANSACTION('D','M','P')
|
||||
|
||||
typedef struct app_options {
|
||||
char* dev;
|
||||
const char* service;
|
||||
} AppOptions;
|
||||
|
||||
typedef struct app {
|
||||
const AppOptions* opt;
|
||||
GMainLoop* loop;
|
||||
GBinderServiceManager* sm;
|
||||
int ret;
|
||||
} App;
|
||||
|
||||
static const char pname[] = "binder-dump";
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_dump_service(
|
||||
App* app,
|
||||
const char* service)
|
||||
{
|
||||
int status = 0;
|
||||
GBinderRemoteObject* obj = gbinder_servicemanager_get_service_sync(app->sm,
|
||||
service, &status);
|
||||
|
||||
if (obj) {
|
||||
GBinderClient* client = gbinder_client_new(obj, NULL);
|
||||
GBinderLocalRequest* req = gbinder_client_new_request(client);
|
||||
GBinderRemoteReply* reply;
|
||||
GBinderWriter writer;
|
||||
|
||||
gbinder_remote_object_ref(obj);
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
gbinder_writer_append_fd(&writer, STDOUT_FILENO);
|
||||
gbinder_writer_append_int32(&writer, 0);
|
||||
reply = gbinder_client_transact_sync_reply(client,
|
||||
GBINDER_DUMP_TRANSACTION, req, &status);
|
||||
if (status < 0) {
|
||||
GERR("Error %d", status);
|
||||
}
|
||||
gbinder_remote_object_unref(obj);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
gbinder_local_request_unref(req);
|
||||
gbinder_client_unref(client);
|
||||
return TRUE;
|
||||
} else {
|
||||
GERR("No such service: %s (%d)", service, status);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
app_dump_services(
|
||||
App* app,
|
||||
char** strv)
|
||||
{
|
||||
if (strv) {
|
||||
while (*strv) {
|
||||
const char* name = *strv++;
|
||||
|
||||
printf("========= %s\n", name);
|
||||
app_dump_service(app, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
app_run(
|
||||
App* app)
|
||||
{
|
||||
const AppOptions* opt = app->opt;
|
||||
|
||||
if (opt->service) {
|
||||
app->ret = app_dump_service(app, opt->service) ? RET_OK : RET_NOTFOUND;
|
||||
} else {
|
||||
char** services = gbinder_servicemanager_list_sync(app->sm);
|
||||
|
||||
if (services) {
|
||||
app_dump_services(app, services);
|
||||
g_strfreev(services);
|
||||
app->ret = RET_OK;
|
||||
} else {
|
||||
app->ret = RET_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_verbose(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_VERBOSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_log_quiet(
|
||||
const gchar* name,
|
||||
const gchar* value,
|
||||
gpointer data,
|
||||
GError** error)
|
||||
{
|
||||
gutil_log_default.level = GLOG_LEVEL_ERR;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
app_init(
|
||||
AppOptions* opt,
|
||||
int argc,
|
||||
char* argv[])
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
GOptionEntry entries[] = {
|
||||
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_verbose, "Enable verbose output", NULL },
|
||||
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||
app_log_quiet, "Be quiet", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
GError* error = NULL;
|
||||
GOptionContext* options = g_option_context_new("[SERVICE]");
|
||||
|
||||
memset(opt, 0, sizeof(*opt));
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_set_type(GLOG_TYPE_STDERR, pname);
|
||||
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
|
||||
|
||||
g_option_context_add_main_entries(options, entries, NULL);
|
||||
if (g_option_context_parse(options, &argc, &argv, &error)) {
|
||||
char* help;
|
||||
|
||||
opt->dev = g_strdup(DEV_DEFAULT);
|
||||
switch (argc) {
|
||||
case 2:
|
||||
opt->service = argv[1];
|
||||
/* no break */
|
||||
case 1:
|
||||
ok = TRUE;
|
||||
break;
|
||||
default:
|
||||
help = g_option_context_get_help(options, TRUE, NULL);
|
||||
fprintf(stderr, "%s", help);
|
||||
g_free(help);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GERR("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
g_option_context_free(options);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
App app;
|
||||
AppOptions opt;
|
||||
|
||||
memset(&app, 0, sizeof(app));
|
||||
app.ret = RET_INVARG;
|
||||
app.opt = &opt;
|
||||
if (app_init(&opt, argc, argv)) {
|
||||
app.sm = gbinder_servicemanager_new(opt.dev);
|
||||
if (app.sm) {
|
||||
app_run(&app);
|
||||
gbinder_servicemanager_unref(app.sm);
|
||||
}
|
||||
}
|
||||
g_free(opt.dev);
|
||||
return app.ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -41,7 +41,7 @@ RELEASE_BUILD_DIR = $(BUILD_DIR)/release
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
LD = $(CC)
|
||||
WARNINGS = -Wall
|
||||
INCLUDES = -I$(LIB_DIR)/include
|
||||
@@ -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 $@
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user