Compare commits
130 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
306d08112b | ||
|
|
b489becf51 | ||
|
|
8a27829af3 | ||
|
|
d67b73502e | ||
|
|
4ecf3ae24d | ||
|
|
d0542e759d | ||
|
|
ffa44ac5b3 | ||
|
|
6509e5dac8 | ||
|
|
6b956c0d3c | ||
|
|
3b10a08bad |
3
AUTHORS
3
AUTHORS
@@ -1,2 +1,5 @@
|
|||||||
Slava Monich <slava.monich@jolla.com>
|
Slava Monich <slava.monich@jolla.com>
|
||||||
Matti Lehtimäki <matti.lehtimaki@gmail.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>
|
||||||
|
|||||||
10
LICENSE
10
LICENSE
@@ -1,5 +1,5 @@
|
|||||||
Copyright (C) 2018 Jolla Ltd.
|
Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
|
|
||||||
You may use this file under the terms of BSD license as follows:
|
You may use this file under the terms of BSD license as follows:
|
||||||
|
|
||||||
@@ -12,9 +12,9 @@ are met:
|
|||||||
2. Redistributions in binary form must reproduce the above copyright
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
3. Neither the name of Jolla Ltd nor the names of its contributors may
|
3. Neither the names of the copyright holders nor the names of its
|
||||||
be used to endorse or promote products derived from this software
|
contributors may be used to endorse or promote products derived
|
||||||
without specific prior written permission.
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
|||||||
8
Makefile
8
Makefile
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
.PHONY: clean all debug release test
|
.PHONY: clean all debug release test
|
||||||
.PHONY: print_debug_so print_release_so
|
.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_link print_release_link
|
||||||
.PHONY: print_debug_path print_release_path
|
.PHONY: print_debug_path print_release_path
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ all: debug release pkgconfig
|
|||||||
|
|
||||||
VERSION_MAJOR = 1
|
VERSION_MAJOR = 1
|
||||||
VERSION_MINOR = 0
|
VERSION_MINOR = 0
|
||||||
VERSION_RELEASE = 5
|
VERSION_RELEASE = 33
|
||||||
|
|
||||||
# Version for pkg-config
|
# Version for pkg-config
|
||||||
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
|
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
|
||||||
@@ -62,6 +62,8 @@ SRC = \
|
|||||||
gbinder_remote_reply.c \
|
gbinder_remote_reply.c \
|
||||||
gbinder_remote_request.c \
|
gbinder_remote_request.c \
|
||||||
gbinder_rpc_protocol.c \
|
gbinder_rpc_protocol.c \
|
||||||
|
gbinder_servicename.c \
|
||||||
|
gbinder_servicepoll.c \
|
||||||
gbinder_writer.c
|
gbinder_writer.c
|
||||||
|
|
||||||
SRC += \
|
SRC += \
|
||||||
@@ -247,7 +249,7 @@ $(COVERAGE_LIB): $(COVERAGE_OBJS)
|
|||||||
$(AR) rc $@ $?
|
$(AR) rc $@ $?
|
||||||
ranlib $@
|
ranlib $@
|
||||||
|
|
||||||
$(PKGCONFIG): $(LIB_NAME).pc.in
|
$(PKGCONFIG): $(LIB_NAME).pc.in Makefile
|
||||||
sed -e 's/\[version\]/'$(PCVERSION)/g $< > $@
|
sed -e 's/\[version\]/'$(PCVERSION)/g $< > $@
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
6
README
6
README
@@ -1 +1,7 @@
|
|||||||
GLib-style interface to binder (Android IPC mechanism)
|
GLib-style interface to binder (Android IPC mechanism)
|
||||||
|
|
||||||
|
Provides:
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
188
debian/changelog
vendored
188
debian/changelog
vendored
@@ -1,3 +1,191 @@
|
|||||||
|
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()
|
||||||
|
* Added gbinder_remote_reply_copy_to_local()
|
||||||
|
* Make sure RPC protocol matches servicemanager type
|
||||||
|
|
||||||
|
-- Slava Monich <slava.monich@jolla.com> Sun, 23 Sep 2018 22:47:16 +0300
|
||||||
|
|
||||||
|
libgbinder (1.0.6) unstable; urgency=low
|
||||||
|
|
||||||
|
* Fixed GBinderServiceManager lifecycle management
|
||||||
|
|
||||||
|
-- Slava Monich <slava.monich@jolla.com> Fri, 21 Sep 2018 21:15:28 +0300
|
||||||
|
|
||||||
libgbinder (1.0.5) unstable; urgency=low
|
libgbinder (1.0.5) unstable; urgency=low
|
||||||
|
|
||||||
* Added double and float support
|
* Added double and float support
|
||||||
|
|||||||
4
debian/control
vendored
4
debian/control
vendored
@@ -2,13 +2,13 @@ Source: libgbinder
|
|||||||
Section: libs
|
Section: libs
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Slava Monich <slava.monich@jolla.com>
|
Maintainer: Slava Monich <slava.monich@jolla.com>
|
||||||
Build-Depends: debhelper (>= 7), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.29)
|
Build-Depends: debhelper (>= 7), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.35)
|
||||||
Standards-Version: 3.8.4
|
Standards-Version: 3.8.4
|
||||||
|
|
||||||
Package: libgbinder
|
Package: libgbinder
|
||||||
Section: libs
|
Section: libs
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: libglibutil (>= 1.0.29), ${shlibs:Depends}, ${misc:Depends}
|
Depends: libglibutil (>= 1.0.35), ${shlibs:Depends}, ${misc:Depends}
|
||||||
Description: Binder client library
|
Description: Binder client library
|
||||||
|
|
||||||
Package: libgbinder-dev
|
Package: libgbinder-dev
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "gbinder_remote_object.h"
|
#include "gbinder_remote_object.h"
|
||||||
#include "gbinder_remote_reply.h"
|
#include "gbinder_remote_reply.h"
|
||||||
#include "gbinder_remote_request.h"
|
#include "gbinder_remote_request.h"
|
||||||
|
#include "gbinder_servicename.h"
|
||||||
#include "gbinder_servicemanager.h"
|
#include "gbinder_servicemanager.h"
|
||||||
#include "gbinder_writer.h"
|
#include "gbinder_writer.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -58,6 +58,10 @@ void
|
|||||||
gbinder_client_unref(
|
gbinder_client_unref(
|
||||||
GBinderClient* client);
|
GBinderClient* client);
|
||||||
|
|
||||||
|
const char*
|
||||||
|
gbinder_client_interface(
|
||||||
|
GBinderClient* client); /* since 1.0.22 */
|
||||||
|
|
||||||
GBinderLocalRequest*
|
GBinderLocalRequest*
|
||||||
gbinder_client_new_request(
|
gbinder_client_new_request(
|
||||||
GBinderClient* client);
|
GBinderClient* client);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -37,6 +37,14 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS
|
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*
|
GBinderLocalObject*
|
||||||
gbinder_local_object_ref(
|
gbinder_local_object_ref(
|
||||||
GBinderLocalObject* obj);
|
GBinderLocalObject* obj);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -53,7 +53,7 @@ struct gbinder_reader {
|
|||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_reader_at_end(
|
gbinder_reader_at_end(
|
||||||
GBinderReader* reader);
|
const GBinderReader* reader);
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_reader_read_byte(
|
gbinder_reader_read_byte(
|
||||||
@@ -95,6 +95,15 @@ gbinder_reader_read_double(
|
|||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
gdouble* value);
|
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
|
gboolean
|
||||||
gbinder_reader_read_nullable_object(
|
gbinder_reader_read_nullable_object(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
@@ -113,11 +122,43 @@ gbinder_reader_read_buffer(
|
|||||||
GBinderReader* reader)
|
GBinderReader* reader)
|
||||||
G_GNUC_WARN_UNUSED_RESULT;
|
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*
|
char*
|
||||||
gbinder_reader_read_hidl_string(
|
gbinder_reader_read_hidl_string(
|
||||||
GBinderReader* reader)
|
GBinderReader* reader)
|
||||||
G_GNUC_WARN_UNUSED_RESULT;
|
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**
|
char**
|
||||||
gbinder_reader_read_hidl_string_vec(
|
gbinder_reader_read_hidl_string_vec(
|
||||||
GBinderReader* reader);
|
GBinderReader* reader);
|
||||||
@@ -140,17 +181,38 @@ gbinder_reader_read_nullable_string16(
|
|||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
char** out);
|
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
|
gboolean
|
||||||
gbinder_reader_skip_string16(
|
gbinder_reader_skip_string16(
|
||||||
GBinderReader* reader);
|
GBinderReader* reader);
|
||||||
|
|
||||||
|
const void*
|
||||||
|
gbinder_reader_read_byte_array(
|
||||||
|
GBinderReader* reader,
|
||||||
|
gsize* len); /* Since 1.0.12 */
|
||||||
|
|
||||||
gsize
|
gsize
|
||||||
gbinder_reader_bytes_read(
|
gbinder_reader_bytes_read(
|
||||||
GBinderReader* reader);
|
const GBinderReader* reader);
|
||||||
|
|
||||||
gsize
|
gsize
|
||||||
gbinder_reader_bytes_remaining(
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -51,6 +51,10 @@ void
|
|||||||
gbinder_remote_object_unref(
|
gbinder_remote_object_unref(
|
||||||
GBinderRemoteObject* obj);
|
GBinderRemoteObject* obj);
|
||||||
|
|
||||||
|
GBinderIpc*
|
||||||
|
gbinder_remote_object_ipc(
|
||||||
|
GBinderRemoteObject* obj); /* Since 1.0.30 */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_remote_object_is_dead(
|
gbinder_remote_object_is_dead(
|
||||||
GBinderRemoteObject* obj);
|
GBinderRemoteObject* obj);
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -50,6 +50,11 @@ gbinder_remote_reply_init_reader(
|
|||||||
GBinderRemoteReply* reply,
|
GBinderRemoteReply* reply,
|
||||||
GBinderReader* reader);
|
GBinderReader* reader);
|
||||||
|
|
||||||
|
GBinderLocalReply*
|
||||||
|
gbinder_remote_reply_copy_to_local(
|
||||||
|
GBinderRemoteReply* reply) /* since 1.0.6 */
|
||||||
|
G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
/* Convenience function to decode replies with just one data item */
|
/* Convenience function to decode replies with just one data item */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -62,6 +62,21 @@ uid_t
|
|||||||
gbinder_remote_request_sender_euid(
|
gbinder_remote_request_sender_euid(
|
||||||
GBinderRemoteRequest* req); /* since 1.0.2 */
|
GBinderRemoteRequest* req); /* since 1.0.2 */
|
||||||
|
|
||||||
|
GBinderLocalRequest*
|
||||||
|
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 */
|
/* Convenience function to decode requests with just one data item */
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -37,6 +37,12 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef
|
||||||
|
void
|
||||||
|
(*GBinderServiceManagerFunc)(
|
||||||
|
GBinderServiceManager* sm,
|
||||||
|
void* user_data);
|
||||||
|
|
||||||
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
|
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
|
||||||
* list, otherwise the caller will deallocate it. */
|
* list, otherwise the caller will deallocate it. */
|
||||||
typedef
|
typedef
|
||||||
@@ -61,6 +67,13 @@ void
|
|||||||
int status,
|
int status,
|
||||||
void* user_data);
|
void* user_data);
|
||||||
|
|
||||||
|
typedef
|
||||||
|
void
|
||||||
|
(*GBinderServiceManagerRegistrationFunc)(
|
||||||
|
GBinderServiceManager* sm,
|
||||||
|
const char* name,
|
||||||
|
void* user_data);
|
||||||
|
|
||||||
GBinderServiceManager*
|
GBinderServiceManager*
|
||||||
gbinder_servicemanager_new(
|
gbinder_servicemanager_new(
|
||||||
const char* dev);
|
const char* dev);
|
||||||
@@ -80,6 +93,13 @@ gbinder_servicemanager_new_local_object(
|
|||||||
GBinderLocalTransactFunc handler,
|
GBinderLocalTransactFunc handler,
|
||||||
void* user_data);
|
void* user_data);
|
||||||
|
|
||||||
|
GBinderLocalObject*
|
||||||
|
gbinder_servicemanager_new_local_object2(
|
||||||
|
GBinderServiceManager* sm,
|
||||||
|
const char* const* ifaces,
|
||||||
|
GBinderLocalTransactFunc handler,
|
||||||
|
void* user_data); /* Since 1.0.29 */
|
||||||
|
|
||||||
GBinderServiceManager*
|
GBinderServiceManager*
|
||||||
gbinder_servicemanager_ref(
|
gbinder_servicemanager_ref(
|
||||||
GBinderServiceManager* sm);
|
GBinderServiceManager* sm);
|
||||||
@@ -88,6 +108,15 @@ void
|
|||||||
gbinder_servicemanager_unref(
|
gbinder_servicemanager_unref(
|
||||||
GBinderServiceManager* sm);
|
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
|
gulong
|
||||||
gbinder_servicemanager_list(
|
gbinder_servicemanager_list(
|
||||||
GBinderServiceManager* sm,
|
GBinderServiceManager* sm,
|
||||||
@@ -130,6 +159,33 @@ gbinder_servicemanager_cancel(
|
|||||||
GBinderServiceManager* sm,
|
GBinderServiceManager* sm,
|
||||||
gulong id);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* GBINDER_SERVICEMANAGER_H */
|
#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-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -61,6 +61,7 @@ G_BEGIN_DECLS
|
|||||||
|
|
||||||
typedef struct gbinder_buffer GBinderBuffer;
|
typedef struct gbinder_buffer GBinderBuffer;
|
||||||
typedef struct gbinder_client GBinderClient;
|
typedef struct gbinder_client GBinderClient;
|
||||||
|
typedef struct gbinder_ipc GBinderIpc;
|
||||||
typedef struct gbinder_local_object GBinderLocalObject;
|
typedef struct gbinder_local_object GBinderLocalObject;
|
||||||
typedef struct gbinder_local_reply GBinderLocalReply;
|
typedef struct gbinder_local_reply GBinderLocalReply;
|
||||||
typedef struct gbinder_local_request GBinderLocalRequest;
|
typedef struct gbinder_local_request GBinderLocalRequest;
|
||||||
@@ -68,10 +69,35 @@ typedef struct gbinder_reader GBinderReader;
|
|||||||
typedef struct gbinder_remote_object GBinderRemoteObject;
|
typedef struct gbinder_remote_object GBinderRemoteObject;
|
||||||
typedef struct gbinder_remote_reply GBinderRemoteReply;
|
typedef struct gbinder_remote_reply GBinderRemoteReply;
|
||||||
typedef struct gbinder_remote_request GBinderRemoteRequest;
|
typedef struct gbinder_remote_request GBinderRemoteRequest;
|
||||||
|
typedef struct gbinder_servicename GBinderServiceName;
|
||||||
typedef struct gbinder_servicemanager GBinderServiceManager;
|
typedef struct gbinder_servicemanager GBinderServiceManager;
|
||||||
typedef struct gbinder_writer GBinderWriter;
|
typedef struct gbinder_writer GBinderWriter;
|
||||||
typedef struct gbinder_parent GBinderParent;
|
typedef struct gbinder_parent GBinderParent;
|
||||||
|
|
||||||
|
/* Basic HIDL types */
|
||||||
|
|
||||||
|
typedef struct gbinder_hidl_vec {
|
||||||
|
union {
|
||||||
|
guint64 value;
|
||||||
|
const void* ptr;
|
||||||
|
} data;
|
||||||
|
guint32 count;
|
||||||
|
guint32 owns_buffer;
|
||||||
|
} GBinderHidlVec;
|
||||||
|
|
||||||
|
#define GBINDER_HIDL_VEC_BUFFER_OFFSET (0)
|
||||||
|
|
||||||
|
typedef struct gbinder_hidl_string {
|
||||||
|
union {
|
||||||
|
guint64 value;
|
||||||
|
const char* str;
|
||||||
|
} data;
|
||||||
|
guint32 len;
|
||||||
|
guint32 owns_buffer;
|
||||||
|
} GBinderHidlString;
|
||||||
|
|
||||||
|
#define GBINDER_HIDL_STRING_BUFFER_OFFSET (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each RPC call is identified by the interface name returned
|
* Each RPC call is identified by the interface name returned
|
||||||
* by gbinder_remote_request_interface() the transaction code.
|
* by gbinder_remote_request_interface() the transaction code.
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -86,6 +86,12 @@ gbinder_writer_append_string16_len(
|
|||||||
const char* utf8,
|
const char* utf8,
|
||||||
gssize num_bytes);
|
gssize num_bytes);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_append_string16_utf16(
|
||||||
|
GBinderWriter* writer,
|
||||||
|
const gunichar2* utf16,
|
||||||
|
gssize length); /* Since 1.0.17 */
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_writer_append_string8(
|
gbinder_writer_append_string8(
|
||||||
GBinderWriter* writer,
|
GBinderWriter* writer,
|
||||||
@@ -108,6 +114,21 @@ gbinder_writer_append_bytes(
|
|||||||
const void* data,
|
const void* data,
|
||||||
gsize size);
|
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
|
guint
|
||||||
gbinder_writer_append_buffer_object_with_parent(
|
gbinder_writer_append_buffer_object_with_parent(
|
||||||
GBinderWriter* writer,
|
GBinderWriter* writer,
|
||||||
@@ -121,6 +142,13 @@ gbinder_writer_append_buffer_object(
|
|||||||
const void* buf,
|
const void* buf,
|
||||||
gsize len);
|
gsize len);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_append_hidl_vec(
|
||||||
|
GBinderWriter* writer,
|
||||||
|
const void* base,
|
||||||
|
guint count,
|
||||||
|
guint elemsize); /* since 1.0.8 */
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_writer_append_hidl_string(
|
gbinder_writer_append_hidl_string(
|
||||||
GBinderWriter* writer,
|
GBinderWriter* writer,
|
||||||
@@ -142,6 +170,40 @@ gbinder_writer_append_remote_object(
|
|||||||
GBinderWriter* writer,
|
GBinderWriter* writer,
|
||||||
GBinderRemoteObject* obj);
|
GBinderRemoteObject* obj);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_append_byte_array(
|
||||||
|
GBinderWriter* writer,
|
||||||
|
const void* byte_array,
|
||||||
|
gint32 len); /* since 1.0.12 */
|
||||||
|
|
||||||
|
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_memdup(
|
||||||
|
GBinderWriter* writer,
|
||||||
|
const void* buf,
|
||||||
|
gsize size); /* since 1.0.19 */
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_add_cleanup(
|
||||||
|
GBinderWriter* writer,
|
||||||
|
GDestroyNotify destroy,
|
||||||
|
gpointer data); /* since 1.0.19 */
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* GBINDER_WRITER_H */
|
#endif /* GBINDER_WRITER_H */
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
Name: libgbinder
|
Name: libgbinder
|
||||||
Version: 1.0.5
|
Version: 1.0.32
|
||||||
Release: 0
|
Release: 0
|
||||||
Summary: Binder client library
|
Summary: Binder client library
|
||||||
Group: Development/Libraries
|
Group: Development/Libraries
|
||||||
License: BSD
|
License: BSD
|
||||||
URL: https://github.com/mer-hybris/libgbinder
|
URL: https://github.com/mer-hybris/libgbinder
|
||||||
Source: %{name}-%{version}.tar.bz2
|
Source: %{name}-%{version}.tar.bz2
|
||||||
Requires: libglibutil >= 1.0.29
|
Requires: libglibutil >= 1.0.35
|
||||||
BuildRequires: pkgconfig(glib-2.0)
|
BuildRequires: pkgconfig(glib-2.0)
|
||||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.29
|
BuildRequires: pkgconfig(libglibutil) >= 1.0.35
|
||||||
Requires(post): /sbin/ldconfig
|
Requires(post): /sbin/ldconfig
|
||||||
Requires(postun): /sbin/ldconfig
|
Requires(postun): /sbin/ldconfig
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -36,55 +36,62 @@
|
|||||||
|
|
||||||
#include <gutil_macros.h>
|
#include <gutil_macros.h>
|
||||||
|
|
||||||
typedef struct gbinder_buffer_memory {
|
struct gbinder_buffer_contents {
|
||||||
gint refcount;
|
gint refcount;
|
||||||
void* buffer;
|
void* buffer;
|
||||||
gsize size;
|
gsize size;
|
||||||
|
void** objects;
|
||||||
GBinderDriver* driver;
|
GBinderDriver* driver;
|
||||||
} GBinderBufferMemory;
|
};
|
||||||
|
|
||||||
typedef struct gbinder_buffer_priv {
|
typedef struct gbinder_buffer_priv {
|
||||||
GBinderBuffer pub;
|
GBinderBuffer pub;
|
||||||
GBinderBufferMemory* memory;
|
GBinderBufferContents* contents;
|
||||||
} GBinderBufferPriv;
|
} GBinderBufferPriv;
|
||||||
|
|
||||||
static inline GBinderBufferPriv* gbinder_buffer_cast(GBinderBuffer* buf)
|
static inline GBinderBufferPriv* gbinder_buffer_cast(GBinderBuffer* buf)
|
||||||
{ return G_CAST(buf, GBinderBufferPriv, pub); }
|
{ return G_CAST(buf, GBinderBufferPriv, pub); }
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* GBinderBufferMemory
|
* GBinderBufferContents
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
static
|
static
|
||||||
GBinderBufferMemory*
|
GBinderBufferContents*
|
||||||
gbinder_buffer_memory_new(
|
gbinder_buffer_contents_new(
|
||||||
GBinderDriver* driver,
|
GBinderDriver* driver,
|
||||||
void* buffer,
|
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);
|
g_atomic_int_set(&self->refcount, 1);
|
||||||
self->buffer = buffer;
|
self->buffer = buffer;
|
||||||
self->size = size;
|
self->size = size;
|
||||||
|
self->objects = objects;
|
||||||
self->driver = gbinder_driver_ref(driver);
|
self->driver = gbinder_driver_ref(driver);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
gbinder_buffer_memory_free(
|
gbinder_buffer_contents_free(
|
||||||
GBinderBufferMemory* self)
|
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_free_buffer(self->driver, self->buffer);
|
||||||
gbinder_driver_unref(self->driver);
|
gbinder_driver_unref(self->driver);
|
||||||
g_slice_free(GBinderBufferMemory, self);
|
g_slice_free(GBinderBufferContents, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
GBinderBufferContents*
|
||||||
GBinderBufferMemory*
|
gbinder_buffer_contents_ref(
|
||||||
gbinder_buffer_memory_ref(
|
GBinderBufferContents* self)
|
||||||
GBinderBufferMemory* self)
|
|
||||||
{
|
{
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GASSERT(self->refcount > 0);
|
GASSERT(self->refcount > 0);
|
||||||
@@ -93,15 +100,14 @@ gbinder_buffer_memory_ref(
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void
|
void
|
||||||
gbinder_buffer_memory_unref(
|
gbinder_buffer_contents_unref(
|
||||||
GBinderBufferMemory* self)
|
GBinderBufferContents* self)
|
||||||
{
|
{
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GASSERT(self->refcount > 0);
|
GASSERT(self->refcount > 0);
|
||||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||||
gbinder_buffer_memory_free(self);
|
gbinder_buffer_contents_free(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,14 +119,14 @@ gbinder_buffer_memory_unref(
|
|||||||
static
|
static
|
||||||
GBinderBuffer*
|
GBinderBuffer*
|
||||||
gbinder_buffer_alloc(
|
gbinder_buffer_alloc(
|
||||||
GBinderBufferMemory* memory,
|
GBinderBufferContents* contents,
|
||||||
void* data,
|
void* data,
|
||||||
gsize size)
|
gsize size)
|
||||||
{
|
{
|
||||||
GBinderBufferPriv* priv = g_slice_new0(GBinderBufferPriv);
|
GBinderBufferPriv* priv = g_slice_new0(GBinderBufferPriv);
|
||||||
GBinderBuffer* self = &priv->pub;
|
GBinderBuffer* self = &priv->pub;
|
||||||
|
|
||||||
priv->memory = memory;
|
priv->contents = contents;
|
||||||
self->data = data;
|
self->data = data;
|
||||||
self->size = size;
|
self->size = size;
|
||||||
return self;
|
return self;
|
||||||
@@ -133,7 +139,7 @@ gbinder_buffer_free(
|
|||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
||||||
|
|
||||||
gbinder_buffer_memory_unref(priv->memory);
|
gbinder_buffer_contents_unref(priv->contents);
|
||||||
g_slice_free(GBinderBufferPriv, priv);
|
g_slice_free(GBinderBufferPriv, priv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,10 +148,12 @@ GBinderBuffer*
|
|||||||
gbinder_buffer_new(
|
gbinder_buffer_new(
|
||||||
GBinderDriver* driver,
|
GBinderDriver* driver,
|
||||||
void* data,
|
void* data,
|
||||||
gsize size)
|
gsize size,
|
||||||
|
void** objects)
|
||||||
{
|
{
|
||||||
return gbinder_buffer_alloc((driver && data) ?
|
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*
|
GBinderBuffer*
|
||||||
@@ -155,10 +163,30 @@ gbinder_buffer_new_with_parent(
|
|||||||
gsize size)
|
gsize size)
|
||||||
{
|
{
|
||||||
return gbinder_buffer_alloc(parent ?
|
return gbinder_buffer_alloc(parent ?
|
||||||
gbinder_buffer_memory_ref(gbinder_buffer_cast(parent)->memory) : NULL,
|
gbinder_buffer_contents_ref(gbinder_buffer_contents(parent)) : NULL,
|
||||||
data, size);
|
data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gconstpointer
|
||||||
|
gbinder_buffer_data(
|
||||||
|
GBinderBuffer* self,
|
||||||
|
gsize* size)
|
||||||
|
{
|
||||||
|
GBinderBufferContents* contents = gbinder_buffer_contents(self);
|
||||||
|
|
||||||
|
if (G_LIKELY(contents)) {
|
||||||
|
if (size) {
|
||||||
|
*size = contents->size;
|
||||||
|
}
|
||||||
|
return contents->buffer;
|
||||||
|
} else {
|
||||||
|
if (size) {
|
||||||
|
*size = 0;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GBinderDriver*
|
GBinderDriver*
|
||||||
gbinder_buffer_driver(
|
gbinder_buffer_driver(
|
||||||
GBinderBuffer* self)
|
GBinderBuffer* self)
|
||||||
@@ -166,13 +194,43 @@ gbinder_buffer_driver(
|
|||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
|
||||||
|
|
||||||
if (priv->memory) {
|
if (priv->contents) {
|
||||||
return priv->memory->driver;
|
return priv->contents->driver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GBinderIo*
|
||||||
|
gbinder_buffer_io(
|
||||||
|
GBinderBuffer* buf)
|
||||||
|
{
|
||||||
|
GBinderDriver* driver = gbinder_buffer_driver(buf);
|
||||||
|
|
||||||
|
return driver ? gbinder_driver_io(driver) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void**
|
||||||
|
gbinder_buffer_objects(
|
||||||
|
GBinderBuffer* self)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* mode: C
|
* mode: C
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -41,7 +41,8 @@ GBinderBuffer*
|
|||||||
gbinder_buffer_new(
|
gbinder_buffer_new(
|
||||||
GBinderDriver* driver,
|
GBinderDriver* driver,
|
||||||
void* data,
|
void* data,
|
||||||
gsize size);
|
gsize size,
|
||||||
|
void** objects);
|
||||||
|
|
||||||
GBinderBuffer*
|
GBinderBuffer*
|
||||||
gbinder_buffer_new_with_parent(
|
gbinder_buffer_new_with_parent(
|
||||||
@@ -53,8 +54,30 @@ GBinderDriver*
|
|||||||
gbinder_buffer_driver(
|
gbinder_buffer_driver(
|
||||||
GBinderBuffer* buf);
|
GBinderBuffer* buf);
|
||||||
|
|
||||||
#define gbinder_buffer_io(buf) \
|
GBinderBufferContents*
|
||||||
gbinder_driver_io(gbinder_buffer_driver(buf))
|
gbinder_buffer_contents(
|
||||||
|
GBinderBuffer* buf);
|
||||||
|
|
||||||
|
gconstpointer
|
||||||
|
gbinder_buffer_data(
|
||||||
|
GBinderBuffer* buf,
|
||||||
|
gsize* size);
|
||||||
|
|
||||||
|
const GBinderIo*
|
||||||
|
gbinder_buffer_io(
|
||||||
|
GBinderBuffer* buf);
|
||||||
|
|
||||||
|
void**
|
||||||
|
gbinder_buffer_objects(
|
||||||
|
GBinderBuffer* buffer);
|
||||||
|
|
||||||
|
GBinderBufferContents*
|
||||||
|
gbinder_buffer_contents_ref(
|
||||||
|
GBinderBufferContents* contents);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_buffer_contents_unref(
|
||||||
|
GBinderBufferContents* contents);
|
||||||
|
|
||||||
#endif /* GBINDER_BUFFER_PRIVATE_H */
|
#endif /* GBINDER_BUFFER_PRIVATE_H */
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -48,11 +48,33 @@ struct gbinder_cleanup {
|
|||||||
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
|
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
|
||||||
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
|
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_cleanup_destroy_func(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GBinderCleanupItem* item = data;
|
||||||
|
|
||||||
|
item->destroy(item->pointer);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
GBinderCleanup*
|
GBinderCleanup*
|
||||||
gbinder_cleanup_new()
|
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
|
void
|
||||||
@@ -60,11 +82,6 @@ gbinder_cleanup_free(
|
|||||||
GBinderCleanup* self)
|
GBinderCleanup* self)
|
||||||
{
|
{
|
||||||
if (G_LIKELY(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);
|
g_array_free((GArray*)self, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -39,6 +39,10 @@ void
|
|||||||
gbinder_cleanup_free(
|
gbinder_cleanup_free(
|
||||||
GBinderCleanup* cleanup);
|
GBinderCleanup* cleanup);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_cleanup_reset(
|
||||||
|
GBinderCleanup* cleanup);
|
||||||
|
|
||||||
GBinderCleanup*
|
GBinderCleanup*
|
||||||
gbinder_cleanup_add(
|
gbinder_cleanup_add(
|
||||||
GBinderCleanup* cleanup,
|
GBinderCleanup* cleanup,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -75,7 +75,9 @@ gbinder_client_free(
|
|||||||
gbinder_remote_object_unref(self->remote);
|
gbinder_remote_object_unref(self->remote);
|
||||||
gbinder_local_request_unref(priv->basic_req);
|
gbinder_local_request_unref(priv->basic_req);
|
||||||
g_free(priv->iface);
|
g_free(priv->iface);
|
||||||
g_bytes_unref(priv->rpc_header);
|
if (priv->rpc_header) {
|
||||||
|
g_bytes_unref(priv->rpc_header);
|
||||||
|
}
|
||||||
g_slice_free(GBinderClientPriv, priv);
|
g_slice_free(GBinderClientPriv, priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +119,13 @@ gbinder_client_new(
|
|||||||
GBinderRemoteObject* remote,
|
GBinderRemoteObject* remote,
|
||||||
const char* iface)
|
const char* iface)
|
||||||
{
|
{
|
||||||
if (G_LIKELY(remote) && G_LIKELY(iface)) {
|
if (G_LIKELY(remote)) {
|
||||||
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
|
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
|
||||||
GBinderClient* self = &priv->pub;
|
GBinderClient* self = &priv->pub;
|
||||||
GBinderIpc* ipc = remote->ipc;
|
GBinderDriver* driver = remote->ipc->driver;
|
||||||
GBinderOutputData* hdr;
|
|
||||||
|
|
||||||
g_atomic_int_set(&priv->refcount, 1);
|
g_atomic_int_set(&priv->refcount, 1);
|
||||||
|
self->remote = gbinder_remote_object_ref(remote);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate basic request (without additional parameters) and pull
|
* Generate basic request (without additional parameters) and pull
|
||||||
@@ -131,12 +133,17 @@ gbinder_client_new(
|
|||||||
* transactions which has no additional parameters. The header data
|
* transactions which has no additional parameters. The header data
|
||||||
* are needed for building non-trivial requests.
|
* are needed for building non-trivial requests.
|
||||||
*/
|
*/
|
||||||
priv->basic_req = gbinder_driver_local_request_new(ipc->driver, iface);
|
if (iface) {
|
||||||
hdr = gbinder_local_request_data(priv->basic_req);
|
GBinderOutputData* hdr;
|
||||||
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
|
|
||||||
|
|
||||||
self->remote = gbinder_remote_object_ref(remote);
|
priv->basic_req = gbinder_driver_local_request_new(driver, iface);
|
||||||
self->iface = priv->iface = g_strdup(iface);
|
hdr = gbinder_local_request_data(priv->basic_req);
|
||||||
|
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
|
||||||
|
self->iface = priv->iface = g_strdup(iface);
|
||||||
|
} else {
|
||||||
|
priv->basic_req = gbinder_local_request_new
|
||||||
|
(gbinder_driver_io(driver), NULL);
|
||||||
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -169,6 +176,13 @@ gbinder_client_unref(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
gbinder_client_interface(
|
||||||
|
GBinderClient* self) /* since 1.0.22 */
|
||||||
|
{
|
||||||
|
return G_LIKELY(self) ? gbinder_client_cast(self)->iface : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
GBinderLocalRequest*
|
GBinderLocalRequest*
|
||||||
gbinder_client_new_request(
|
gbinder_client_new_request(
|
||||||
GBinderClient* self)
|
GBinderClient* self)
|
||||||
@@ -191,12 +205,15 @@ gbinder_client_transact_sync_reply(
|
|||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderRemoteObject* obj = self->remote;
|
GBinderRemoteObject* obj = self->remote;
|
||||||
|
|
||||||
if (!req) {
|
if (G_LIKELY(!obj->dead)) {
|
||||||
/* Default empty request (just the header, no parameters) */
|
if (!req) {
|
||||||
req = gbinder_client_cast(self)->basic_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 gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
|
GDEBUG("Refusing to perform transaction with a dead object");
|
||||||
code, req, status);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -210,15 +227,18 @@ gbinder_client_transact_sync_oneway(
|
|||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderRemoteObject* obj = self->remote;
|
GBinderRemoteObject* obj = self->remote;
|
||||||
|
|
||||||
if (!req) {
|
if (G_LIKELY(!obj->dead)) {
|
||||||
/* Default empty request (just the header, no parameters) */
|
if (!req) {
|
||||||
req = gbinder_client_cast(self)->basic_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);
|
||||||
}
|
}
|
||||||
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
|
GDEBUG("Refusing to perform transaction with a dead object");
|
||||||
code, req);
|
return (-ESTALE);
|
||||||
} else {
|
|
||||||
return (-EINVAL);
|
|
||||||
}
|
}
|
||||||
|
return (-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
gulong
|
gulong
|
||||||
@@ -233,23 +253,27 @@ gbinder_client_transact(
|
|||||||
{
|
{
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderRemoteObject* obj = self->remote;
|
GBinderRemoteObject* obj = self->remote;
|
||||||
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
|
|
||||||
|
|
||||||
tx->client = gbinder_client_ref(self);
|
if (G_LIKELY(!obj->dead)) {
|
||||||
tx->reply = reply;
|
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
|
||||||
tx->destroy = destroy;
|
|
||||||
tx->user_data = user_data;
|
|
||||||
|
|
||||||
if (!req) {
|
tx->client = gbinder_client_ref(self);
|
||||||
/* Default empty request (just the header, no parameters) */
|
tx->reply = reply;
|
||||||
req = gbinder_client_cast(self)->basic_req;
|
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);
|
||||||
}
|
}
|
||||||
|
GDEBUG("Refusing to perform transaction with a dead object");
|
||||||
return gbinder_ipc_transact(obj->ipc, obj->handle, code, flags, req,
|
|
||||||
gbinder_client_transact_reply, gbinder_client_transact_destroy, tx);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -31,6 +31,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gbinder_servicemanager_p.h"
|
#include "gbinder_servicemanager_p.h"
|
||||||
|
#include "gbinder_rpc_protocol.h"
|
||||||
|
#include "gbinder_servicepoll.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
#include <gbinder_client.h>
|
#include <gbinder_client.h>
|
||||||
@@ -42,13 +44,31 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
typedef GBinderServiceManager GBinderDefaultServiceManager;
|
typedef struct gbinder_defaultservicemanager_watch {
|
||||||
|
GBinderServicePoll* poll;
|
||||||
|
char* name;
|
||||||
|
gulong handler_id;
|
||||||
|
guint notify_id;
|
||||||
|
} GBinderDefaultServiceManagerWatch;
|
||||||
|
|
||||||
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
|
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
|
||||||
|
typedef struct gbinder_defaultservicemanager {
|
||||||
|
GBinderServiceManager manager;
|
||||||
|
GBinderServicePoll* poll;
|
||||||
|
GHashTable* watch_table;
|
||||||
|
} GBinderDefaultServiceManager;
|
||||||
|
|
||||||
G_DEFINE_TYPE(GBinderDefaultServiceManager,
|
G_DEFINE_TYPE(GBinderDefaultServiceManager,
|
||||||
gbinder_defaultservicemanager,
|
gbinder_defaultservicemanager,
|
||||||
GBINDER_TYPE_SERVICEMANAGER)
|
GBINDER_TYPE_SERVICEMANAGER)
|
||||||
|
|
||||||
|
#define PARENT_CLASS gbinder_defaultservicemanager_parent_class
|
||||||
|
#define GBINDER_TYPE_DEFAULTSERVICEMANAGER \
|
||||||
|
gbinder_defaultservicemanager_get_type()
|
||||||
|
#define GBINDER_DEFAULTSERVICEMANAGER(obj) \
|
||||||
|
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_DEFAULTSERVICEMANAGER, \
|
||||||
|
GBinderDefaultServiceManager)
|
||||||
|
|
||||||
enum gbinder_defaultservicemanager_calls {
|
enum gbinder_defaultservicemanager_calls {
|
||||||
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
|
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
|
||||||
CHECK_SERVICE_TRANSACTION,
|
CHECK_SERVICE_TRANSACTION,
|
||||||
@@ -56,8 +76,6 @@ enum gbinder_defaultservicemanager_calls {
|
|||||||
LIST_SERVICES_TRANSACTION
|
LIST_SERVICES_TRANSACTION
|
||||||
};
|
};
|
||||||
|
|
||||||
/* As a special case, ServiceManager's handle is zero */
|
|
||||||
#define DEFAULTSERVICEMANAGER_HANDLE (0)
|
|
||||||
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager"
|
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager"
|
||||||
|
|
||||||
GBinderServiceManager*
|
GBinderServiceManager*
|
||||||
@@ -65,7 +83,76 @@ gbinder_defaultservicemanager_new(
|
|||||||
const char* dev)
|
const char* dev)
|
||||||
{
|
{
|
||||||
return gbinder_servicemanager_new_with_type
|
return gbinder_servicemanager_new_with_type
|
||||||
(gbinder_defaultservicemanager_get_type(), dev);
|
(GBINDER_TYPE_DEFAULTSERVICEMANAGER, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_defaultservicemanager_watch_proc(
|
||||||
|
GBinderServicePoll* poll,
|
||||||
|
const char* name_added,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
GBinderDefaultServiceManagerWatch* watch = user_data;
|
||||||
|
|
||||||
|
if (!g_strcmp0(name_added, watch->name)) {
|
||||||
|
GBinderServiceManager* manager =
|
||||||
|
gbinder_servicepoll_manager(watch->poll);
|
||||||
|
|
||||||
|
if (watch->notify_id) {
|
||||||
|
g_source_remove(watch->notify_id);
|
||||||
|
watch->notify_id = 0;
|
||||||
|
}
|
||||||
|
gbinder_servicemanager_service_registered(manager, name_added);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
gbinder_defaultservicemanager_watch_notify(
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GBinderDefaultServiceManagerWatch* watch = user_data;
|
||||||
|
GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll);
|
||||||
|
char* name = g_strdup(watch->name);
|
||||||
|
|
||||||
|
GASSERT(watch->notify_id);
|
||||||
|
watch->notify_id = 0;
|
||||||
|
gbinder_servicemanager_service_registered(manager, name);
|
||||||
|
g_free(name);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_defaultservicemanager_watch_free(
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GBinderDefaultServiceManagerWatch* watch = user_data;
|
||||||
|
|
||||||
|
if (watch->notify_id) {
|
||||||
|
g_source_remove(watch->notify_id);
|
||||||
|
}
|
||||||
|
gbinder_servicepoll_remove_handler(watch->poll, watch->handler_id);
|
||||||
|
gbinder_servicepoll_unref(watch->poll);
|
||||||
|
g_free(watch->name);
|
||||||
|
g_slice_free(GBinderDefaultServiceManagerWatch, watch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderDefaultServiceManagerWatch*
|
||||||
|
gbinder_defaultservicemanager_watch_new(
|
||||||
|
GBinderDefaultServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
GBinderDefaultServiceManagerWatch* watch =
|
||||||
|
g_slice_new0(GBinderDefaultServiceManagerWatch);
|
||||||
|
|
||||||
|
watch->name = g_strdup(name);
|
||||||
|
watch->poll = gbinder_servicepoll_new(&manager->manager, &manager->poll);
|
||||||
|
watch->handler_id = gbinder_servicepoll_add_handler(watch->poll,
|
||||||
|
gbinder_defaultservicemanager_watch_proc, watch);
|
||||||
|
return watch;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -150,11 +237,61 @@ gbinder_defaultservicemanager_add_service(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBINDER_SERVICEMANAGER_NAME_CHECK
|
||||||
|
gbinder_defaultservicemanager_check_name(
|
||||||
|
GBinderServiceManager* self,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
return GBINDER_SERVICEMANAGER_NAME_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
gbinder_defaultservicemanager_watch(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(manager);
|
||||||
|
GBinderDefaultServiceManagerWatch* watch =
|
||||||
|
gbinder_defaultservicemanager_watch_new(self, name);
|
||||||
|
|
||||||
|
g_hash_table_replace(self->watch_table, watch->name, watch);
|
||||||
|
if (gbinder_servicepoll_is_known_name(watch->poll, name)) {
|
||||||
|
watch->notify_id =
|
||||||
|
g_idle_add(gbinder_defaultservicemanager_watch_notify, watch);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_defaultservicemanager_unwatch(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
g_hash_table_remove(GBINDER_DEFAULTSERVICEMANAGER(manager)->watch_table,
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
gbinder_defaultservicemanager_init(
|
gbinder_defaultservicemanager_init(
|
||||||
GBinderDefaultServiceManager* self)
|
GBinderDefaultServiceManager* self)
|
||||||
{
|
{
|
||||||
|
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||||
|
NULL, gbinder_defaultservicemanager_watch_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_defaultservicemanager_finalize(
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(object);
|
||||||
|
|
||||||
|
g_hash_table_destroy(self->watch_table);
|
||||||
|
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -162,13 +299,18 @@ void
|
|||||||
gbinder_defaultservicemanager_class_init(
|
gbinder_defaultservicemanager_class_init(
|
||||||
GBinderDefaultServiceManagerClass* klass)
|
GBinderDefaultServiceManagerClass* klass)
|
||||||
{
|
{
|
||||||
klass->handle = DEFAULTSERVICEMANAGER_HANDLE;
|
|
||||||
klass->iface = DEFAULTSERVICEMANAGER_IFACE;
|
klass->iface = DEFAULTSERVICEMANAGER_IFACE;
|
||||||
klass->default_device = GBINDER_DEFAULT_BINDER;
|
klass->default_device = GBINDER_DEFAULT_BINDER;
|
||||||
|
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
|
||||||
|
|
||||||
klass->list = gbinder_defaultservicemanager_list;
|
klass->list = gbinder_defaultservicemanager_list;
|
||||||
klass->get_service = gbinder_defaultservicemanager_get_service;
|
klass->get_service = gbinder_defaultservicemanager_get_service;
|
||||||
klass->add_service = gbinder_defaultservicemanager_add_service;
|
klass->add_service = gbinder_defaultservicemanager_add_service;
|
||||||
|
klass->check_name = gbinder_defaultservicemanager_check_name;
|
||||||
|
/* normalize_name is not needed */
|
||||||
|
klass->watch = gbinder_defaultservicemanager_watch;
|
||||||
|
klass->unwatch = gbinder_defaultservicemanager_unwatch;
|
||||||
|
G_OBJECT_CLASS(klass)->finalize = gbinder_defaultservicemanager_finalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -288,19 +288,15 @@ gbinder_driver_death_notification(
|
|||||||
guint32 cmd,
|
guint32 cmd,
|
||||||
GBinderRemoteObject* obj)
|
GBinderRemoteObject* obj)
|
||||||
{
|
{
|
||||||
if (G_LIKELY(obj)) {
|
GBinderIoBuf write;
|
||||||
GBinderIoBuf write;
|
guint8 buf[4 + GBINDER_MAX_DEATH_NOTIFICATION_SIZE];
|
||||||
guint8 buf[4 + GBINDER_MAX_DEATH_NOTIFICATION_SIZE];
|
guint32* data = (guint32*)buf;
|
||||||
guint32* data = (guint32*)buf;
|
|
||||||
|
|
||||||
data[0] = cmd;
|
data[0] = cmd;
|
||||||
memset(&write, 0, sizeof(write));
|
memset(&write, 0, sizeof(write));
|
||||||
write.ptr = (uintptr_t)buf;
|
write.ptr = (uintptr_t)buf;
|
||||||
write.size = 4 + self->io->encode_death_notification(data + 1, obj);
|
write.size = 4 + self->io->encode_death_notification(data + 1, obj);
|
||||||
|
return gbinder_driver_write(self, &write) >= 0;
|
||||||
return gbinder_driver_write(self, &write) >= 0;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -439,11 +435,10 @@ gbinder_driver_handle_transaction(
|
|||||||
/* Transfer data ownership to the request */
|
/* Transfer data ownership to the request */
|
||||||
if (tx.data && tx.size) {
|
if (tx.data && tx.size) {
|
||||||
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
|
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
|
||||||
gbinder_remote_request_set_data(req,
|
gbinder_remote_request_set_data(req, tx.code,
|
||||||
gbinder_buffer_new(self, tx.data, tx.size),
|
gbinder_buffer_new(self, tx.data, tx.size, tx.objects));
|
||||||
tx.objects);
|
|
||||||
} else {
|
} else {
|
||||||
g_free(tx.objects);
|
GASSERT(!tx.objects);
|
||||||
gbinder_driver_free_buffer(self, tx.data);
|
gbinder_driver_free_buffer(self, tx.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,7 +454,7 @@ gbinder_driver_handle_transaction(
|
|||||||
&status);
|
&status);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
GWARN("Unhandled transaction 0x%08x", tx.code);
|
GWARN("Unhandled transaction %s 0x%08x", iface, tx.code);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,6 +531,7 @@ gbinder_driver_handle_command(
|
|||||||
} else if (cmd == io->br.transaction) {
|
} else if (cmd == io->br.transaction) {
|
||||||
gbinder_driver_handle_transaction(self, reg, handler, data);
|
gbinder_driver_handle_transaction(self, reg, handler, data);
|
||||||
} else if (cmd == io->br.dead_binder) {
|
} else if (cmd == io->br.dead_binder) {
|
||||||
|
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
|
||||||
guint64 handle = 0;
|
guint64 handle = 0;
|
||||||
GBinderRemoteObject* obj;
|
GBinderRemoteObject* obj;
|
||||||
|
|
||||||
@@ -546,6 +542,8 @@ gbinder_driver_handle_command(
|
|||||||
gbinder_remote_object_handle_death_notification(obj);
|
gbinder_remote_object_handle_death_notification(obj);
|
||||||
gbinder_remote_object_unref(obj);
|
gbinder_remote_object_unref(obj);
|
||||||
}
|
}
|
||||||
|
GVERBOSE("< BC_DEAD_BINDER_DONE %llu", (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) {
|
} else if (cmd == io->br.clear_death_notification_done) {
|
||||||
GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE");
|
GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE");
|
||||||
} else {
|
} else {
|
||||||
@@ -637,10 +635,9 @@ gbinder_driver_txstatus(
|
|||||||
if (tx.data && tx.size) {
|
if (tx.data && tx.size) {
|
||||||
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
|
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
|
||||||
gbinder_remote_reply_set_data(reply,
|
gbinder_remote_reply_set_data(reply,
|
||||||
gbinder_buffer_new(self, tx.data, tx.size),
|
gbinder_buffer_new(self, tx.data, tx.size, tx.objects));
|
||||||
tx.objects);
|
|
||||||
} else {
|
} else {
|
||||||
g_free(tx.objects);
|
GASSERT(!tx.objects);
|
||||||
gbinder_driver_free_buffer(self, tx.data);
|
gbinder_driver_free_buffer(self, tx.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,7 +669,8 @@ gbinder_driver_txstatus(
|
|||||||
|
|
||||||
GBinderDriver*
|
GBinderDriver*
|
||||||
gbinder_driver_new(
|
gbinder_driver_new(
|
||||||
const char* dev)
|
const char* dev,
|
||||||
|
const GBinderRpcProtocol* protocol)
|
||||||
{
|
{
|
||||||
const int fd = gbinder_system_open(dev, O_RDWR | O_CLOEXEC);
|
const int fd = gbinder_system_open(dev, O_RDWR | O_CLOEXEC);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
@@ -711,8 +709,10 @@ gbinder_driver_new(
|
|||||||
GERR("%s failed to set max threads (%u): %s", dev,
|
GERR("%s failed to set max threads (%u): %s", dev,
|
||||||
max_threads, strerror(errno));
|
max_threads, strerror(errno));
|
||||||
}
|
}
|
||||||
/* Choose the protocol based on the device name */
|
/* Choose the protocol based on the device name
|
||||||
self->protocol = gbinder_rpc_protocol_for_device(dev);
|
* if none is explicitely specified */
|
||||||
|
self->protocol = protocol ? protocol :
|
||||||
|
gbinder_rpc_protocol_for_device(dev);
|
||||||
return self;
|
return self;
|
||||||
} else {
|
} else {
|
||||||
GERR("%s failed to mmap: %s", dev, strerror(errno));
|
GERR("%s failed to mmap: %s", dev, strerror(errno));
|
||||||
@@ -811,8 +811,13 @@ gbinder_driver_request_death_notification(
|
|||||||
GBinderDriver* self,
|
GBinderDriver* self,
|
||||||
GBinderRemoteObject* obj)
|
GBinderRemoteObject* obj)
|
||||||
{
|
{
|
||||||
return gbinder_driver_death_notification
|
if (G_LIKELY(obj)) {
|
||||||
(self, self->io->bc.request_death_notification, obj);
|
GVERBOSE("< BC_REQUEST_DEATH_NOTIFICATION 0x%08x", obj->handle);
|
||||||
|
return gbinder_driver_death_notification(self,
|
||||||
|
self->io->bc.request_death_notification, obj);
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@@ -820,8 +825,13 @@ gbinder_driver_clear_death_notification(
|
|||||||
GBinderDriver* self,
|
GBinderDriver* self,
|
||||||
GBinderRemoteObject* obj)
|
GBinderRemoteObject* obj)
|
||||||
{
|
{
|
||||||
return gbinder_driver_death_notification
|
if (G_LIKELY(obj)) {
|
||||||
(self, self->io->bc.clear_death_notification, obj);
|
GVERBOSE("< BC_CLEAR_DEATH_NOTIFICATION 0x%08x", obj->handle);
|
||||||
|
return gbinder_driver_death_notification(self,
|
||||||
|
self->io->bc.clear_death_notification, obj);
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@@ -860,6 +870,32 @@ gbinder_driver_release(
|
|||||||
return gbinder_driver_cmd_int32(self, self->io->bc.release, handle);
|
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
|
void
|
||||||
gbinder_driver_free_buffer(
|
gbinder_driver_free_buffer(
|
||||||
GBinderDriver* self,
|
GBinderDriver* self,
|
||||||
@@ -1011,6 +1047,28 @@ gbinder_driver_transact(
|
|||||||
return txstatus;
|
return txstatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gbinder_driver_ping(
|
||||||
|
GBinderDriver* self,
|
||||||
|
GBinderObjectRegistry* reg,
|
||||||
|
guint32 handle)
|
||||||
|
{
|
||||||
|
const GBinderRpcProtocol* protocol = self->protocol;
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(self->io, NULL);
|
||||||
|
GBinderRemoteReply* reply = gbinder_remote_reply_new(reg);
|
||||||
|
GBinderWriter writer;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
protocol->write_ping(&writer);
|
||||||
|
ret = gbinder_driver_transact(self, reg, handle, protocol->ping_tx,
|
||||||
|
req, reply);
|
||||||
|
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
gbinder_remote_reply_unref(reply);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
GBinderLocalRequest*
|
GBinderLocalRequest*
|
||||||
gbinder_driver_local_request_new(
|
gbinder_driver_local_request_new(
|
||||||
GBinderDriver* self,
|
GBinderDriver* self,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -39,7 +39,8 @@ struct pollfd;
|
|||||||
|
|
||||||
GBinderDriver*
|
GBinderDriver*
|
||||||
gbinder_driver_new(
|
gbinder_driver_new(
|
||||||
const char* dev);
|
const char* dev,
|
||||||
|
const GBinderRpcProtocol* protocol);
|
||||||
|
|
||||||
GBinderDriver*
|
GBinderDriver*
|
||||||
gbinder_driver_ref(
|
gbinder_driver_ref(
|
||||||
@@ -96,6 +97,12 @@ gbinder_driver_release(
|
|||||||
GBinderDriver* driver,
|
GBinderDriver* driver,
|
||||||
guint32 handle);
|
guint32 handle);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_driver_close_fds(
|
||||||
|
GBinderDriver* self,
|
||||||
|
void** objects,
|
||||||
|
const void* end);
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_driver_free_buffer(
|
gbinder_driver_free_buffer(
|
||||||
GBinderDriver* driver,
|
GBinderDriver* driver,
|
||||||
@@ -124,6 +131,12 @@ gbinder_driver_transact(
|
|||||||
GBinderLocalRequest* request,
|
GBinderLocalRequest* request,
|
||||||
GBinderRemoteReply* reply);
|
GBinderRemoteReply* reply);
|
||||||
|
|
||||||
|
int
|
||||||
|
gbinder_driver_ping(
|
||||||
|
GBinderDriver* driver,
|
||||||
|
GBinderObjectRegistry* reg,
|
||||||
|
guint32 handle);
|
||||||
|
|
||||||
GBinderLocalRequest*
|
GBinderLocalRequest*
|
||||||
gbinder_driver_local_request_new(
|
gbinder_driver_local_request_new(
|
||||||
GBinderDriver* self,
|
GBinderDriver* self,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -31,23 +31,40 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gbinder_servicemanager_p.h"
|
#include "gbinder_servicemanager_p.h"
|
||||||
|
#include "gbinder_rpc_protocol.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
#include <gbinder_client.h>
|
#include <gbinder_client.h>
|
||||||
|
#include <gbinder_local_object.h>
|
||||||
#include <gbinder_local_request.h>
|
#include <gbinder_local_request.h>
|
||||||
#include <gbinder_remote_reply.h>
|
#include <gbinder_remote_reply.h>
|
||||||
|
#include <gbinder_remote_request.h>
|
||||||
#include <gbinder_reader.h>
|
#include <gbinder_reader.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
typedef GBinderServiceManager GBinderHwServiceManager;
|
typedef struct gbinder_hwservicemanager_watch {
|
||||||
|
char* name;
|
||||||
|
GBinderLocalObject* callback;
|
||||||
|
} GBinderHwServiceManagerWatch;
|
||||||
|
|
||||||
typedef GBinderServiceManagerClass GBinderHwServiceManagerClass;
|
typedef GBinderServiceManagerClass GBinderHwServiceManagerClass;
|
||||||
|
typedef struct gbinder_hwservicemanager {
|
||||||
|
GBinderServiceManager manager;
|
||||||
|
GHashTable* watch_table;
|
||||||
|
} GBinderHwServiceManager;
|
||||||
|
|
||||||
G_DEFINE_TYPE(GBinderHwServiceManager,
|
G_DEFINE_TYPE(GBinderHwServiceManager,
|
||||||
gbinder_hwservicemanager,
|
gbinder_hwservicemanager,
|
||||||
GBINDER_TYPE_SERVICEMANAGER)
|
GBINDER_TYPE_SERVICEMANAGER)
|
||||||
|
|
||||||
|
#define PARENT_CLASS gbinder_hwservicemanager_parent_class
|
||||||
|
#define GBINDER_TYPE_HWSERVICEMANAGER (gbinder_hwservicemanager_get_type())
|
||||||
|
#define GBINDER_HWSERVICEMANAGER(obj) \
|
||||||
|
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_HWSERVICEMANAGER, \
|
||||||
|
GBinderHwServiceManager)
|
||||||
|
|
||||||
enum gbinder_hwservicemanager_calls {
|
enum gbinder_hwservicemanager_calls {
|
||||||
GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
|
GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
|
||||||
ADD_TRANSACTION,
|
ADD_TRANSACTION,
|
||||||
@@ -59,9 +76,74 @@ enum gbinder_hwservicemanager_calls {
|
|||||||
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
|
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
|
||||||
};
|
};
|
||||||
|
|
||||||
/* As a special case, ServiceManager's handle is zero */
|
enum gbinder_hwservicemanager_notifications {
|
||||||
#define HWSERVICEMANAGER_HANDLE (0)
|
ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION
|
||||||
|
};
|
||||||
|
|
||||||
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
|
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
|
||||||
|
#define HWSERVICEMANAGER_NOTIFICATION_IFACE \
|
||||||
|
"android.hidl.manager@1.0::IServiceNotification"
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_hwservicemanager_handle_registration(
|
||||||
|
GBinderHwServiceManager* 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_hwservicemanager_notification(
|
||||||
|
GBinderLocalObject* obj,
|
||||||
|
GBinderRemoteRequest* req,
|
||||||
|
guint code,
|
||||||
|
guint flags,
|
||||||
|
int* status,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(user_data);
|
||||||
|
const char* iface = gbinder_remote_request_interface(req);
|
||||||
|
|
||||||
|
if (!g_strcmp0(iface, HWSERVICEMANAGER_NOTIFICATION_IFACE)) {
|
||||||
|
GBinderReader reader;
|
||||||
|
|
||||||
|
gbinder_remote_request_init_reader(req, &reader);
|
||||||
|
switch (code) {
|
||||||
|
case ON_REGISTRATION_TRANSACTION:
|
||||||
|
GDEBUG(HWSERVICEMANAGER_NOTIFICATION_IFACE " %u onRegistration",
|
||||||
|
code);
|
||||||
|
gbinder_hwservicemanager_handle_registration(self, &reader);
|
||||||
|
*status = GBINDER_STATUS_OK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GDEBUG(HWSERVICEMANAGER_NOTIFICATION_IFACE " %u", code);
|
||||||
|
*status = GBINDER_STATUS_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GDEBUG("%s %u", iface, code);
|
||||||
|
*status = GBINDER_STATUS_FAILED;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
GBinderServiceManager*
|
GBinderServiceManager*
|
||||||
gbinder_hwservicemanager_new(
|
gbinder_hwservicemanager_new(
|
||||||
@@ -74,7 +156,7 @@ gbinder_hwservicemanager_new(
|
|||||||
static
|
static
|
||||||
char**
|
char**
|
||||||
gbinder_hwservicemanager_list(
|
gbinder_hwservicemanager_list(
|
||||||
GBinderHwServiceManager* self)
|
GBinderServiceManager* self)
|
||||||
{
|
{
|
||||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||||
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply
|
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply
|
||||||
@@ -110,6 +192,7 @@ gbinder_hwservicemanager_get_service(
|
|||||||
/* e.g. "android.hardware.radio@1.1::IRadio/slot1" */
|
/* e.g. "android.hardware.radio@1.1::IRadio/slot1" */
|
||||||
const char* sep = strchr(fqinstance, '/');
|
const char* sep = strchr(fqinstance, '/');
|
||||||
GBinderRemoteObject* obj = NULL;
|
GBinderRemoteObject* obj = NULL;
|
||||||
|
|
||||||
if (sep) {
|
if (sep) {
|
||||||
GBinderRemoteReply* reply;
|
GBinderRemoteReply* reply;
|
||||||
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
|
||||||
@@ -169,11 +252,123 @@ gbinder_hwservicemanager_add_service(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_hwservicemanager_watch_free(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GBinderHwServiceManagerWatch* watch = data;
|
||||||
|
|
||||||
|
g_free(watch->name);
|
||||||
|
gbinder_local_object_drop(watch->callback);
|
||||||
|
g_free(watch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBINDER_SERVICEMANAGER_NAME_CHECK
|
||||||
|
gbinder_hwservicemanager_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_hwservicemanager_normalize_name(
|
||||||
|
GBinderServiceManager* self,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
/* Slash must be there, see gbinder_hwservicemanager_check_name() above */
|
||||||
|
return g_strndup(name, strchr(name, '/') - name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
gbinder_hwservicemanager_watch(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(manager);
|
||||||
|
GBinderLocalRequest* req = gbinder_client_new_request(manager->client);
|
||||||
|
GBinderRemoteReply* reply;
|
||||||
|
GBinderHwServiceManagerWatch* watch =
|
||||||
|
g_new0(GBinderHwServiceManagerWatch, 1);
|
||||||
|
gboolean success = FALSE;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
watch->name = g_strdup(name);
|
||||||
|
watch->callback = gbinder_servicemanager_new_local_object(manager,
|
||||||
|
HWSERVICEMANAGER_NOTIFICATION_IFACE,
|
||||||
|
gbinder_hwservicemanager_notification, self);
|
||||||
|
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_hwservicemanager_unwatch(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
g_hash_table_remove(GBINDER_HWSERVICEMANAGER(manager)->watch_table, name);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
gbinder_hwservicemanager_init(
|
gbinder_hwservicemanager_init(
|
||||||
GBinderHwServiceManager* self)
|
GBinderHwServiceManager* self)
|
||||||
{
|
{
|
||||||
|
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||||
|
NULL, gbinder_hwservicemanager_watch_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_hwservicemanager_finalize(
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
GBinderHwServiceManager* self = GBINDER_HWSERVICEMANAGER(object);
|
||||||
|
|
||||||
|
g_hash_table_destroy(self->watch_table);
|
||||||
|
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -181,13 +376,18 @@ void
|
|||||||
gbinder_hwservicemanager_class_init(
|
gbinder_hwservicemanager_class_init(
|
||||||
GBinderHwServiceManagerClass* klass)
|
GBinderHwServiceManagerClass* klass)
|
||||||
{
|
{
|
||||||
klass->handle = HWSERVICEMANAGER_HANDLE;
|
|
||||||
klass->iface = HWSERVICEMANAGER_IFACE;
|
klass->iface = HWSERVICEMANAGER_IFACE;
|
||||||
klass->default_device = GBINDER_DEFAULT_HWBINDER;
|
klass->default_device = GBINDER_DEFAULT_HWBINDER;
|
||||||
|
klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;
|
||||||
|
|
||||||
klass->list = gbinder_hwservicemanager_list;
|
klass->list = gbinder_hwservicemanager_list;
|
||||||
klass->get_service = gbinder_hwservicemanager_get_service;
|
klass->get_service = gbinder_hwservicemanager_get_service;
|
||||||
klass->add_service = gbinder_hwservicemanager_add_service;
|
klass->add_service = gbinder_hwservicemanager_add_service;
|
||||||
|
klass->check_name = gbinder_hwservicemanager_check_name;
|
||||||
|
klass->normalize_name = gbinder_hwservicemanager_normalize_name;
|
||||||
|
klass->watch = gbinder_hwservicemanager_watch;
|
||||||
|
klass->unwatch = gbinder_hwservicemanager_unwatch;
|
||||||
|
G_OBJECT_CLASS(klass)->finalize = gbinder_hwservicemanager_finalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -90,6 +90,21 @@ GBINDER_IO_FN(write_read)(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 (buf && buf->hdr.type == BINDER_TYPE_PTR) {
|
||||||
|
return buf->length;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Writes pointer to the buffer */
|
/* Writes pointer to the buffer */
|
||||||
static
|
static
|
||||||
guint
|
guint
|
||||||
@@ -113,9 +128,13 @@ GBINDER_IO_FN(encode_local_object)(
|
|||||||
struct flat_binder_object* dest = out;
|
struct flat_binder_object* dest = out;
|
||||||
|
|
||||||
memset(dest, 0, sizeof(*dest));
|
memset(dest, 0, sizeof(*dest));
|
||||||
dest->hdr.type = BINDER_TYPE_BINDER;
|
if (obj) {
|
||||||
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
dest->hdr.type = BINDER_TYPE_BINDER;
|
||||||
dest->binder = (uintptr_t)obj;
|
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||||
|
dest->binder = (uintptr_t)obj;
|
||||||
|
} else {
|
||||||
|
dest->hdr.type = BINDER_TYPE_WEAK_BINDER;
|
||||||
|
}
|
||||||
return sizeof(*dest);
|
return sizeof(*dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +157,21 @@ GBINDER_IO_FN(encode_remote_object)(
|
|||||||
return sizeof(*dest);
|
return sizeof(*dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
guint
|
||||||
|
GBINDER_IO_FN(encode_fd_object)(
|
||||||
|
void* out,
|
||||||
|
int fd)
|
||||||
|
{
|
||||||
|
struct flat_binder_object* dest = out;
|
||||||
|
|
||||||
|
memset(dest, 0, sizeof(*dest));
|
||||||
|
dest->hdr.type = BINDER_TYPE_FD;
|
||||||
|
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||||
|
dest->handle = fd;
|
||||||
|
return sizeof(*dest);
|
||||||
|
}
|
||||||
|
|
||||||
/* Encodes binder_buffer_object */
|
/* Encodes binder_buffer_object */
|
||||||
static
|
static
|
||||||
guint
|
guint
|
||||||
@@ -379,7 +413,7 @@ guint
|
|||||||
GBINDER_IO_FN(decode_buffer_object)(
|
GBINDER_IO_FN(decode_buffer_object)(
|
||||||
GBinderBuffer* buf,
|
GBinderBuffer* buf,
|
||||||
gsize offset,
|
gsize offset,
|
||||||
GBinderBuffer** out)
|
GBinderIoBufferObject* out)
|
||||||
{
|
{
|
||||||
const void* data = (guint8*)buf->data + offset;
|
const void* data = (guint8*)buf->data + offset;
|
||||||
const gsize size = (offset < buf->size) ? (buf->size - offset) : 0;
|
const gsize size = (offset < buf->size) ? (buf->size - offset) : 0;
|
||||||
@@ -387,12 +421,36 @@ GBINDER_IO_FN(decode_buffer_object)(
|
|||||||
|
|
||||||
if (size >= sizeof(*flat) && flat->hdr.type == BINDER_TYPE_PTR) {
|
if (size >= sizeof(*flat) && flat->hdr.type == BINDER_TYPE_PTR) {
|
||||||
if (out) {
|
if (out) {
|
||||||
*out = gbinder_buffer_new_with_parent(buf,
|
out->data = (void*)(uintptr_t)flat->buffer;
|
||||||
(void*)(uintptr_t)flat->buffer, flat->length);
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,10 +503,13 @@ const GBinderIo GBINDER_IO_PREFIX = {
|
|||||||
.failed_reply = BR_FAILED_REPLY
|
.failed_reply = BR_FAILED_REPLY
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.object_data_size = GBINDER_IO_FN(object_data_size),
|
||||||
|
|
||||||
/* Encoders */
|
/* Encoders */
|
||||||
.encode_pointer = GBINDER_IO_FN(encode_pointer),
|
.encode_pointer = GBINDER_IO_FN(encode_pointer),
|
||||||
.encode_local_object = GBINDER_IO_FN(encode_local_object),
|
.encode_local_object = GBINDER_IO_FN(encode_local_object),
|
||||||
.encode_remote_object = GBINDER_IO_FN(encode_remote_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_buffer_object = GBINDER_IO_FN(encode_buffer_object),
|
||||||
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
|
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
|
||||||
.encode_transaction = GBINDER_IO_FN(encode_transaction),
|
.encode_transaction = GBINDER_IO_FN(encode_transaction),
|
||||||
@@ -461,6 +522,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
|
|||||||
.decode_binder_ptr_cookie = GBINDER_IO_FN(decode_binder_ptr_cookie),
|
.decode_binder_ptr_cookie = GBINDER_IO_FN(decode_binder_ptr_cookie),
|
||||||
.decode_binder_object = GBINDER_IO_FN(decode_binder_object),
|
.decode_binder_object = GBINDER_IO_FN(decode_binder_object),
|
||||||
.decode_buffer_object = GBINDER_IO_FN(decode_buffer_object),
|
.decode_buffer_object = GBINDER_IO_FN(decode_buffer_object),
|
||||||
|
.decode_fd_object = GBINDER_IO_FN(decode_fd_object),
|
||||||
|
|
||||||
/* ioctl wrappers */
|
/* ioctl wrappers */
|
||||||
.write_read = GBINDER_IO_FN(write_read)
|
.write_read = GBINDER_IO_FN(write_read)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -43,6 +43,13 @@ typedef struct gbinder_io_buf {
|
|||||||
gsize consumed;
|
gsize consumed;
|
||||||
} GBinderIoBuf;
|
} GBinderIoBuf;
|
||||||
|
|
||||||
|
typedef struct gbinder_io_buffer_object {
|
||||||
|
void* data;
|
||||||
|
gsize size;
|
||||||
|
gsize parent_offset;
|
||||||
|
gboolean has_parent;
|
||||||
|
} GBinderIoBufferObject;
|
||||||
|
|
||||||
typedef struct gbinder_io_tx_data {
|
typedef struct gbinder_io_tx_data {
|
||||||
int status;
|
int status;
|
||||||
guint32 code;
|
guint32 code;
|
||||||
@@ -118,6 +125,9 @@ struct gbinder_io {
|
|||||||
guint failed_reply;
|
guint failed_reply;
|
||||||
} br;
|
} br;
|
||||||
|
|
||||||
|
/* Size of the object's extra data */
|
||||||
|
gsize (*object_data_size)(const void* obj);
|
||||||
|
|
||||||
/* Writes pointer to the buffer. The destination buffer must have
|
/* Writes pointer to the buffer. The destination buffer must have
|
||||||
* at least GBINDER_IO_MAX_POINTER_SIZE bytes available. The
|
* at least GBINDER_IO_MAX_POINTER_SIZE bytes available. The
|
||||||
* actual size is returned. */
|
* actual size is returned. */
|
||||||
@@ -128,6 +138,7 @@ struct gbinder_io {
|
|||||||
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
|
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
|
||||||
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
|
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
|
||||||
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
|
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
|
||||||
|
guint (*encode_fd_object)(void* out, int fd);
|
||||||
|
|
||||||
/* Encode binder_buffer_object */
|
/* Encode binder_buffer_object */
|
||||||
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
|
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
|
||||||
@@ -161,9 +172,10 @@ struct gbinder_io {
|
|||||||
void* (*decode_binder_ptr_cookie)(const void* data);
|
void* (*decode_binder_ptr_cookie)(const void* data);
|
||||||
guint (*decode_cookie)(const void* data, guint64* cookie);
|
guint (*decode_cookie)(const void* data, guint64* cookie);
|
||||||
guint (*decode_binder_object)(const void* data, gsize size,
|
guint (*decode_binder_object)(const void* data, gsize size,
|
||||||
GBinderObjectRegistry* reg, GBinderRemoteObject** obj);
|
GBinderObjectRegistry* reg, GBinderRemoteObject** obj);
|
||||||
guint (*decode_buffer_object)(GBinderBuffer* buf, gsize offset,
|
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 */
|
/* ioctl wrappers */
|
||||||
int (*write_read)(int fd, GBinderIoBuf* write, GBinderIoBuf* read);
|
int (*write_read)(int fd, GBinderIoBuf* write, GBinderIoBuf* read);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -68,9 +68,9 @@ struct gbinder_ipc_priv {
|
|||||||
GMutex local_objects_mutex;
|
GMutex local_objects_mutex;
|
||||||
GHashTable* local_objects;
|
GHashTable* local_objects;
|
||||||
|
|
||||||
/* We may need more loopers... But let's start with just one */
|
|
||||||
GMutex looper_mutex;
|
GMutex looper_mutex;
|
||||||
GBinderIpcLooper* looper;
|
GBinderIpcLooper* primary_loopers;
|
||||||
|
GBinderIpcLooper* blocked_loopers;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef GObjectClass GBinderIpcClass;
|
typedef GObjectClass GBinderIpcClass;
|
||||||
@@ -87,7 +87,8 @@ static GHashTable* gbinder_ipc_table = NULL;
|
|||||||
static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
#define GBINDER_IPC_MAX_TX_THREADS (15)
|
#define GBINDER_IPC_MAX_TX_THREADS (15)
|
||||||
#define GBINDER_IPC_MAX_LOOPERS (15)
|
#define GBINDER_IPC_MAX_PRIMARY_LOOPERS (5)
|
||||||
|
#define GBINDER_IPC_LOOPER_START_TIMEOUT_SEC (2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When looper receives the transaction:
|
* When looper receives the transaction:
|
||||||
@@ -99,7 +100,7 @@ static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|||||||
* When the main thread receives GBinderIpcLooperTx:
|
* When the main thread receives GBinderIpcLooperTx:
|
||||||
*
|
*
|
||||||
* 1. Lets the object to process it and produce the response (GBinderOutput).
|
* 1. Lets the object to process it and produce the response (GBinderOutput).
|
||||||
* 2. Writes one byte to the sending end of the tx pipe.
|
* 2. Writes one byte (TX_DONE) to the sending end of the tx pipe.
|
||||||
* 3. Unreferences GBinderIpcLooperTx
|
* 3. Unreferences GBinderIpcLooperTx
|
||||||
*
|
*
|
||||||
* When tx pipe wakes up the looper:
|
* When tx pipe wakes up the looper:
|
||||||
@@ -110,11 +111,26 @@ static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|||||||
* Note that GBinderIpcLooperTx can be deallocated on either looper or
|
* Note that GBinderIpcLooperTx can be deallocated on either looper or
|
||||||
* main thread, depending on whether looper gives up on the transaction
|
* main thread, depending on whether looper gives up on the transaction
|
||||||
* before it gets processed.
|
* before it gets processed.
|
||||||
|
*
|
||||||
|
* When transaction is blocked by gbinder_remote_request_block() call, it
|
||||||
|
* gets slightly more complicated. Then the main thread writes TX_BLOCKED
|
||||||
|
* to the pipe (rather than TX_DONE) and then looper thread spawn another
|
||||||
|
* looper and keeps waiting for TX_DONE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TX_DONE (0x2a)
|
#define TX_DONE (0x2a)
|
||||||
|
#define TX_BLOCKED (0x3b)
|
||||||
|
|
||||||
typedef struct gbinder_ipc_looper_tx {
|
typedef enum gbinder_ipc_looper_tx_state {
|
||||||
|
GBINDER_IPC_LOOPER_TX_SCHEDULED,
|
||||||
|
GBINDER_IPC_LOOPER_TX_PROCESSING,
|
||||||
|
GBINDER_IPC_LOOPER_TX_PROCESSED,
|
||||||
|
GBINDER_IPC_LOOPER_TX_BLOCKING,
|
||||||
|
GBINDER_IPC_LOOPER_TX_BLOCKED,
|
||||||
|
GBINDER_IPC_LOOPER_TX_COMPLETE
|
||||||
|
} GBINDER_IPC_LOOPER_TX_STATE;
|
||||||
|
|
||||||
|
struct gbinder_ipc_looper_tx {
|
||||||
/* Reference count */
|
/* Reference count */
|
||||||
gint refcount;
|
gint refcount;
|
||||||
/* These are filled by the looper: */
|
/* These are filled by the looper: */
|
||||||
@@ -124,16 +140,23 @@ typedef struct gbinder_ipc_looper_tx {
|
|||||||
GBinderLocalObject* obj;
|
GBinderLocalObject* obj;
|
||||||
GBinderRemoteRequest* req;
|
GBinderRemoteRequest* req;
|
||||||
/* And these by the main thread processing the transaction: */
|
/* And these by the main thread processing the transaction: */
|
||||||
|
GBINDER_IPC_LOOPER_TX_STATE state;
|
||||||
GBinderLocalReply* reply;
|
GBinderLocalReply* reply;
|
||||||
int status;
|
int status;
|
||||||
} GBinderIpcLooperTx;
|
} /* GBinderIpcLooperTx */;
|
||||||
|
|
||||||
struct gbinder_ipc_looper {
|
struct gbinder_ipc_looper {
|
||||||
gint refcount;
|
gint refcount;
|
||||||
|
GBinderIpcLooper* next;
|
||||||
|
char* name;
|
||||||
GBinderHandler handler;
|
GBinderHandler handler;
|
||||||
GBinderDriver* driver;
|
GBinderDriver* driver;
|
||||||
GBinderIpc* ipc; /* Not a reference! */
|
GBinderIpc* ipc; /* Not a reference! */
|
||||||
GThread* thread;
|
GThread* thread;
|
||||||
|
GMutex mutex;
|
||||||
|
GCond start_cond;
|
||||||
|
gint exit;
|
||||||
|
gint started;
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
int txfd[2];
|
int txfd[2];
|
||||||
};
|
};
|
||||||
@@ -174,6 +197,11 @@ typedef struct gbinder_ipc_tx_custom {
|
|||||||
GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self)
|
GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self)
|
||||||
{ return gbinder_driver_dev(self->driver); }
|
{ return gbinder_driver_dev(self->driver); }
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderIpcLooper*
|
||||||
|
gbinder_ipc_looper_new(
|
||||||
|
GBinderIpc* ipc);
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* GBinderIpcLooperTx
|
* GBinderIpcLooperTx
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -241,21 +269,207 @@ gbinder_ipc_looper_tx_unref(
|
|||||||
return dropped;
|
return dropped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* State machine of transaction handling. All this is happening on the event
|
||||||
|
* thread and therefore doesn't need to be synchronized.
|
||||||
|
*
|
||||||
|
* SCHEDULED
|
||||||
|
* =========
|
||||||
|
* |
|
||||||
|
* PROCESSING
|
||||||
|
* ==========
|
||||||
|
* |
|
||||||
|
* --------------------- handler is called ---------------------------------
|
||||||
|
* |
|
||||||
|
* +---------------- request doesn't need to be blocked ----------+
|
||||||
|
* | |
|
||||||
|
* gbinder_remote_request_block() |
|
||||||
|
* | |
|
||||||
|
* BLOCKING -- gbinder_remote_request_complete() --> PROCESSED |
|
||||||
|
* ======== ========= |
|
||||||
|
* | | |
|
||||||
|
* --------------------- handler returns -----------------------------------
|
||||||
|
* | | |
|
||||||
|
* BLOCKED COMPLETE <-------+
|
||||||
|
* ======= ========
|
||||||
|
* ^
|
||||||
|
* ... |
|
||||||
|
* gbinder_remote_request_complete() is called later ----+
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_remote_request_block(
|
||||||
|
GBinderRemoteRequest* req) /* Since 1.0.20 */
|
||||||
|
{
|
||||||
|
if (G_LIKELY(req)) {
|
||||||
|
GBinderIpcLooperTx* tx = req->tx;
|
||||||
|
|
||||||
|
GASSERT(tx);
|
||||||
|
if (G_LIKELY(tx)) {
|
||||||
|
GASSERT(tx->state == GBINDER_IPC_LOOPER_TX_PROCESSING);
|
||||||
|
if (tx->state == GBINDER_IPC_LOOPER_TX_PROCESSING) {
|
||||||
|
tx->state = GBINDER_IPC_LOOPER_TX_BLOCKING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_remote_request_complete(
|
||||||
|
GBinderRemoteRequest* req,
|
||||||
|
GBinderLocalReply* reply,
|
||||||
|
int status) /* Since 1.0.20 */
|
||||||
|
{
|
||||||
|
if (G_LIKELY(req)) {
|
||||||
|
GBinderIpcLooperTx* tx = req->tx;
|
||||||
|
|
||||||
|
GASSERT(tx);
|
||||||
|
if (G_LIKELY(tx)) {
|
||||||
|
const guint8 done = TX_DONE;
|
||||||
|
|
||||||
|
switch (tx->state) {
|
||||||
|
case GBINDER_IPC_LOOPER_TX_BLOCKING:
|
||||||
|
/* Called by the transaction handler */
|
||||||
|
tx->status = status;
|
||||||
|
tx->reply = gbinder_local_reply_ref(reply);
|
||||||
|
tx->state = GBINDER_IPC_LOOPER_TX_PROCESSED;
|
||||||
|
break;
|
||||||
|
case GBINDER_IPC_LOOPER_TX_BLOCKED:
|
||||||
|
/* Really asynchronous completion */
|
||||||
|
tx->status = status;
|
||||||
|
tx->reply = gbinder_local_reply_ref(reply);
|
||||||
|
tx->state = GBINDER_IPC_LOOPER_TX_COMPLETE;
|
||||||
|
/* Wake up the looper */
|
||||||
|
(void)write(tx->pipefd[1], &done, sizeof(done));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GWARN("Unexpected state %d in request completion", tx->state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the transaction reference */
|
||||||
|
gbinder_ipc_looper_tx_unref(tx, FALSE);
|
||||||
|
req->tx = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* GBinderIpcLooper
|
* GBinderIpcLooper
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_ipc_looper_free(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
if (looper->thread) {
|
||||||
|
g_thread_unref(looper->thread);
|
||||||
|
}
|
||||||
|
close(looper->pipefd[0]);
|
||||||
|
close(looper->pipefd[1]);
|
||||||
|
if (looper->txfd[0] >= 0) {
|
||||||
|
close(looper->txfd[0]);
|
||||||
|
close(looper->txfd[1]);
|
||||||
|
}
|
||||||
|
gbinder_driver_unref(looper->driver);
|
||||||
|
g_free(looper->name);
|
||||||
|
g_cond_clear(&looper->start_cond);
|
||||||
|
g_mutex_clear(&looper->mutex);
|
||||||
|
g_slice_free(GBinderIpcLooper, looper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderIpcLooper*
|
||||||
|
gbinder_ipc_looper_ref(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
GASSERT(looper->refcount > 0);
|
||||||
|
g_atomic_int_inc(&looper->refcount);
|
||||||
|
return looper;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_ipc_looper_unref(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
GASSERT(looper->refcount > 0);
|
||||||
|
if (g_atomic_int_dec_and_test(&looper->refcount)) {
|
||||||
|
gbinder_ipc_looper_free(looper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_ipc_looper_tx_handle(
|
gbinder_ipc_looper_tx_handle(
|
||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
GBinderIpcLooperTx* tx = data;
|
GBinderIpcLooperTx* tx = data;
|
||||||
guint8 done = TX_DONE;
|
GBinderRemoteRequest* req = tx->req;
|
||||||
|
GBinderLocalReply* reply;
|
||||||
|
int status = GBINDER_STATUS_OK;
|
||||||
|
guint8 done;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transaction reference for gbinder_remote_request_block()
|
||||||
|
* and gbinder_remote_request_complete().
|
||||||
|
*/
|
||||||
|
req->tx = gbinder_ipc_looper_tx_ref(tx);
|
||||||
|
|
||||||
|
/* See state machine */
|
||||||
|
GASSERT(tx->state == GBINDER_IPC_LOOPER_TX_SCHEDULED);
|
||||||
|
tx->state = GBINDER_IPC_LOOPER_TX_PROCESSING;
|
||||||
|
|
||||||
/* Actually handle the transaction */
|
/* Actually handle the transaction */
|
||||||
tx->reply = gbinder_local_object_handle_transaction(tx->obj, tx->req,
|
reply = gbinder_local_object_handle_transaction(tx->obj, req,
|
||||||
tx->code, tx->flags, &tx->status);
|
tx->code, tx->flags, &status);
|
||||||
|
|
||||||
|
/* Handle all possible return states */
|
||||||
|
switch (tx->state) {
|
||||||
|
case GBINDER_IPC_LOOPER_TX_PROCESSING:
|
||||||
|
/* Result was returned by the handler */
|
||||||
|
tx->reply = reply;
|
||||||
|
tx->status = status;
|
||||||
|
tx->state = GBINDER_IPC_LOOPER_TX_COMPLETE;
|
||||||
|
reply = NULL;
|
||||||
|
break;
|
||||||
|
case GBINDER_IPC_LOOPER_TX_PROCESSED:
|
||||||
|
/* Result has been provided to gbinder_remote_request_complete() */
|
||||||
|
tx->state = GBINDER_IPC_LOOPER_TX_COMPLETE;
|
||||||
|
break;
|
||||||
|
case GBINDER_IPC_LOOPER_TX_BLOCKING:
|
||||||
|
/* Result will be provided to gbinder_remote_request_complete() */
|
||||||
|
tx->state = GBINDER_IPC_LOOPER_TX_BLOCKED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case handler returns a reply which it wasn't expected to return */
|
||||||
|
GASSERT(!reply);
|
||||||
|
gbinder_local_reply_unref(reply);
|
||||||
|
|
||||||
|
/* Drop the transaction reference unless blocked */
|
||||||
|
if (tx->state == GBINDER_IPC_LOOPER_TX_BLOCKED) {
|
||||||
|
done = TX_BLOCKED;
|
||||||
|
/*
|
||||||
|
* From this point on, it's GBinderRemoteRequest who's holding
|
||||||
|
* reference to GBinderIpcLooperTx, not the other way around and
|
||||||
|
* not both ways. Even if gbinder_remote_request_complete() never
|
||||||
|
* gets called, transaction will still be completed when the last
|
||||||
|
* reference to GBinderRemoteRequest goes away. And if request
|
||||||
|
* never gets deallocated... oh well.
|
||||||
|
*/
|
||||||
|
gbinder_remote_request_unref(tx->req);
|
||||||
|
tx->req = NULL;
|
||||||
|
} else {
|
||||||
|
done = TX_DONE;
|
||||||
|
if (req->tx) {
|
||||||
|
gbinder_ipc_looper_tx_unref(req->tx, FALSE);
|
||||||
|
req->tx = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* And wake up the looper */
|
/* And wake up the looper */
|
||||||
(void)write(tx->pipefd[1], &done, sizeof(done));
|
(void)write(tx->pipefd[1], &done, sizeof(done));
|
||||||
@@ -270,6 +484,83 @@ gbinder_ipc_looper_tx_done(
|
|||||||
gbinder_ipc_looper_tx_unref(data, FALSE);
|
gbinder_ipc_looper_tx_unref(data, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_ipc_looper_start(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
if (!g_atomic_int_get(&looper->started)) {
|
||||||
|
/* Lock */
|
||||||
|
g_mutex_lock(&looper->mutex);
|
||||||
|
if (!g_atomic_int_get(&looper->started)) {
|
||||||
|
g_cond_wait_until(&looper->start_cond, &looper->mutex,
|
||||||
|
g_get_monotonic_time() + GBINDER_IPC_LOOPER_START_TIMEOUT_SEC *
|
||||||
|
G_TIME_SPAN_SECOND);
|
||||||
|
GASSERT(g_atomic_int_get(&looper->started));
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&looper->mutex);
|
||||||
|
/* Unlock */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
gbinder_ipc_looper_remove_from_list(
|
||||||
|
GBinderIpcLooper* looper,
|
||||||
|
GBinderIpcLooper** list)
|
||||||
|
{
|
||||||
|
/* Caller holds looper_mutex */
|
||||||
|
if (*list) {
|
||||||
|
if ((*list) == looper) {
|
||||||
|
(*list) = looper->next;
|
||||||
|
looper->next = NULL;
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
GBinderIpcLooper* prev = (*list);
|
||||||
|
|
||||||
|
while (prev->next) {
|
||||||
|
if (prev->next == looper) {
|
||||||
|
prev->next = looper->next;
|
||||||
|
looper->next = NULL;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
prev = prev->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
gbinder_ipc_looper_remove_primary(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
return gbinder_ipc_looper_remove_from_list(looper,
|
||||||
|
&looper->ipc->priv->primary_loopers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
gbinder_ipc_looper_remove_blocked(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
return gbinder_ipc_looper_remove_from_list(looper,
|
||||||
|
&looper->ipc->priv->blocked_loopers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
guint
|
||||||
|
gbinder_ipc_looper_count_primary(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
const GBinderIpcLooper* ptr = looper->ipc->priv->primary_loopers;
|
||||||
|
guint n = 0;
|
||||||
|
|
||||||
|
for (n = 0; ptr; ptr = ptr->next) n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
GBinderLocalReply*
|
GBinderLocalReply*
|
||||||
gbinder_ipc_looper_transact(
|
gbinder_ipc_looper_transact(
|
||||||
@@ -296,6 +587,7 @@ gbinder_ipc_looper_transact(
|
|||||||
struct pollfd fds[2];
|
struct pollfd fds[2];
|
||||||
guint8 done = 0;
|
guint8 done = 0;
|
||||||
GSource* source = g_idle_source_new();
|
GSource* source = g_idle_source_new();
|
||||||
|
gboolean was_blocked = FALSE;
|
||||||
|
|
||||||
/* Let GBinderLocalObject handle the transaction on the main thread */
|
/* Let GBinderLocalObject handle the transaction on the main thread */
|
||||||
g_source_set_callback(source, gbinder_ipc_looper_tx_handle,
|
g_source_set_callback(source, gbinder_ipc_looper_tx_handle,
|
||||||
@@ -314,60 +606,100 @@ gbinder_ipc_looper_transact(
|
|||||||
if ((fds[1].revents & POLLIN) &&
|
if ((fds[1].revents & POLLIN) &&
|
||||||
read(fds[1].fd, &done, sizeof(done)) == 1) {
|
read(fds[1].fd, &done, sizeof(done)) == 1) {
|
||||||
/* Normal completion */
|
/* Normal completion */
|
||||||
|
if (done == TX_BLOCKED) {
|
||||||
|
/*
|
||||||
|
* We are going to block this looper for potentially
|
||||||
|
* significant period of time. Start new looper to
|
||||||
|
* accept normal incoming requests and terminate this
|
||||||
|
* one when we are done with this transaction.
|
||||||
|
*
|
||||||
|
* For the duration of the transaction, this looper is
|
||||||
|
* moved to the blocked_loopers list.
|
||||||
|
*/
|
||||||
|
GBinderIpcPriv* priv = looper->ipc->priv;
|
||||||
|
GBinderIpcLooper* new_looper = NULL;
|
||||||
|
|
||||||
|
/* Lock */
|
||||||
|
g_mutex_lock(&priv->looper_mutex);
|
||||||
|
if (gbinder_ipc_looper_remove_primary(looper)) {
|
||||||
|
GDEBUG("Primary looper %s is blocked", looper->name);
|
||||||
|
looper->next = priv->blocked_loopers;
|
||||||
|
priv->blocked_loopers = looper;
|
||||||
|
was_blocked = TRUE;
|
||||||
|
|
||||||
|
/* If there's no more primary loopers left, create one */
|
||||||
|
if (!priv->primary_loopers) {
|
||||||
|
new_looper = gbinder_ipc_looper_new(ipc);
|
||||||
|
if (new_looper) {
|
||||||
|
/* Will unref it after it gets started */
|
||||||
|
gbinder_ipc_looper_ref(new_looper);
|
||||||
|
priv->primary_loopers = new_looper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&priv->looper_mutex);
|
||||||
|
/* Unlock */
|
||||||
|
|
||||||
|
if (new_looper) {
|
||||||
|
/* Wait until it gets started */
|
||||||
|
gbinder_ipc_looper_start(new_looper);
|
||||||
|
gbinder_ipc_looper_unref(new_looper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Block until asynchronous transaction gets completed. */
|
||||||
|
done = 0;
|
||||||
|
memset(fds, 0, sizeof(fds));
|
||||||
|
fds[0].fd = looper->pipefd[0];
|
||||||
|
fds[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
||||||
|
fds[1].fd = tx->pipefd[0];
|
||||||
|
fds[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
||||||
|
poll(fds, 2, -1);
|
||||||
|
if ((fds[1].revents & POLLIN) &&
|
||||||
|
read(fds[1].fd, &done, sizeof(done)) == 1) {
|
||||||
|
GDEBUG("Looper %s is released", looper->name);
|
||||||
|
GASSERT(done == TX_DONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (done) {
|
||||||
GASSERT(done == TX_DONE);
|
GASSERT(done == TX_DONE);
|
||||||
reply = gbinder_local_reply_ref(tx->reply);
|
reply = gbinder_local_reply_ref(tx->reply);
|
||||||
status = tx->status;
|
status = tx->status;
|
||||||
if (!gbinder_ipc_looper_tx_unref(tx, TRUE)) {
|
if (!gbinder_ipc_looper_tx_unref(tx, TRUE)) {
|
||||||
/* gbinder_ipc_looper_tx_free() will close those */
|
/*
|
||||||
|
* This wasn't the last references meaning that
|
||||||
|
* gbinder_ipc_looper_tx_free() will close the
|
||||||
|
* descriptors and we will have to create a new
|
||||||
|
* pipe for the next transaction.
|
||||||
|
*/
|
||||||
looper->txfd[0] = looper->txfd[1] = -1;
|
looper->txfd[0] = looper->txfd[1] = -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gbinder_ipc_looper_tx_unref(tx, FALSE);
|
gbinder_ipc_looper_tx_unref(tx, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (was_blocked) {
|
||||||
|
guint n;
|
||||||
|
|
||||||
|
g_mutex_lock(&priv->looper_mutex);
|
||||||
|
n = gbinder_ipc_looper_count_primary(looper);
|
||||||
|
if (n >= GBINDER_IPC_MAX_PRIMARY_LOOPERS) {
|
||||||
|
/* Looper will exit once transaction completes */
|
||||||
|
GDEBUG("Too many primary loopers (%u)", n);
|
||||||
|
g_atomic_int_set(&looper->exit, 1);
|
||||||
|
} else {
|
||||||
|
/* Move it back to the primary list */
|
||||||
|
gbinder_ipc_looper_remove_blocked(looper);
|
||||||
|
looper->next = priv->primary_loopers;
|
||||||
|
priv->primary_loopers = looper;
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&priv->looper_mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*result = status;
|
*result = status;
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
gbinder_ipc_looper_free(
|
|
||||||
GBinderIpcLooper* looper)
|
|
||||||
{
|
|
||||||
if (looper->thread) {
|
|
||||||
g_thread_unref(looper->thread);
|
|
||||||
}
|
|
||||||
close(looper->pipefd[0]);
|
|
||||||
close(looper->pipefd[1]);
|
|
||||||
if (looper->txfd[0] >= 0) {
|
|
||||||
close(looper->txfd[0]);
|
|
||||||
close(looper->txfd[1]);
|
|
||||||
}
|
|
||||||
gbinder_driver_unref(looper->driver);
|
|
||||||
g_slice_free(GBinderIpcLooper, looper);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
GBinderIpcLooper*
|
|
||||||
gbinder_ipc_looper_ref(
|
|
||||||
GBinderIpcLooper* looper)
|
|
||||||
{
|
|
||||||
GASSERT(looper->refcount > 0);
|
|
||||||
g_atomic_int_inc(&looper->refcount);
|
|
||||||
return looper;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
gbinder_ipc_looper_unref(
|
|
||||||
GBinderIpcLooper* looper)
|
|
||||||
{
|
|
||||||
GASSERT(looper->refcount > 0);
|
|
||||||
if (g_atomic_int_dec_and_test(&looper->refcount)) {
|
|
||||||
gbinder_ipc_looper_free(looper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
gpointer
|
gpointer
|
||||||
gbinder_ipc_looper_thread(
|
gbinder_ipc_looper_thread(
|
||||||
@@ -378,38 +710,45 @@ gbinder_ipc_looper_thread(
|
|||||||
|
|
||||||
if (gbinder_driver_enter_looper(driver)) {
|
if (gbinder_driver_enter_looper(driver)) {
|
||||||
struct pollfd pipefd;
|
struct pollfd pipefd;
|
||||||
int result;
|
int res;
|
||||||
|
|
||||||
|
GDEBUG("Looper %s running", looper->name);
|
||||||
|
g_mutex_lock(&looper->mutex);
|
||||||
|
g_atomic_int_set(&looper->started, TRUE);
|
||||||
|
g_cond_broadcast(&looper->start_cond);
|
||||||
|
g_mutex_unlock(&looper->mutex);
|
||||||
|
|
||||||
GDEBUG("Looper %s running", gbinder_driver_dev(driver));
|
|
||||||
memset(&pipefd, 0, sizeof(pipefd));
|
memset(&pipefd, 0, sizeof(pipefd));
|
||||||
pipefd.fd = looper->pipefd[0]; /* read end of the pipe */
|
pipefd.fd = looper->pipefd[0]; /* read end of the pipe */
|
||||||
pipefd.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
pipefd.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
||||||
|
|
||||||
result = gbinder_driver_poll(driver, &pipefd);
|
res = gbinder_driver_poll(driver, &pipefd);
|
||||||
while (looper->ipc && ((result & POLLIN) || !result)) {
|
while (!g_atomic_int_get(&looper->exit) && ((res & POLLIN) || !res)) {
|
||||||
if (result & POLLIN) {
|
if (res & POLLIN) {
|
||||||
/* No need to synchronize access to looper->ipc because
|
/*
|
||||||
|
* No need to synchronize access to looper->ipc because
|
||||||
* the other thread would wait until this thread exits
|
* the other thread would wait until this thread exits
|
||||||
* before setting looper->ipc to NULL */
|
* before setting looper->ipc to NULL.
|
||||||
|
*/
|
||||||
GBinderIpc* ipc = gbinder_ipc_ref(looper->ipc);
|
GBinderIpc* ipc = gbinder_ipc_ref(looper->ipc);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
/* But that gbinder_driver_read() may unref GBinderIpc */
|
/* But that gbinder_driver_read() may unref GBinderIpc */
|
||||||
int ret = gbinder_driver_read(driver, reg, &looper->handler);
|
int ret = gbinder_driver_read(driver, reg, &looper->handler);
|
||||||
|
|
||||||
/* And this gbinder_ipc_unref() may release the last ref: */
|
/* And this gbinder_ipc_unref() may release the last ref: */
|
||||||
gbinder_ipc_unref(ipc);
|
gbinder_ipc_unref(ipc);
|
||||||
/* And at this point looper->ipc may be NULL */
|
/* And at this point looper->ipc may be NULL */
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
GDEBUG("Looper %s failed", gbinder_driver_dev(driver));
|
GDEBUG("Looper %s failed", looper->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pipefd.revents) {
|
/* Any event from this pipe terminates the loop */
|
||||||
/* Any event from this pipe terminates the loop */
|
if (pipefd.revents || g_atomic_int_get(&looper->exit)) {
|
||||||
GDEBUG("Looper %s is asked to exit",
|
GDEBUG("Looper %s is requested to exit", looper->name);
|
||||||
gbinder_driver_dev(driver));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result = gbinder_driver_poll(driver, &pipefd);
|
res = gbinder_driver_poll(driver, &pipefd);
|
||||||
}
|
}
|
||||||
|
|
||||||
gbinder_driver_exit_looper(driver);
|
gbinder_driver_exit_looper(driver);
|
||||||
@@ -421,21 +760,28 @@ gbinder_ipc_looper_thread(
|
|||||||
*/
|
*/
|
||||||
if (looper->ipc) {
|
if (looper->ipc) {
|
||||||
GBinderIpcPriv* priv = looper->ipc->priv;
|
GBinderIpcPriv* priv = looper->ipc->priv;
|
||||||
|
|
||||||
/* Lock */
|
/* Lock */
|
||||||
g_mutex_lock(&priv->looper_mutex);
|
g_mutex_lock(&priv->looper_mutex);
|
||||||
if (priv->looper == looper) {
|
if (gbinder_ipc_looper_remove_blocked(looper) ||
|
||||||
|
gbinder_ipc_looper_remove_primary(looper)) {
|
||||||
/* Spontaneous exit */
|
/* Spontaneous exit */
|
||||||
priv->looper = NULL;
|
GDEBUG("Looper %s exits", looper->name);
|
||||||
GDEBUG("Looper %s exits", gbinder_driver_dev(driver));
|
gbinder_ipc_looper_unref(looper);
|
||||||
} else {
|
} else {
|
||||||
/* Main thread is shutting it down */
|
/* Main thread is shutting it down */
|
||||||
GDEBUG("Looper %s done", gbinder_driver_dev(driver));
|
GDEBUG("Looper %s done", looper->name);
|
||||||
}
|
}
|
||||||
g_mutex_unlock(&priv->looper_mutex);
|
g_mutex_unlock(&priv->looper_mutex);
|
||||||
/* Unlock */
|
/* Unlock */
|
||||||
} else {
|
} else {
|
||||||
GDEBUG("Looper %s is abandoned", gbinder_driver_dev(driver));
|
GDEBUG("Looper %s is abandoned", looper->name);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
g_mutex_lock(&looper->mutex);
|
||||||
|
g_atomic_int_set(&looper->started, TRUE);
|
||||||
|
g_cond_broadcast(&looper->start_cond);
|
||||||
|
g_mutex_unlock(&looper->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
gbinder_ipc_looper_unref(looper);
|
gbinder_ipc_looper_unref(looper);
|
||||||
@@ -456,18 +802,24 @@ gbinder_ipc_looper_new(
|
|||||||
};
|
};
|
||||||
GError* error = NULL;
|
GError* error = NULL;
|
||||||
GBinderIpcLooper* looper = g_slice_new0(GBinderIpcLooper);
|
GBinderIpcLooper* looper = g_slice_new0(GBinderIpcLooper);
|
||||||
|
static gint gbinder_ipc_next_looper_id = 1;
|
||||||
|
guint id = (guint)g_atomic_int_add(&gbinder_ipc_next_looper_id, 1);
|
||||||
|
|
||||||
memcpy(looper->pipefd, fd, sizeof(fd));
|
memcpy(looper->pipefd, fd, sizeof(fd));
|
||||||
looper->txfd[0] = looper->txfd[1] = -1;
|
looper->txfd[0] = looper->txfd[1] = -1;
|
||||||
g_atomic_int_set(&looper->refcount, 1);
|
g_atomic_int_set(&looper->refcount, 1);
|
||||||
|
g_cond_init(&looper->start_cond);
|
||||||
|
g_mutex_init(&looper->mutex);
|
||||||
|
looper->name = g_strdup_printf("%s#%u", gbinder_ipc_name(ipc), id);
|
||||||
looper->handler.f = &handler_functions;
|
looper->handler.f = &handler_functions;
|
||||||
looper->ipc = ipc;
|
looper->ipc = ipc;
|
||||||
looper->driver = gbinder_driver_ref(ipc->driver);
|
looper->driver = gbinder_driver_ref(ipc->driver);
|
||||||
looper->thread = g_thread_try_new(gbinder_ipc_name(ipc),
|
looper->thread = g_thread_try_new(looper->name,
|
||||||
gbinder_ipc_looper_thread, looper, &error);
|
gbinder_ipc_looper_thread, looper, &error);
|
||||||
if (looper->thread) {
|
if (looper->thread) {
|
||||||
/* gbinder_ipc_looper_thread() will release this reference: */
|
/* gbinder_ipc_looper_thread() will release this reference: */
|
||||||
gbinder_ipc_looper_ref(looper);
|
gbinder_ipc_looper_ref(looper);
|
||||||
|
GDEBUG("Starting looper %s", looper->name);
|
||||||
return looper;
|
return looper;
|
||||||
} else {
|
} else {
|
||||||
GERR("Failed to create looper thread: %s", GERRMSG(error));
|
GERR("Failed to create looper thread: %s", GERRMSG(error));
|
||||||
@@ -487,25 +839,116 @@ gbinder_ipc_looper_check(
|
|||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderIpcPriv* priv = self->priv;
|
GBinderIpcPriv* priv = self->priv;
|
||||||
|
|
||||||
if (!priv->looper) {
|
if (!priv->primary_loopers) {
|
||||||
|
GBinderIpcLooper* looper;
|
||||||
|
|
||||||
/* Lock */
|
/* Lock */
|
||||||
g_mutex_lock(&priv->looper_mutex);
|
g_mutex_lock(&priv->looper_mutex);
|
||||||
if (!priv->looper) {
|
if (!priv->primary_loopers) {
|
||||||
GDEBUG("Starting looper %s", gbinder_ipc_name(self));
|
priv->primary_loopers = gbinder_ipc_looper_new(self);
|
||||||
priv->looper = gbinder_ipc_looper_new(self);
|
}
|
||||||
|
looper = priv->primary_loopers;
|
||||||
|
if (looper) {
|
||||||
|
gbinder_ipc_looper_ref(looper);
|
||||||
}
|
}
|
||||||
g_mutex_unlock(&priv->looper_mutex);
|
g_mutex_unlock(&priv->looper_mutex);
|
||||||
/* Unlock */
|
/* Unlock */
|
||||||
|
|
||||||
|
/* We are not ready to accept incoming transactions until
|
||||||
|
* looper has started. We may need to wait a bit. */
|
||||||
|
if (looper) {
|
||||||
|
gbinder_ipc_looper_start(looper);
|
||||||
|
gbinder_ipc_looper_unref(looper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_ipc_looper_stop(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
/* Caller checks looper for NULL */
|
||||||
|
if (looper->thread && looper->thread != g_thread_self()) {
|
||||||
|
guint8 done = TX_DONE;
|
||||||
|
|
||||||
|
GDEBUG("Stopping looper %s", looper->name);
|
||||||
|
g_atomic_int_set(&looper->exit, TRUE);
|
||||||
|
if (write(looper->pipefd[1], &done, sizeof(done)) <= 0) {
|
||||||
|
looper->thread = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderIpcLooper*
|
||||||
|
gbinder_ipc_looper_stop_all(
|
||||||
|
GBinderIpcLooper* loopers,
|
||||||
|
GBinderIpcLooper* list)
|
||||||
|
{
|
||||||
|
while (list) {
|
||||||
|
GBinderIpcLooper* looper = list;
|
||||||
|
GBinderIpcLooper* next = looper->next;
|
||||||
|
|
||||||
|
gbinder_ipc_looper_stop(looper);
|
||||||
|
looper->next = loopers;
|
||||||
|
loopers = looper;
|
||||||
|
list = next;
|
||||||
|
}
|
||||||
|
return loopers;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_ipc_looper_join(
|
||||||
|
GBinderIpcLooper* looper)
|
||||||
|
{
|
||||||
|
/* Caller checks looper for NULL */
|
||||||
|
if (looper->thread && looper->thread != g_thread_self()) {
|
||||||
|
g_thread_join(looper->thread);
|
||||||
|
looper->thread = NULL;
|
||||||
|
}
|
||||||
|
looper->ipc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* GBinderObjectRegistry
|
* GBinderObjectRegistry
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_ipc_invalidate_remote_handle_locked(
|
||||||
|
GBinderIpcPriv* priv,
|
||||||
|
guint32 handle)
|
||||||
|
{
|
||||||
|
/* Caller holds priv->remote_objects_mutex */
|
||||||
|
if (priv->remote_objects) {
|
||||||
|
GVERBOSE_("handle %u", handle);
|
||||||
|
g_hash_table_remove(priv->remote_objects, GINT_TO_POINTER(handle));
|
||||||
|
if (g_hash_table_size(priv->remote_objects) == 0) {
|
||||||
|
g_hash_table_unref(priv->remote_objects);
|
||||||
|
priv->remote_objects = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_ipc_invalidate_remote_handle(
|
||||||
|
GBinderIpc* self,
|
||||||
|
guint32 handle)
|
||||||
|
{
|
||||||
|
GBinderIpcPriv* priv = self->priv;
|
||||||
|
|
||||||
|
/* Lock */
|
||||||
|
g_mutex_lock(&priv->remote_objects_mutex);
|
||||||
|
gbinder_ipc_invalidate_remote_handle_locked(priv, handle);
|
||||||
|
g_mutex_unlock(&priv->remote_objects_mutex);
|
||||||
|
/* Unlock */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal function called by gbinder_object_dispose(). Among other things,
|
* Internal functions called by gbinder_object_dispose(). Among other things,
|
||||||
* it means that it doesn't have to check GBinderIpc pointer for NULL.
|
* it means that it doesn't have to check GBinderIpc pointer for NULL.
|
||||||
*
|
*
|
||||||
* Note the following scenario (where object may be either local or remote):
|
* Note the following scenario (where object may be either local or remote):
|
||||||
@@ -553,31 +996,19 @@ gbinder_ipc_remote_object_disposed(
|
|||||||
|
|
||||||
/* Lock */
|
/* Lock */
|
||||||
g_mutex_lock(&priv->remote_objects_mutex);
|
g_mutex_lock(&priv->remote_objects_mutex);
|
||||||
if (obj->object.ref_count == 1 && priv->remote_objects) {
|
if (obj->object.ref_count == 1) {
|
||||||
void* key = GINT_TO_POINTER(obj->handle);
|
gbinder_ipc_invalidate_remote_handle_locked(priv, obj->handle);
|
||||||
|
|
||||||
GVERBOSE_("handle %u", obj->handle);
|
|
||||||
GASSERT(g_hash_table_contains(priv->remote_objects, key));
|
|
||||||
g_hash_table_remove(priv->remote_objects, key);
|
|
||||||
if (g_hash_table_size(priv->remote_objects) == 0) {
|
|
||||||
g_hash_table_unref(priv->remote_objects);
|
|
||||||
priv->remote_objects = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g_mutex_unlock(&priv->remote_objects_mutex);
|
g_mutex_unlock(&priv->remote_objects_mutex);
|
||||||
/* Unlock */
|
/* Unlock */
|
||||||
}
|
}
|
||||||
|
|
||||||
GBinderLocalObject*
|
void
|
||||||
gbinder_ipc_new_local_object(
|
gbinder_ipc_register_local_object(
|
||||||
GBinderIpc* self,
|
GBinderIpc* self,
|
||||||
const char* iface,
|
GBinderLocalObject* obj)
|
||||||
GBinderLocalTransactFunc txproc,
|
|
||||||
void* data)
|
|
||||||
{
|
{
|
||||||
GBinderIpcPriv* priv = self->priv;
|
GBinderIpcPriv* priv = self->priv;
|
||||||
GBinderLocalObject* obj = gbinder_local_object_new
|
|
||||||
(self, iface, txproc, data);
|
|
||||||
|
|
||||||
/* Lock */
|
/* Lock */
|
||||||
g_mutex_lock(&priv->local_objects_mutex);
|
g_mutex_lock(&priv->local_objects_mutex);
|
||||||
@@ -590,7 +1021,6 @@ gbinder_ipc_new_local_object(
|
|||||||
|
|
||||||
GVERBOSE_("%p", obj);
|
GVERBOSE_("%p", obj);
|
||||||
gbinder_ipc_looper_check(self);
|
gbinder_ipc_looper_check(self);
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -625,7 +1055,8 @@ static
|
|||||||
GBinderRemoteObject*
|
GBinderRemoteObject*
|
||||||
gbinder_ipc_priv_get_remote_object(
|
gbinder_ipc_priv_get_remote_object(
|
||||||
GBinderIpcPriv* priv,
|
GBinderIpcPriv* priv,
|
||||||
guint32 handle)
|
guint32 handle,
|
||||||
|
gboolean maybe_dead)
|
||||||
{
|
{
|
||||||
GBinderRemoteObject* obj = NULL;
|
GBinderRemoteObject* obj = NULL;
|
||||||
void* key = GINT_TO_POINTER(handle);
|
void* key = GINT_TO_POINTER(handle);
|
||||||
@@ -638,7 +1069,11 @@ gbinder_ipc_priv_get_remote_object(
|
|||||||
if (obj) {
|
if (obj) {
|
||||||
gbinder_remote_object_ref(obj);
|
gbinder_remote_object_ref(obj);
|
||||||
} else {
|
} else {
|
||||||
obj = gbinder_remote_object_new(priv->self, handle);
|
/*
|
||||||
|
* If maybe_dead is TRUE, the caller is supposed to try reanimating
|
||||||
|
* the object on the main thread not holding any global locks.
|
||||||
|
*/
|
||||||
|
obj = gbinder_remote_object_new(priv->self, handle, maybe_dead);
|
||||||
if (!priv->remote_objects) {
|
if (!priv->remote_objects) {
|
||||||
priv->remote_objects = g_hash_table_new
|
priv->remote_objects = g_hash_table_new
|
||||||
(g_direct_hash, g_direct_equal);
|
(g_direct_hash, g_direct_equal);
|
||||||
@@ -654,10 +1089,11 @@ gbinder_ipc_priv_get_remote_object(
|
|||||||
GBinderRemoteObject*
|
GBinderRemoteObject*
|
||||||
gbinder_ipc_get_remote_object(
|
gbinder_ipc_get_remote_object(
|
||||||
GBinderIpc* self,
|
GBinderIpc* self,
|
||||||
guint32 handle)
|
guint32 handle,
|
||||||
|
gboolean maybe_dead)
|
||||||
{
|
{
|
||||||
/* GBinderServiceManager makes sure that GBinderIpc pointer is not NULL */
|
/* GBinderServiceManager makes sure that GBinderIpc pointer is not NULL */
|
||||||
return gbinder_ipc_priv_get_remote_object(self->priv, handle);
|
return gbinder_ipc_priv_get_remote_object(self->priv, handle, maybe_dead);
|
||||||
}
|
}
|
||||||
|
|
||||||
GBINDER_INLINE_FUNC
|
GBINDER_INLINE_FUNC
|
||||||
@@ -709,7 +1145,7 @@ gbinder_ipc_object_registry_get_remote(
|
|||||||
guint32 handle)
|
guint32 handle)
|
||||||
{
|
{
|
||||||
return gbinder_ipc_priv_get_remote_object
|
return gbinder_ipc_priv_get_remote_object
|
||||||
(gbinder_ipc_priv_from_object_registry(reg), handle);
|
(gbinder_ipc_priv_from_object_registry(reg), handle, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
@@ -803,14 +1239,19 @@ gbinder_ipc_tx_internal_exec(
|
|||||||
GBinderObjectRegistry* reg = &self->priv->object_registry;
|
GBinderObjectRegistry* reg = &self->priv->object_registry;
|
||||||
|
|
||||||
/* Perform synchronous transaction */
|
/* Perform synchronous transaction */
|
||||||
tx->reply = gbinder_remote_reply_new(&self->priv->object_registry);
|
if (tx->flags & GBINDER_TX_FLAG_ONEWAY) {
|
||||||
tx->status = gbinder_driver_transact(self->driver, reg,
|
tx->status = gbinder_driver_transact(self->driver, reg, tx->handle,
|
||||||
tx->handle, tx->code, tx->req, tx->reply);
|
tx->code, tx->req, NULL);
|
||||||
if (tx->status != GBINDER_STATUS_OK &&
|
} else {
|
||||||
gbinder_remote_reply_is_empty(tx->reply)) {
|
tx->reply = gbinder_remote_reply_new(&self->priv->object_registry);
|
||||||
/* Drop useless reply */
|
tx->status = gbinder_driver_transact(self->driver, reg, tx->handle,
|
||||||
gbinder_remote_reply_unref(tx->reply);
|
tx->code, tx->req, tx->reply);
|
||||||
tx->reply = NULL;
|
if (tx->status != GBINDER_STATUS_OK &&
|
||||||
|
gbinder_remote_reply_is_empty(tx->reply)) {
|
||||||
|
/* Drop useless reply */
|
||||||
|
gbinder_remote_reply_unref(tx->reply);
|
||||||
|
tx->reply = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,7 +1422,8 @@ gbinder_ipc_tx_proc(
|
|||||||
|
|
||||||
GBinderIpc*
|
GBinderIpc*
|
||||||
gbinder_ipc_new(
|
gbinder_ipc_new(
|
||||||
const char* dev)
|
const char* dev,
|
||||||
|
const GBinderRpcProtocol* protocol)
|
||||||
{
|
{
|
||||||
GBinderIpc* self = NULL;
|
GBinderIpc* self = NULL;
|
||||||
|
|
||||||
@@ -994,7 +1436,7 @@ gbinder_ipc_new(
|
|||||||
if (self) {
|
if (self) {
|
||||||
gbinder_ipc_ref(self);
|
gbinder_ipc_ref(self);
|
||||||
} else {
|
} else {
|
||||||
GBinderDriver* driver = gbinder_driver_new(dev);
|
GBinderDriver* driver = gbinder_driver_new(dev, protocol);
|
||||||
|
|
||||||
if (driver) {
|
if (driver) {
|
||||||
GBinderIpcPriv* priv;
|
GBinderIpcPriv* priv;
|
||||||
@@ -1195,7 +1637,7 @@ gbinder_ipc_dispose(
|
|||||||
{
|
{
|
||||||
GBinderIpc* self = GBINDER_IPC(object);
|
GBinderIpc* self = GBINDER_IPC(object);
|
||||||
GBinderIpcPriv* priv = self->priv;
|
GBinderIpcPriv* priv = self->priv;
|
||||||
GBinderIpcLooper* looper;
|
GBinderIpcLooper* loopers = NULL;
|
||||||
|
|
||||||
GVERBOSE_("%s", self->dev);
|
GVERBOSE_("%s", self->dev);
|
||||||
/* Lock */
|
/* Lock */
|
||||||
@@ -1214,26 +1656,28 @@ gbinder_ipc_dispose(
|
|||||||
pthread_mutex_unlock(&gbinder_ipc_mutex);
|
pthread_mutex_unlock(&gbinder_ipc_mutex);
|
||||||
/* Unlock */
|
/* Unlock */
|
||||||
|
|
||||||
/* Lock */
|
do {
|
||||||
g_mutex_lock(&priv->looper_mutex);
|
GBinderIpcLooper* tmp;
|
||||||
looper = priv->looper;
|
|
||||||
priv->looper = NULL;
|
|
||||||
g_mutex_unlock(&priv->looper_mutex);
|
|
||||||
/* Unlock */
|
|
||||||
|
|
||||||
if (looper) {
|
/* Lock */
|
||||||
if (looper->thread && looper->thread != g_thread_self()) {
|
g_mutex_lock(&priv->looper_mutex);
|
||||||
guint8 done = TX_DONE;
|
loopers = gbinder_ipc_looper_stop_all(gbinder_ipc_looper_stop_all(NULL,
|
||||||
|
priv->primary_loopers), priv->blocked_loopers);
|
||||||
|
priv->blocked_loopers = NULL;
|
||||||
|
priv->primary_loopers = NULL;
|
||||||
|
g_mutex_unlock(&priv->looper_mutex);
|
||||||
|
/* Unlock */
|
||||||
|
|
||||||
GDEBUG("Stopping looper %s", gbinder_ipc_name(looper->ipc));
|
tmp = loopers;
|
||||||
if (write(looper->pipefd[1], &done, sizeof(done)) > 0) {
|
while (tmp) {
|
||||||
g_thread_join(looper->thread);
|
GBinderIpcLooper* looper = tmp;
|
||||||
looper->thread = NULL;
|
|
||||||
}
|
tmp = looper->next;
|
||||||
|
looper->next = NULL;
|
||||||
|
gbinder_ipc_looper_join(looper);
|
||||||
|
gbinder_ipc_looper_unref(looper);
|
||||||
}
|
}
|
||||||
looper->ipc = NULL;
|
} while (loopers);
|
||||||
gbinder_ipc_looper_unref(looper);
|
|
||||||
}
|
|
||||||
|
|
||||||
G_OBJECT_CLASS(gbinder_ipc_parent_class)->finalize(object);
|
G_OBJECT_CLASS(gbinder_ipc_parent_class)->finalize(object);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -70,7 +70,8 @@ void
|
|||||||
|
|
||||||
GBinderIpc*
|
GBinderIpc*
|
||||||
gbinder_ipc_new(
|
gbinder_ipc_new(
|
||||||
const char* dev);
|
const char* dev,
|
||||||
|
const GBinderRpcProtocol* protocol);
|
||||||
|
|
||||||
GBinderIpc*
|
GBinderIpc*
|
||||||
gbinder_ipc_ref(
|
gbinder_ipc_ref(
|
||||||
@@ -88,15 +89,19 @@ GBinderObjectRegistry*
|
|||||||
gbinder_ipc_object_registry(
|
gbinder_ipc_object_registry(
|
||||||
GBinderIpc* ipc);
|
GBinderIpc* ipc);
|
||||||
|
|
||||||
GBinderLocalObject*
|
void
|
||||||
gbinder_ipc_new_local_object(
|
gbinder_ipc_register_local_object(
|
||||||
GBinderIpc* ipc,
|
GBinderIpc* ipc,
|
||||||
const char* iface,
|
GBinderLocalObject* obj);
|
||||||
GBinderLocalTransactFunc txproc,
|
|
||||||
void* data);
|
|
||||||
|
|
||||||
GBinderRemoteObject*
|
GBinderRemoteObject*
|
||||||
gbinder_ipc_get_remote_object(
|
gbinder_ipc_get_remote_object(
|
||||||
|
GBinderIpc* ipc,
|
||||||
|
guint32 handle,
|
||||||
|
gboolean maybe_dead);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_ipc_invalidate_remote_handle(
|
||||||
GBinderIpc* ipc,
|
GBinderIpc* ipc,
|
||||||
guint32 handle);
|
guint32 handle);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -38,11 +38,13 @@
|
|||||||
#include "gbinder_writer.h"
|
#include "gbinder_writer.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
|
#include <gutil_strv.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
struct gbinder_local_object_priv {
|
struct gbinder_local_object_priv {
|
||||||
GMainContext* context;
|
GMainContext* context;
|
||||||
char* iface;
|
char** ifaces;
|
||||||
GBinderLocalTransactFunc txproc;
|
GBinderLocalTransactFunc txproc;
|
||||||
void* user_data;
|
void* user_data;
|
||||||
};
|
};
|
||||||
@@ -53,6 +55,13 @@ G_DEFINE_TYPE(GBinderLocalObject, gbinder_local_object, G_TYPE_OBJECT)
|
|||||||
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_LOCAL_OBJECT, \
|
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_LOCAL_OBJECT, \
|
||||||
GBinderLocalObjectClass)
|
GBinderLocalObjectClass)
|
||||||
|
|
||||||
|
typedef
|
||||||
|
GBinderLocalReply*
|
||||||
|
(*GBinderLocalObjectTxHandler)(
|
||||||
|
GBinderLocalObject* self,
|
||||||
|
GBinderRemoteRequest* req,
|
||||||
|
int* status);
|
||||||
|
|
||||||
enum gbinder_local_object_signal {
|
enum gbinder_local_object_signal {
|
||||||
SIGNAL_WEAK_REFS_CHANGED,
|
SIGNAL_WEAK_REFS_CHANGED,
|
||||||
SIGNAL_STRONG_REFS_CHANGED,
|
SIGNAL_STRONG_REFS_CHANGED,
|
||||||
@@ -78,6 +87,9 @@ gbinder_local_object_default_can_handle_transaction(
|
|||||||
guint code)
|
guint code)
|
||||||
{
|
{
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
case GBINDER_PING_TRANSACTION:
|
||||||
|
case GBINDER_INTERFACE_TRANSACTION:
|
||||||
|
return GBINDER_LOCAL_TRANSACTION_LOOPER;
|
||||||
case HIDL_PING_TRANSACTION:
|
case HIDL_PING_TRANSACTION:
|
||||||
case HIDL_GET_DESCRIPTOR_TRANSACTION:
|
case HIDL_GET_DESCRIPTOR_TRANSACTION:
|
||||||
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
|
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
|
||||||
@@ -110,6 +122,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
|
static
|
||||||
GBinderLocalReply*
|
GBinderLocalReply*
|
||||||
gbinder_local_object_hidl_ping_transaction(
|
gbinder_local_object_hidl_ping_transaction(
|
||||||
@@ -120,12 +165,10 @@ gbinder_local_object_hidl_ping_transaction(
|
|||||||
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
|
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
|
||||||
const GBinderIo* io = gbinder_local_object_io(self);
|
const GBinderIo* io = gbinder_local_object_io(self);
|
||||||
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
||||||
GBinderWriter writer;
|
|
||||||
|
|
||||||
GVERBOSE(" HIDL_PING_TRANSACTION \"%s\"",
|
GVERBOSE(" HIDL_PING_TRANSACTION \"%s\"",
|
||||||
gbinder_remote_request_interface(req));
|
gbinder_remote_request_interface(req));
|
||||||
gbinder_local_reply_init_writer(reply, &writer);
|
gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK);
|
||||||
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
|
|
||||||
*status = GBINDER_STATUS_OK;
|
*status = GBINDER_STATUS_OK;
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
@@ -139,6 +182,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
|
|||||||
{
|
{
|
||||||
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
|
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
|
||||||
const GBinderIo* io = gbinder_local_object_io(self);
|
const GBinderIo* io = gbinder_local_object_io(self);
|
||||||
|
GBinderLocalObjectPriv* priv = self->priv;
|
||||||
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
||||||
GBinderWriter writer;
|
GBinderWriter writer;
|
||||||
|
|
||||||
@@ -146,8 +190,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
|
|||||||
gbinder_remote_request_interface(req));
|
gbinder_remote_request_interface(req));
|
||||||
gbinder_local_reply_init_writer(reply, &writer);
|
gbinder_local_reply_init_writer(reply, &writer);
|
||||||
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
|
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
|
||||||
gbinder_writer_append_hidl_string(&writer, self->iface ? self->iface :
|
gbinder_writer_append_hidl_string(&writer, priv->ifaces[0]);
|
||||||
hidl_base_interface);
|
|
||||||
*status = GBINDER_STATUS_OK;
|
*status = GBINDER_STATUS_OK;
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
@@ -163,17 +206,14 @@ gbinder_local_object_hidl_descriptor_chain_transaction(
|
|||||||
const GBinderIo* io = gbinder_local_object_io(self);
|
const GBinderIo* io = gbinder_local_object_io(self);
|
||||||
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
GBinderLocalReply* reply = gbinder_local_reply_new(io);
|
||||||
GBinderWriter writer;
|
GBinderWriter writer;
|
||||||
const char* chain[2];
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
GVERBOSE(" HIDL_DESCRIPTOR_CHAIN_TRANSACTION \"%s\"",
|
GVERBOSE(" HIDL_DESCRIPTOR_CHAIN_TRANSACTION \"%s\"",
|
||||||
gbinder_remote_request_interface(req));
|
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_local_reply_init_writer(reply, &writer);
|
||||||
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
|
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;
|
*status = GBINDER_STATUS_OK;
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
@@ -187,23 +227,31 @@ gbinder_local_object_default_handle_looper_transaction(
|
|||||||
guint flags,
|
guint flags,
|
||||||
int* status)
|
int* status)
|
||||||
{
|
{
|
||||||
|
GBinderLocalObjectTxHandler handler = NULL;
|
||||||
|
|
||||||
switch (code) {
|
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:
|
case HIDL_PING_TRANSACTION:
|
||||||
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
|
handler = gbinder_local_object_hidl_ping_transaction;
|
||||||
return gbinder_local_object_hidl_ping_transaction
|
break;
|
||||||
(self, req, status);
|
|
||||||
case HIDL_GET_DESCRIPTOR_TRANSACTION:
|
case HIDL_GET_DESCRIPTOR_TRANSACTION:
|
||||||
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
|
handler = gbinder_local_object_hidl_get_descriptor_transaction;
|
||||||
return gbinder_local_object_hidl_get_descriptor_transaction
|
break;
|
||||||
(self, req, status);
|
|
||||||
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
|
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
|
||||||
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
|
handler = gbinder_local_object_hidl_descriptor_chain_transaction;
|
||||||
return gbinder_local_object_hidl_descriptor_chain_transaction
|
break;
|
||||||
(self, req, status);
|
|
||||||
default:
|
default:
|
||||||
if (status) *status = (-EBADMSG);
|
if (status) *status = (-EBADMSG);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
|
||||||
|
return handler(self, req, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -271,6 +319,7 @@ gbinder_local_object_handle_release_proc(
|
|||||||
self->strong_refs--;
|
self->strong_refs--;
|
||||||
g_signal_emit(self, gbinder_local_object_signals
|
g_signal_emit(self, gbinder_local_object_signals
|
||||||
[SIGNAL_STRONG_REFS_CHANGED], 0);
|
[SIGNAL_STRONG_REFS_CHANGED], 0);
|
||||||
|
gbinder_local_object_unref(self);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,20 +330,40 @@ gbinder_local_object_handle_release_proc(
|
|||||||
GBinderLocalObject*
|
GBinderLocalObject*
|
||||||
gbinder_local_object_new(
|
gbinder_local_object_new(
|
||||||
GBinderIpc* ipc,
|
GBinderIpc* ipc,
|
||||||
const char* iface,
|
const char* const* ifaces,
|
||||||
GBinderLocalTransactFunc txproc,
|
GBinderLocalTransactFunc txproc,
|
||||||
void* user_data)
|
void* user_data) /* Since 1.0.30 */
|
||||||
{
|
{
|
||||||
/* Should only be called from gbinder_ipc_new_local_local_object() */
|
|
||||||
if (G_LIKELY(ipc)) {
|
if (G_LIKELY(ipc)) {
|
||||||
GBinderLocalObject* self = g_object_new
|
GBinderLocalObject* self = g_object_new
|
||||||
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
|
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
|
||||||
GBinderLocalObjectPriv* priv = self->priv;
|
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->ipc = gbinder_ipc_ref(ipc);
|
||||||
self->iface = priv->iface = g_strdup(iface);
|
self->ifaces = (const char**)priv->ifaces;
|
||||||
priv->txproc = txproc;
|
priv->txproc = txproc;
|
||||||
priv->user_data = user_data;
|
priv->user_data = user_data;
|
||||||
|
gbinder_ipc_register_local_object(ipc, self);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -440,6 +509,7 @@ void
|
|||||||
gbinder_local_object_handle_acquire(
|
gbinder_local_object_handle_acquire(
|
||||||
GBinderLocalObject* self)
|
GBinderLocalObject* self)
|
||||||
{
|
{
|
||||||
|
gbinder_local_object_ref(self);
|
||||||
gbinder_local_object_handle_later(self,
|
gbinder_local_object_handle_later(self,
|
||||||
gbinder_local_object_handle_acquire_proc);
|
gbinder_local_object_handle_acquire_proc);
|
||||||
}
|
}
|
||||||
@@ -487,8 +557,9 @@ gbinder_local_object_finalize(
|
|||||||
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
|
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
|
||||||
GBinderLocalObjectPriv* priv = self->priv;
|
GBinderLocalObjectPriv* priv = self->priv;
|
||||||
|
|
||||||
|
GASSERT(!self->strong_refs);
|
||||||
gbinder_ipc_unref(self->ipc);
|
gbinder_ipc_unref(self->ipc);
|
||||||
g_free(priv->iface);
|
g_strfreev(priv->ifaces);
|
||||||
G_OBJECT_CLASS(gbinder_local_object_parent_class)->finalize(local);
|
G_OBJECT_CLASS(gbinder_local_object_parent_class)->finalize(local);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -55,7 +55,7 @@ struct gbinder_local_object {
|
|||||||
GObject object;
|
GObject object;
|
||||||
GBinderLocalObjectPriv* priv;
|
GBinderLocalObjectPriv* priv;
|
||||||
GBinderIpc* ipc;
|
GBinderIpc* ipc;
|
||||||
const char* iface;
|
const char* const* ifaces;
|
||||||
gint weak_refs;
|
gint weak_refs;
|
||||||
gint strong_refs;
|
gint strong_refs;
|
||||||
};
|
};
|
||||||
@@ -87,14 +87,6 @@ GType gbinder_local_object_get_type(void);
|
|||||||
#define gbinder_local_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
|
#define gbinder_local_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
|
||||||
#define gbinder_local_object_io(obj) (gbinder_driver_io((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(
|
|
||||||
GBinderIpc* ipc,
|
|
||||||
const char* iface,
|
|
||||||
GBinderLocalTransactFunc handler,
|
|
||||||
void* user_data);
|
|
||||||
|
|
||||||
gulong
|
gulong
|
||||||
gbinder_local_object_add_weak_refs_changed_handler(
|
gbinder_local_object_add_weak_refs_changed_handler(
|
||||||
GBinderLocalObject* obj,
|
GBinderLocalObject* obj,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "gbinder_local_reply_p.h"
|
#include "gbinder_local_reply_p.h"
|
||||||
#include "gbinder_output_data.h"
|
#include "gbinder_output_data.h"
|
||||||
#include "gbinder_writer_p.h"
|
#include "gbinder_writer_p.h"
|
||||||
|
#include "gbinder_buffer_p.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
#include <gutil_intarray.h>
|
#include <gutil_intarray.h>
|
||||||
@@ -92,6 +93,19 @@ gbinder_local_reply_new(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GBinderLocalReply*
|
||||||
|
gbinder_local_reply_new_from_data(
|
||||||
|
GBinderBuffer* buffer)
|
||||||
|
{
|
||||||
|
const GBinderIo* io = gbinder_buffer_io(buffer);
|
||||||
|
GBinderLocalReply* self = gbinder_local_reply_new(io);
|
||||||
|
|
||||||
|
if (self) {
|
||||||
|
gbinder_writer_data_set_contents(&self->data, buffer);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
gbinder_local_reply_free(
|
gbinder_local_reply_free(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -45,6 +45,10 @@ GBinderOutputData*
|
|||||||
gbinder_local_reply_data(
|
gbinder_local_reply_data(
|
||||||
GBinderLocalReply* reply);
|
GBinderLocalReply* reply);
|
||||||
|
|
||||||
|
GBinderLocalReply*
|
||||||
|
gbinder_local_reply_new_from_data(
|
||||||
|
GBinderBuffer* buffer);
|
||||||
|
|
||||||
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */
|
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -33,6 +33,8 @@
|
|||||||
#include "gbinder_local_request_p.h"
|
#include "gbinder_local_request_p.h"
|
||||||
#include "gbinder_output_data.h"
|
#include "gbinder_output_data.h"
|
||||||
#include "gbinder_writer_p.h"
|
#include "gbinder_writer_p.h"
|
||||||
|
#include "gbinder_buffer_p.h"
|
||||||
|
#include "gbinder_io.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
#include <gutil_intarray.h>
|
#include <gutil_intarray.h>
|
||||||
@@ -101,6 +103,19 @@ gbinder_local_request_new(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GBinderLocalRequest*
|
||||||
|
gbinder_local_request_new_from_data(
|
||||||
|
GBinderBuffer* buffer)
|
||||||
|
{
|
||||||
|
GBinderLocalRequest* self = gbinder_local_request_new
|
||||||
|
(gbinder_buffer_io(buffer), NULL);
|
||||||
|
|
||||||
|
if (self) {
|
||||||
|
gbinder_writer_data_set_contents(&self->data, buffer);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
gbinder_local_request_free(
|
gbinder_local_request_free(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -46,6 +46,10 @@ GBinderOutputData*
|
|||||||
gbinder_local_request_data(
|
gbinder_local_request_data(
|
||||||
GBinderLocalRequest* req);
|
GBinderLocalRequest* req);
|
||||||
|
|
||||||
|
GBinderLocalRequest*
|
||||||
|
gbinder_local_request_new_from_data(
|
||||||
|
GBinderBuffer* buffer);
|
||||||
|
|
||||||
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */
|
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -38,6 +38,9 @@
|
|||||||
|
|
||||||
#include <gutil_macros.h>
|
#include <gutil_macros.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
typedef struct gbinder_reader_priv {
|
typedef struct gbinder_reader_priv {
|
||||||
const guint8* start;
|
const guint8* start;
|
||||||
const guint8* end;
|
const guint8* end;
|
||||||
@@ -50,6 +53,8 @@ G_STATIC_ASSERT(sizeof(GBinderReader) >= sizeof(GBinderReaderPriv));
|
|||||||
|
|
||||||
static inline GBinderReaderPriv* gbinder_reader_cast(GBinderReader* reader)
|
static inline GBinderReaderPriv* gbinder_reader_cast(GBinderReader* reader)
|
||||||
{ return (GBinderReaderPriv*)reader; }
|
{ return (GBinderReaderPriv*)reader; }
|
||||||
|
static inline const GBinderReaderPriv* gbinder_reader_cast_c
|
||||||
|
(const GBinderReader* reader) { return (GBinderReaderPriv*)reader; }
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_reader_init(
|
gbinder_reader_init(
|
||||||
@@ -81,9 +86,9 @@ gbinder_reader_init(
|
|||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_reader_at_end(
|
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;
|
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
|
gboolean
|
||||||
gbinder_reader_read_nullable_object(
|
gbinder_reader_read_nullable_object(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
GBinderRemoteObject** out)
|
GBinderRemoteObject** out)
|
||||||
{
|
{
|
||||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||||
const GBinderReaderData* data = p->data;
|
|
||||||
|
|
||||||
if (data && data->reg && p->objects && p->objects[0] &&
|
if (gbinder_reader_can_read_object(p)) {
|
||||||
p->ptr == p->objects[0]) {
|
const GBinderReaderData* data = p->data;
|
||||||
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
|
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
|
||||||
gbinder_reader_bytes_remaining(reader), data->reg, out);
|
gbinder_reader_bytes_remaining(reader), data->reg, out);
|
||||||
|
|
||||||
@@ -264,15 +320,14 @@ gbinder_reader_read_object(
|
|||||||
|
|
||||||
static
|
static
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_reader_read_buffer_impl(
|
gbinder_reader_read_buffer_object(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
GBinderBuffer** out)
|
GBinderIoBufferObject* out)
|
||||||
{
|
{
|
||||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||||
const GBinderReaderData* data = p->data;
|
|
||||||
|
|
||||||
if (data && data->reg && p->objects && p->objects[0] &&
|
if (gbinder_reader_can_read_object(p)) {
|
||||||
p->ptr == p->objects[0]) {
|
const GBinderReaderData* data = p->data;
|
||||||
GBinderBuffer* buf = data->buffer;
|
GBinderBuffer* buf = data->buffer;
|
||||||
const GBinderIo* io = data->reg->io;
|
const GBinderIo* io = data->reg->io;
|
||||||
const gsize offset = p->ptr - (guint8*)buf->data;
|
const gsize offset = p->ptr - (guint8*)buf->data;
|
||||||
@@ -284,7 +339,6 @@ gbinder_reader_read_buffer_impl(
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out) *out = NULL;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,101 +346,178 @@ GBinderBuffer*
|
|||||||
gbinder_reader_read_buffer(
|
gbinder_reader_read_buffer(
|
||||||
GBinderReader* reader)
|
GBinderReader* reader)
|
||||||
{
|
{
|
||||||
GBinderBuffer* buf = NULL;
|
GBinderIoBufferObject obj;
|
||||||
|
|
||||||
gbinder_reader_read_buffer_impl(reader, &buf);
|
if (gbinder_reader_read_buffer_object(reader, &obj)) {
|
||||||
return buf;
|
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
|
gboolean
|
||||||
gbinder_reader_skip_buffer(
|
gbinder_reader_skip_buffer(
|
||||||
GBinderReader* reader)
|
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*
|
char*
|
||||||
gbinder_reader_read_hidl_string(
|
gbinder_reader_read_hidl_string(
|
||||||
GBinderReader* reader)
|
GBinderReader* reader)
|
||||||
{
|
{
|
||||||
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
|
/* This function should've been called gbinder_reader_dup_hidl_string */
|
||||||
char* str = NULL;
|
return g_strdup(gbinder_reader_read_hidl_string_c(reader));
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char**
|
char**
|
||||||
gbinder_reader_read_hidl_string_vec(
|
gbinder_reader_read_hidl_string_vec(
|
||||||
GBinderReader* reader)
|
GBinderReader* reader)
|
||||||
{
|
{
|
||||||
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
|
GBinderIoBufferObject obj;
|
||||||
|
|
||||||
/* First buffer contains hidl_vector */
|
/* First buffer contains hidl_vector */
|
||||||
if (buf && buf->size == sizeof(HidlVec)) {
|
if (gbinder_reader_read_buffer_object(reader, &obj) &&
|
||||||
HidlVec* vec = buf->data;
|
obj.data && obj.size == sizeof(GBinderHidlVec)) {
|
||||||
|
GBinderHidlVec* vec = obj.data;
|
||||||
const guint n = vec->count;
|
const guint n = vec->count;
|
||||||
const void* next = vec->data.ptr;
|
const void* next = vec->data.ptr;
|
||||||
|
|
||||||
gbinder_buffer_free(buf);
|
|
||||||
if (!next && !n) {
|
if (!next && !n) {
|
||||||
char** out = g_new(char*, 1);
|
/* 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 */
|
||||||
|
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;
|
||||||
|
|
||||||
out[0] = NULL;
|
/* Now we expect n buffers containing the actual data */
|
||||||
return out;
|
for (i = 0; i < n &&
|
||||||
} else {
|
gbinder_reader_read_buffer_object(reader, &obj); i++) {
|
||||||
/* The second buffer (if any) contains n hidl_string's */
|
const GBinderHidlString* s = strings + i;
|
||||||
buf = gbinder_reader_read_buffer(reader);
|
const gsize expected_offset = (i * sizeof(*s)) +
|
||||||
if (buf && buf->data == next && buf->size == sizeof(HidlString)*n) {
|
GBINDER_HIDL_STRING_BUFFER_OFFSET;
|
||||||
const HidlString* strings = buf->data;
|
if (obj.has_parent &&
|
||||||
GBinderBuffer* sbuf;
|
obj.parent_offset == expected_offset &&
|
||||||
GPtrArray* list = g_ptr_array_new();
|
obj.data == s->data.str &&
|
||||||
guint i;
|
obj.size == s->len + 1 &&
|
||||||
|
s->data.str[s->len] == 0) {
|
||||||
|
char* name = g_strdup(s->data.str);
|
||||||
|
|
||||||
/* Now we expect n buffers containing the actual data */
|
g_ptr_array_add(list, name);
|
||||||
for (i=0; i<n &&
|
GVERBOSE_("%u. %s", i + 1, name);
|
||||||
(sbuf = gbinder_reader_read_buffer(reader)); i++) {
|
} else {
|
||||||
const HidlString* s = strings + i;
|
GWARN("Unexpected hidl_string buffer %p/%u vs %p/%u",
|
||||||
if (sbuf->size == s->len + 1 &&
|
obj.data, (guint)obj.size, s->data.str, s->len);
|
||||||
sbuf->data == s->data.str &&
|
break;
|
||||||
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);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == n) {
|
|
||||||
gbinder_buffer_free(buf);
|
|
||||||
g_ptr_array_add(list, NULL);
|
|
||||||
return (char**)g_ptr_array_free(list, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_ptr_array_set_free_func(list, g_free);
|
|
||||||
g_ptr_array_free(list, TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i == n) {
|
||||||
|
g_ptr_array_add(list, NULL);
|
||||||
|
return (char**)g_ptr_array_free(list, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_set_free_func(list, g_free);
|
||||||
|
g_ptr_array_free(list, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GWARN("Invalid hidl_vec<string>");
|
GWARN("Invalid hidl_vec<string>");
|
||||||
gbinder_buffer_free(buf);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,6 +549,24 @@ gboolean
|
|||||||
gbinder_reader_read_nullable_string16(
|
gbinder_reader_read_nullable_string16(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
char** out)
|
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);
|
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
||||||
|
|
||||||
@@ -431,15 +580,21 @@ gbinder_reader_read_nullable_string16(
|
|||||||
if (out) {
|
if (out) {
|
||||||
*out = NULL;
|
*out = NULL;
|
||||||
}
|
}
|
||||||
|
if (out_len) {
|
||||||
|
*out_len = 0;
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else if (len >= 0) {
|
} else if (len >= 0) {
|
||||||
const guint32 padded_len = G_ALIGN4((len+1)*2);
|
const guint32 padded_len = G_ALIGN4((len + 1)*2);
|
||||||
const gunichar2* utf16 = (const gunichar2*)(p->ptr + 4);
|
const gunichar2* utf16 = (gunichar2*)(p->ptr + 4);
|
||||||
|
|
||||||
if ((p->ptr + padded_len + 4) <= p->end) {
|
if ((p->ptr + padded_len + 4) <= p->end) {
|
||||||
p->ptr += padded_len + 4;
|
p->ptr += padded_len + 4;
|
||||||
if (out) {
|
if (out) {
|
||||||
*out = g_utf16_to_utf8(utf16, len, NULL, NULL, NULL);
|
*out = utf16;
|
||||||
|
}
|
||||||
|
if (out_len) {
|
||||||
|
*out_len = len;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -448,6 +603,21 @@ gbinder_reader_read_nullable_string16(
|
|||||||
return FALSE;
|
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*
|
char*
|
||||||
gbinder_reader_read_string16(
|
gbinder_reader_read_string16(
|
||||||
GBinderReader* reader)
|
GBinderReader* reader)
|
||||||
@@ -484,24 +654,59 @@ gbinder_reader_skip_string16(
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gsize
|
const void*
|
||||||
gbinder_reader_bytes_read(
|
gbinder_reader_read_byte_array(
|
||||||
GBinderReader* reader)
|
GBinderReader* reader,
|
||||||
|
gsize* len) /* Since 1.0.12 */
|
||||||
{
|
{
|
||||||
GBinderReaderPriv* p = gbinder_reader_cast(reader);
|
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;
|
return p->ptr - p->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
gsize
|
gsize
|
||||||
gbinder_reader_bytes_remaining(
|
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;
|
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:
|
* Local Variables:
|
||||||
* mode: C
|
* mode: C
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "gbinder_driver.h"
|
#include "gbinder_driver.h"
|
||||||
#include "gbinder_ipc.h"
|
#include "gbinder_ipc.h"
|
||||||
#include "gbinder_remote_object_p.h"
|
#include "gbinder_remote_object_p.h"
|
||||||
|
#include "gbinder_servicemanager_p.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
struct gbinder_remote_object_priv {
|
struct gbinder_remote_object_priv {
|
||||||
@@ -65,9 +66,20 @@ void
|
|||||||
gbinder_remote_object_died_on_main_thread(
|
gbinder_remote_object_died_on_main_thread(
|
||||||
GBinderRemoteObject* self)
|
GBinderRemoteObject* self)
|
||||||
{
|
{
|
||||||
|
GBinderIpc* ipc = self->ipc;
|
||||||
|
GBinderDriver* driver = ipc->driver;
|
||||||
|
|
||||||
GASSERT(!self->dead);
|
GASSERT(!self->dead);
|
||||||
self->dead = TRUE;
|
if (!self->dead) {
|
||||||
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
|
self->dead = TRUE;
|
||||||
|
/* ServiceManager always has the same handle, and can be reanimated. */
|
||||||
|
if (self->handle != GBINDER_SERVICEMANAGER_HANDLE) {
|
||||||
|
gbinder_ipc_invalidate_remote_handle(self->ipc, self->handle);
|
||||||
|
}
|
||||||
|
gbinder_driver_clear_death_notification(driver, self);
|
||||||
|
gbinder_driver_release(driver, self->handle);
|
||||||
|
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -79,6 +91,47 @@ gbinder_remote_object_died_handle(
|
|||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* Internal interface
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gbinder_remote_object_reanimate(
|
||||||
|
GBinderRemoteObject* self)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
|
||||||
|
/* Kick the horse */
|
||||||
|
GASSERT(self->handle == GBINDER_SERVICEMANAGER_HANDLE);
|
||||||
|
if (gbinder_driver_ping(ipc->driver, reg, self->handle) == 0) {
|
||||||
|
/* Wow, it's alive! */
|
||||||
|
self->dead = FALSE;
|
||||||
|
gbinder_driver_acquire(ipc->driver, self->handle);
|
||||||
|
gbinder_driver_request_death_notification(ipc->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);
|
||||||
|
g_main_context_invoke_full(self->priv->context, G_PRIORITY_DEFAULT,
|
||||||
|
gbinder_remote_object_died_handle, gbinder_remote_object_ref(self),
|
||||||
|
g_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* Interface
|
* Interface
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -86,15 +139,19 @@ gbinder_remote_object_died_handle(
|
|||||||
GBinderRemoteObject*
|
GBinderRemoteObject*
|
||||||
gbinder_remote_object_new(
|
gbinder_remote_object_new(
|
||||||
GBinderIpc* ipc,
|
GBinderIpc* ipc,
|
||||||
guint32 handle)
|
guint32 handle,
|
||||||
|
gboolean dead)
|
||||||
{
|
{
|
||||||
if (G_LIKELY(ipc) && gbinder_driver_acquire(ipc->driver, handle)) {
|
if (G_LIKELY(ipc)) {
|
||||||
GBinderRemoteObject* self = g_object_new
|
GBinderRemoteObject* self = g_object_new
|
||||||
(GBINDER_TYPE_REMOTE_OBJECT, NULL);
|
(GBINDER_TYPE_REMOTE_OBJECT, NULL);
|
||||||
|
|
||||||
self->ipc = gbinder_ipc_ref(ipc);
|
self->ipc = gbinder_ipc_ref(ipc);
|
||||||
self->handle = handle;
|
self->handle = handle;
|
||||||
gbinder_driver_request_death_notification(ipc->driver, self);
|
if (!(self->dead = dead)) {
|
||||||
|
gbinder_driver_acquire(ipc->driver, handle);
|
||||||
|
gbinder_driver_request_death_notification(ipc->driver, self);
|
||||||
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -121,6 +178,13 @@ gbinder_remote_object_unref(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GBinderIpc*
|
||||||
|
gbinder_remote_object_ipc(
|
||||||
|
GBinderRemoteObject* self) /* Since 1.0.30 */
|
||||||
|
{
|
||||||
|
return G_LIKELY(self) ? self->ipc : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_remote_object_is_dead(
|
gbinder_remote_object_is_dead(
|
||||||
GBinderRemoteObject* self)
|
GBinderRemoteObject* self)
|
||||||
@@ -152,18 +216,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
|
* Internals
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -200,8 +252,10 @@ gbinder_remote_object_finalize(
|
|||||||
GBinderIpc* ipc = self->ipc;
|
GBinderIpc* ipc = self->ipc;
|
||||||
GBinderDriver* driver = ipc->driver;
|
GBinderDriver* driver = ipc->driver;
|
||||||
|
|
||||||
gbinder_driver_clear_death_notification(driver, self);
|
if (!self->dead) {
|
||||||
gbinder_driver_release(driver, self->handle);
|
gbinder_driver_clear_death_notification(driver, self);
|
||||||
|
gbinder_driver_release(driver, self->handle);
|
||||||
|
}
|
||||||
gbinder_ipc_unref(ipc);
|
gbinder_ipc_unref(ipc);
|
||||||
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->finalize(remote);
|
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->finalize(remote);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -54,7 +54,12 @@ struct gbinder_remote_object {
|
|||||||
GBinderRemoteObject*
|
GBinderRemoteObject*
|
||||||
gbinder_remote_object_new(
|
gbinder_remote_object_new(
|
||||||
GBinderIpc* ipc,
|
GBinderIpc* ipc,
|
||||||
guint32 handle);
|
guint32 handle,
|
||||||
|
gboolean maybe_dead);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gbinder_remote_object_reanimate(
|
||||||
|
GBinderRemoteObject* obj);
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_remote_object_handle_death_notification(
|
gbinder_remote_object_handle_death_notification(
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -31,9 +31,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gbinder_remote_reply_p.h"
|
#include "gbinder_remote_reply_p.h"
|
||||||
|
#include "gbinder_local_reply_p.h"
|
||||||
#include "gbinder_reader_p.h"
|
#include "gbinder_reader_p.h"
|
||||||
#include "gbinder_object_registry.h"
|
#include "gbinder_object_registry.h"
|
||||||
#include "gbinder_buffer.h"
|
#include "gbinder_buffer_p.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
#include <gutil_macros.h>
|
#include <gutil_macros.h>
|
||||||
@@ -64,26 +65,22 @@ gbinder_remote_reply_free(
|
|||||||
|
|
||||||
gbinder_object_registry_unref(data->reg);
|
gbinder_object_registry_unref(data->reg);
|
||||||
gbinder_buffer_free(data->buffer);
|
gbinder_buffer_free(data->buffer);
|
||||||
g_free(data->objects);
|
|
||||||
g_slice_free(GBinderRemoteReply, self);
|
g_slice_free(GBinderRemoteReply, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_remote_reply_set_data(
|
gbinder_remote_reply_set_data(
|
||||||
GBinderRemoteReply* self,
|
GBinderRemoteReply* self,
|
||||||
GBinderBuffer* buffer,
|
GBinderBuffer* buffer)
|
||||||
void** objects)
|
|
||||||
{
|
{
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderReaderData* data = &self->data;
|
GBinderReaderData* data = &self->data;
|
||||||
|
|
||||||
g_free(data->objects);
|
|
||||||
gbinder_buffer_free(data->buffer);
|
gbinder_buffer_free(data->buffer);
|
||||||
data->buffer = buffer;
|
data->buffer = buffer;
|
||||||
data->objects = objects;
|
data->objects = gbinder_buffer_objects(buffer);
|
||||||
} else {
|
} else {
|
||||||
gbinder_buffer_free(buffer);
|
gbinder_buffer_free(buffer);
|
||||||
g_free(objects);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +114,18 @@ gbinder_remote_reply_is_empty(
|
|||||||
return !self || !self->data.buffer || !self->data.buffer->size;
|
return !self || !self->data.buffer || !self->data.buffer->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GBinderLocalReply*
|
||||||
|
gbinder_remote_reply_copy_to_local(
|
||||||
|
GBinderRemoteReply* self)
|
||||||
|
{
|
||||||
|
if (G_LIKELY(self)) {
|
||||||
|
GBinderReaderData* d = &self->data;
|
||||||
|
|
||||||
|
return gbinder_local_reply_new_from_data(d->buffer);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -44,8 +44,7 @@ gbinder_remote_reply_new(
|
|||||||
void
|
void
|
||||||
gbinder_remote_reply_set_data(
|
gbinder_remote_reply_set_data(
|
||||||
GBinderRemoteReply* reply,
|
GBinderRemoteReply* reply,
|
||||||
GBinderBuffer* buffer,
|
GBinderBuffer* buffer);
|
||||||
void** objects);
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_remote_reply_is_empty(
|
gbinder_remote_reply_is_empty(
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -33,13 +33,17 @@
|
|||||||
#include "gbinder_remote_request_p.h"
|
#include "gbinder_remote_request_p.h"
|
||||||
#include "gbinder_reader_p.h"
|
#include "gbinder_reader_p.h"
|
||||||
#include "gbinder_rpc_protocol.h"
|
#include "gbinder_rpc_protocol.h"
|
||||||
|
#include "gbinder_local_request_p.h"
|
||||||
#include "gbinder_object_registry.h"
|
#include "gbinder_object_registry.h"
|
||||||
#include "gbinder_buffer.h"
|
#include "gbinder_buffer_p.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
#include <gutil_macros.h>
|
#include <gutil_macros.h>
|
||||||
|
|
||||||
struct gbinder_remote_request {
|
#include <errno.h>
|
||||||
|
|
||||||
|
typedef struct gbinder_remote_request_priv {
|
||||||
|
GBinderRemoteRequest pub;
|
||||||
gint refcount;
|
gint refcount;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
uid_t euid;
|
uid_t euid;
|
||||||
@@ -48,7 +52,11 @@ struct gbinder_remote_request {
|
|||||||
char* iface2;
|
char* iface2;
|
||||||
gsize header_size;
|
gsize header_size;
|
||||||
GBinderReaderData data;
|
GBinderReaderData data;
|
||||||
};
|
} GBinderRemoteRequestPriv;
|
||||||
|
|
||||||
|
GBINDER_INLINE_FUNC GBinderRemoteRequestPriv*
|
||||||
|
gbinder_remote_request_cast(GBinderRemoteRequest* pub)
|
||||||
|
{ return G_LIKELY(pub) ? G_CAST(pub,GBinderRemoteRequestPriv,pub) : NULL; }
|
||||||
|
|
||||||
GBinderRemoteRequest*
|
GBinderRemoteRequest*
|
||||||
gbinder_remote_request_new(
|
gbinder_remote_request_new(
|
||||||
@@ -57,7 +65,7 @@ gbinder_remote_request_new(
|
|||||||
pid_t pid,
|
pid_t pid,
|
||||||
uid_t euid)
|
uid_t euid)
|
||||||
{
|
{
|
||||||
GBinderRemoteRequest* self = g_slice_new0(GBinderRemoteRequest);
|
GBinderRemoteRequestPriv* self = g_slice_new0(GBinderRemoteRequestPriv);
|
||||||
GBinderReaderData* data = &self->data;
|
GBinderReaderData* data = &self->data;
|
||||||
|
|
||||||
g_atomic_int_set(&self->refcount, 1);
|
g_atomic_int_set(&self->refcount, 1);
|
||||||
@@ -65,28 +73,47 @@ gbinder_remote_request_new(
|
|||||||
self->euid = euid;
|
self->euid = euid;
|
||||||
self->protocol = protocol;
|
self->protocol = protocol;
|
||||||
data->reg = gbinder_object_registry_ref(reg);
|
data->reg = gbinder_object_registry_ref(reg);
|
||||||
return self;
|
return &self->pub;
|
||||||
|
}
|
||||||
|
|
||||||
|
GBinderLocalRequest*
|
||||||
|
gbinder_remote_request_copy_to_local(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
gbinder_remote_request_free(
|
gbinder_remote_request_free(
|
||||||
GBinderRemoteRequest* self)
|
GBinderRemoteRequestPriv* self)
|
||||||
{
|
{
|
||||||
GBinderReaderData* data = &self->data;
|
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_object_registry_unref(data->reg);
|
||||||
gbinder_buffer_free(data->buffer);
|
gbinder_buffer_free(data->buffer);
|
||||||
g_free(data->objects);
|
|
||||||
g_free(self->iface2);
|
g_free(self->iface2);
|
||||||
g_slice_free(GBinderRemoteRequest, self);
|
g_slice_free(GBinderRemoteRequestPriv, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
gbinder_remote_request_init_reader2(
|
gbinder_remote_request_init_reader2(
|
||||||
GBinderRemoteRequest* self,
|
GBinderRemoteRequestPriv* self,
|
||||||
GBinderReader* p)
|
GBinderReader* p)
|
||||||
{
|
{
|
||||||
/* The caller has already checked the request for NULL */
|
/* The caller has already checked the request for NULL */
|
||||||
@@ -103,53 +130,64 @@ gbinder_remote_request_init_reader2(
|
|||||||
|
|
||||||
void
|
void
|
||||||
gbinder_remote_request_set_data(
|
gbinder_remote_request_set_data(
|
||||||
GBinderRemoteRequest* self,
|
GBinderRemoteRequest* req,
|
||||||
GBinderBuffer* buffer,
|
guint32 txcode,
|
||||||
void** objects)
|
GBinderBuffer* buffer)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderReaderData* data = &self->data;
|
GBinderReaderData* data = &self->data;
|
||||||
GBinderReader reader;
|
GBinderReader reader;
|
||||||
|
|
||||||
g_free(self->iface2);
|
g_free(self->iface2);
|
||||||
g_free(data->objects);
|
|
||||||
gbinder_buffer_free(data->buffer);
|
gbinder_buffer_free(data->buffer);
|
||||||
data->buffer = buffer;
|
data->buffer = buffer;
|
||||||
data->objects = objects;
|
data->objects = gbinder_buffer_objects(buffer);
|
||||||
|
|
||||||
/* Parse RPC header */
|
/* Parse RPC header */
|
||||||
self->header_size = 0;
|
|
||||||
gbinder_remote_request_init_reader2(self, &reader);
|
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->header_size = gbinder_reader_bytes_read(&reader);
|
&self->iface2);
|
||||||
|
if (self->iface) {
|
||||||
|
self->header_size = gbinder_reader_bytes_read(&reader);
|
||||||
|
} else {
|
||||||
|
/* No RPC header */
|
||||||
|
self->header_size = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
gbinder_buffer_free(buffer);
|
gbinder_buffer_free(buffer);
|
||||||
g_free(objects);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
gbinder_remote_request_interface(
|
gbinder_remote_request_interface(
|
||||||
GBinderRemoteRequest* self)
|
GBinderRemoteRequest* req)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
return G_LIKELY(self) ? self->iface : NULL;
|
return G_LIKELY(self) ? self->iface : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
GBinderRemoteRequest*
|
GBinderRemoteRequest*
|
||||||
gbinder_remote_request_ref(
|
gbinder_remote_request_ref(
|
||||||
GBinderRemoteRequest* self)
|
GBinderRemoteRequest* req)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GASSERT(self->refcount > 0);
|
GASSERT(self->refcount > 0);
|
||||||
g_atomic_int_inc(&self->refcount);
|
g_atomic_int_inc(&self->refcount);
|
||||||
}
|
}
|
||||||
return self;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_remote_request_unref(
|
gbinder_remote_request_unref(
|
||||||
GBinderRemoteRequest* self)
|
GBinderRemoteRequest* req)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GASSERT(self->refcount > 0);
|
GASSERT(self->refcount > 0);
|
||||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||||
@@ -160,9 +198,11 @@ gbinder_remote_request_unref(
|
|||||||
|
|
||||||
void
|
void
|
||||||
gbinder_remote_request_init_reader(
|
gbinder_remote_request_init_reader(
|
||||||
GBinderRemoteRequest* self,
|
GBinderRemoteRequest* req,
|
||||||
GBinderReader* reader)
|
GBinderReader* reader)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
gbinder_remote_request_init_reader2(self, reader);
|
gbinder_remote_request_init_reader2(self, reader);
|
||||||
} else {
|
} else {
|
||||||
@@ -172,15 +212,19 @@ gbinder_remote_request_init_reader(
|
|||||||
|
|
||||||
pid_t
|
pid_t
|
||||||
gbinder_remote_request_sender_pid(
|
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);
|
return G_LIKELY(self) ? self->pid : (uid_t)(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uid_t
|
uid_t
|
||||||
gbinder_remote_request_sender_euid(
|
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);
|
return G_LIKELY(self) ? self->euid : (uid_t)(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,9 +238,11 @@ gbinder_remote_request_read_int32(
|
|||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_remote_request_read_uint32(
|
gbinder_remote_request_read_uint32(
|
||||||
GBinderRemoteRequest* self,
|
GBinderRemoteRequest* req,
|
||||||
guint32* value)
|
guint32* value)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderReader reader;
|
GBinderReader reader;
|
||||||
|
|
||||||
@@ -216,9 +262,11 @@ gbinder_remote_request_read_int64(
|
|||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gbinder_remote_request_read_uint64(
|
gbinder_remote_request_read_uint64(
|
||||||
GBinderRemoteRequest* self,
|
GBinderRemoteRequest* req,
|
||||||
guint64* value)
|
guint64* value)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderReader reader;
|
GBinderReader reader;
|
||||||
|
|
||||||
@@ -230,8 +278,10 @@ gbinder_remote_request_read_uint64(
|
|||||||
|
|
||||||
const char*
|
const char*
|
||||||
gbinder_remote_request_read_string8(
|
gbinder_remote_request_read_string8(
|
||||||
GBinderRemoteRequest* self)
|
GBinderRemoteRequest* req)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderReader reader;
|
GBinderReader reader;
|
||||||
|
|
||||||
@@ -243,8 +293,10 @@ gbinder_remote_request_read_string8(
|
|||||||
|
|
||||||
char*
|
char*
|
||||||
gbinder_remote_request_read_string16(
|
gbinder_remote_request_read_string16(
|
||||||
GBinderRemoteRequest* self)
|
GBinderRemoteRequest* req)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderReader reader;
|
GBinderReader reader;
|
||||||
|
|
||||||
@@ -256,8 +308,10 @@ gbinder_remote_request_read_string16(
|
|||||||
|
|
||||||
GBinderRemoteObject*
|
GBinderRemoteObject*
|
||||||
gbinder_remote_request_read_object(
|
gbinder_remote_request_read_object(
|
||||||
GBinderRemoteRequest* self)
|
GBinderRemoteRequest* req)
|
||||||
{
|
{
|
||||||
|
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
|
||||||
|
|
||||||
if (G_LIKELY(self)) {
|
if (G_LIKELY(self)) {
|
||||||
GBinderReader reader;
|
GBinderReader reader;
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -37,6 +37,10 @@
|
|||||||
|
|
||||||
#include "gbinder_types_p.h"
|
#include "gbinder_types_p.h"
|
||||||
|
|
||||||
|
struct gbinder_remote_request {
|
||||||
|
GBinderIpcLooperTx* tx;
|
||||||
|
};
|
||||||
|
|
||||||
GBinderRemoteRequest*
|
GBinderRemoteRequest*
|
||||||
gbinder_remote_request_new(
|
gbinder_remote_request_new(
|
||||||
GBinderObjectRegistry* reg,
|
GBinderObjectRegistry* reg,
|
||||||
@@ -47,8 +51,8 @@ gbinder_remote_request_new(
|
|||||||
void
|
void
|
||||||
gbinder_remote_request_set_data(
|
gbinder_remote_request_set_data(
|
||||||
GBinderRemoteRequest* request,
|
GBinderRemoteRequest* request,
|
||||||
GBinderBuffer* buffer,
|
guint txcode,
|
||||||
void** objects);
|
GBinderBuffer* buffer);
|
||||||
|
|
||||||
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */
|
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -50,6 +50,14 @@
|
|||||||
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
|
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
|
||||||
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
|
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_rpc_protocol_binder_write_ping(
|
||||||
|
GBinderWriter* writer)
|
||||||
|
{
|
||||||
|
/* No payload */
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
gbinder_rpc_protocol_binder_write_rpc_header(
|
gbinder_rpc_protocol_binder_write_rpc_header(
|
||||||
@@ -69,9 +77,13 @@ static
|
|||||||
const char*
|
const char*
|
||||||
gbinder_rpc_protocol_binder_read_rpc_header(
|
gbinder_rpc_protocol_binder_read_rpc_header(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
|
guint32 txcode,
|
||||||
char** iface)
|
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);
|
*iface = gbinder_reader_read_string16(reader);
|
||||||
} else {
|
} else {
|
||||||
*iface = NULL;
|
*iface = NULL;
|
||||||
@@ -95,10 +107,20 @@ gbinder_rpc_protocol_hwbinder_write_rpc_header(
|
|||||||
gbinder_writer_append_string8(writer, iface);
|
gbinder_writer_append_string8(writer, iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_rpc_protocol_hwbinder_write_ping(
|
||||||
|
GBinderWriter* writer)
|
||||||
|
{
|
||||||
|
gbinder_rpc_protocol_hwbinder_write_rpc_header(writer,
|
||||||
|
"android.hidl.base@1.0::IBase");
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
const char*
|
const char*
|
||||||
gbinder_rpc_protocol_hwbinder_read_rpc_header(
|
gbinder_rpc_protocol_hwbinder_read_rpc_header(
|
||||||
GBinderReader* reader,
|
GBinderReader* reader,
|
||||||
|
guint32 txcode,
|
||||||
char** iface)
|
char** iface)
|
||||||
{
|
{
|
||||||
*iface = NULL;
|
*iface = NULL;
|
||||||
@@ -109,22 +131,26 @@ gbinder_rpc_protocol_hwbinder_read_rpc_header(
|
|||||||
* Interface
|
* Interface
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
|
const GBinderRpcProtocol gbinder_rpc_protocol_binder = {
|
||||||
|
.ping_tx = GBINDER_PING_TRANSACTION,
|
||||||
|
.write_ping = gbinder_rpc_protocol_binder_write_ping,
|
||||||
|
.write_rpc_header = gbinder_rpc_protocol_binder_write_rpc_header,
|
||||||
|
.read_rpc_header = gbinder_rpc_protocol_binder_read_rpc_header
|
||||||
|
};
|
||||||
|
|
||||||
|
const GBinderRpcProtocol gbinder_rpc_protocol_hwbinder = {
|
||||||
|
.ping_tx = HIDL_PING_TRANSACTION,
|
||||||
|
.write_ping = gbinder_rpc_protocol_hwbinder_write_ping,
|
||||||
|
.write_rpc_header = gbinder_rpc_protocol_hwbinder_write_rpc_header,
|
||||||
|
.read_rpc_header = gbinder_rpc_protocol_hwbinder_read_rpc_header
|
||||||
|
};
|
||||||
|
|
||||||
const GBinderRpcProtocol*
|
const GBinderRpcProtocol*
|
||||||
gbinder_rpc_protocol_for_device(
|
gbinder_rpc_protocol_for_device(
|
||||||
const char* dev)
|
const char* dev)
|
||||||
{
|
{
|
||||||
static const GBinderRpcProtocol protocol_binder = {
|
|
||||||
.read_rpc_header = gbinder_rpc_protocol_binder_read_rpc_header,
|
|
||||||
.write_rpc_header = gbinder_rpc_protocol_binder_write_rpc_header
|
|
||||||
};
|
|
||||||
|
|
||||||
static const GBinderRpcProtocol protocol_hwbinder = {
|
|
||||||
.read_rpc_header = gbinder_rpc_protocol_hwbinder_read_rpc_header,
|
|
||||||
.write_rpc_header = gbinder_rpc_protocol_hwbinder_write_rpc_header
|
|
||||||
};
|
|
||||||
|
|
||||||
return (dev && !strcmp(dev, GBINDER_DEFAULT_HWBINDER)) ?
|
return (dev && !strcmp(dev, GBINDER_DEFAULT_HWBINDER)) ?
|
||||||
&protocol_hwbinder : &protocol_binder;
|
&gbinder_rpc_protocol_hwbinder : &gbinder_rpc_protocol_binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,10 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* documentation and/or other materials provided with the distribution.
|
||||||
* be used to endorse or promote products derived from this software
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* 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"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -41,10 +42,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct gbinder_rpc_protocol {
|
struct gbinder_rpc_protocol {
|
||||||
const char* (*read_rpc_header)(GBinderReader* reader, char** iface);
|
guint32 ping_tx;
|
||||||
|
void (*write_ping)(GBinderWriter* writer);
|
||||||
void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
|
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*
|
const GBinderRpcProtocol*
|
||||||
gbinder_rpc_protocol_for_device(
|
gbinder_rpc_protocol_for_device(
|
||||||
const char* dev);
|
const char* dev);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -41,9 +41,29 @@
|
|||||||
#include <gbinder_client.h>
|
#include <gbinder_client.h>
|
||||||
|
|
||||||
#include <gutil_idlepool.h>
|
#include <gutil_idlepool.h>
|
||||||
|
#include <gutil_misc.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
guint presence_check_id;
|
||||||
|
guint presence_check_delay_ms;
|
||||||
|
};
|
||||||
|
|
||||||
G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
|
G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
|
||||||
G_TYPE_OBJECT)
|
G_TYPE_OBJECT)
|
||||||
|
|
||||||
@@ -60,6 +80,18 @@ G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
|
|||||||
#define GBINDER_IS_SERVICEMANAGER_TYPE(klass) \
|
#define GBINDER_IS_SERVICEMANAGER_TYPE(klass) \
|
||||||
G_TYPE_CHECK_CLASS_TYPE(klass, GBINDER_TYPE_SERVICEMANAGER)
|
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
|
* Implementation
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -81,53 +113,29 @@ gbinder_servicemanager_class_ref(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
GBinderServiceManager*
|
static
|
||||||
gbinder_servicemanager_new_with_type(
|
GBinderServiceManagerWatch*
|
||||||
GType type,
|
gbinder_servicemanager_watch_new(
|
||||||
const char* dev)
|
const char* name)
|
||||||
{
|
{
|
||||||
GBinderServiceManager* self = NULL;
|
GBinderServiceManagerWatch* watch = g_new0(GBinderServiceManagerWatch, 1);
|
||||||
GBinderServiceManagerClass* klass = gbinder_servicemanager_class_ref(type);
|
|
||||||
|
|
||||||
if (klass) {
|
watch->name = g_strdup(name);
|
||||||
GBinderIpc* ipc;
|
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;
|
static
|
||||||
ipc = gbinder_ipc_new(dev);
|
void
|
||||||
if (ipc) {
|
gbinder_servicemanager_watch_free(
|
||||||
GBinderRemoteObject* object = gbinder_ipc_get_remote_object
|
gpointer data)
|
||||||
(ipc, klass->handle);
|
{
|
||||||
|
GBinderServiceManagerWatch* watch = data;
|
||||||
|
|
||||||
if (object) {
|
g_free(watch->name);
|
||||||
/* Lock */
|
g_free(watch->detail);
|
||||||
g_mutex_lock(&klass->mutex);
|
g_free(watch);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct gbinder_servicemanager_list_tx_data {
|
typedef struct gbinder_servicemanager_list_tx_data {
|
||||||
@@ -256,6 +264,230 @@ gbinder_servicemanager_add_service_tx_free(
|
|||||||
g_slice_free(GBinderServiceManagerAddServiceTxData, data);
|
g_slice_free(GBinderServiceManagerAddServiceTxData, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_servicemanager_reanimated(
|
||||||
|
GBinderServiceManager* self)
|
||||||
|
{
|
||||||
|
GBinderServiceManagerPriv* priv = self->priv;
|
||||||
|
|
||||||
|
if (priv->presence_check_id) {
|
||||||
|
g_source_remove(priv->presence_check_id);
|
||||||
|
priv->presence_check_id = 0;
|
||||||
|
}
|
||||||
|
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_id = 0;
|
||||||
|
gbinder_servicemanager_reanimated(self);
|
||||||
|
result = G_SOURCE_REMOVE;
|
||||||
|
} else if (priv->presence_check_delay_ms < PRESENSE_WAIT_MS_MAX) {
|
||||||
|
priv->presence_check_delay_ms += PRESENSE_WAIT_MS_STEP;
|
||||||
|
priv->presence_check_id = g_timeout_add(priv->presence_check_delay_ms,
|
||||||
|
gbinder_servicemanager_presense_check_timer, self);
|
||||||
|
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_id);
|
||||||
|
priv->presence_check_delay_ms = PRESENSE_WAIT_MS_MIN;
|
||||||
|
priv->presence_check_id = g_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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* 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, klass->rpc_protocol);
|
||||||
|
if (ipc) {
|
||||||
|
/* Create a possible dead remote object */
|
||||||
|
GBinderRemoteObject* object = gbinder_ipc_get_remote_object
|
||||||
|
(ipc, GBINDER_SERVICEMANAGER_HANDLE, TRUE);
|
||||||
|
|
||||||
|
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
|
* Interface
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -277,10 +509,25 @@ gbinder_servicemanager_new_local_object(
|
|||||||
const char* iface,
|
const char* iface,
|
||||||
GBinderLocalTransactFunc txproc,
|
GBinderLocalTransactFunc txproc,
|
||||||
void* user_data)
|
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)) {
|
if (G_LIKELY(self)) {
|
||||||
return gbinder_ipc_new_local_object(gbinder_client_ipc(self->client),
|
return gbinder_local_object_new(gbinder_client_ipc(self->client),
|
||||||
iface, txproc, user_data);
|
ifaces, txproc, user_data);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -304,6 +551,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
|
gulong
|
||||||
gbinder_servicemanager_list(
|
gbinder_servicemanager_list(
|
||||||
GBinderServiceManager* self,
|
GBinderServiceManager* self,
|
||||||
@@ -433,6 +732,118 @@ 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--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* Internals
|
* Internals
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -442,6 +853,12 @@ void
|
|||||||
gbinder_servicemanager_init(
|
gbinder_servicemanager_init(
|
||||||
GBinderServiceManager* self)
|
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
|
static
|
||||||
@@ -450,8 +867,7 @@ gbinder_servicemanager_dispose(
|
|||||||
GObject* object)
|
GObject* object)
|
||||||
{
|
{
|
||||||
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
|
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
|
||||||
GBinderServiceManagerClass* klass =
|
GBinderServiceManagerClass* klass = GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
||||||
GBINDER_SERVICEMANAGER_GET_CLASS(self);
|
|
||||||
|
|
||||||
GVERBOSE_("%s", self->dev);
|
GVERBOSE_("%s", self->dev);
|
||||||
/* Lock */
|
/* Lock */
|
||||||
@@ -475,7 +891,7 @@ gbinder_servicemanager_dispose(
|
|||||||
* gbinder_servicemanager_finalize() will not be called
|
* gbinder_servicemanager_finalize() will not be called
|
||||||
* this time around.
|
* this time around.
|
||||||
*/
|
*/
|
||||||
if (klass->table && object->ref_count == 0) {
|
if (klass->table && g_atomic_int_get(&object->ref_count) <= 1) {
|
||||||
g_hash_table_remove(klass->table, self->dev);
|
g_hash_table_remove(klass->table, self->dev);
|
||||||
if (g_hash_table_size(klass->table) == 0) {
|
if (g_hash_table_size(klass->table) == 0) {
|
||||||
g_hash_table_unref(klass->table);
|
g_hash_table_unref(klass->table);
|
||||||
@@ -493,9 +909,14 @@ gbinder_servicemanager_finalize(
|
|||||||
GObject* object)
|
GObject* object)
|
||||||
{
|
{
|
||||||
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
|
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
|
||||||
|
GBinderServiceManagerPriv* priv = self->priv;
|
||||||
|
|
||||||
gutil_idle_pool_drain(self->pool);
|
if (priv->presence_check_id) {
|
||||||
gutil_idle_pool_unref(self->pool);
|
g_source_remove(priv->presence_check_id);
|
||||||
|
}
|
||||||
|
gbinder_remote_object_remove_handler(self->client->remote, priv->death_id);
|
||||||
|
g_hash_table_destroy(priv->watch_table);
|
||||||
|
gutil_idle_pool_destroy(self->pool);
|
||||||
gbinder_client_unref(self->client);
|
gbinder_client_unref(self->client);
|
||||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||||
}
|
}
|
||||||
@@ -506,10 +927,20 @@ gbinder_servicemanager_class_init(
|
|||||||
GBinderServiceManagerClass* klass)
|
GBinderServiceManagerClass* klass)
|
||||||
{
|
{
|
||||||
GObjectClass* object_class = G_OBJECT_CLASS(klass);
|
GObjectClass* object_class = G_OBJECT_CLASS(klass);
|
||||||
|
GType type = G_OBJECT_CLASS_TYPE(klass);
|
||||||
|
|
||||||
g_mutex_init(&klass->mutex);
|
g_mutex_init(&klass->mutex);
|
||||||
|
g_type_class_add_private(klass, sizeof(GBinderServiceManagerPriv));
|
||||||
object_class->dispose = gbinder_servicemanager_dispose;
|
object_class->dispose = gbinder_servicemanager_dispose;
|
||||||
object_class->finalize = gbinder_servicemanager_finalize;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -39,21 +39,33 @@
|
|||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
/* As a special case, ServiceManager's handle is zero */
|
||||||
|
#define GBINDER_SERVICEMANAGER_HANDLE (0)
|
||||||
|
|
||||||
|
typedef struct gbinder_servicemanager_priv GBinderServiceManagerPriv;
|
||||||
|
|
||||||
typedef struct gbinder_servicemanager {
|
typedef struct gbinder_servicemanager {
|
||||||
GObject parent;
|
GObject parent;
|
||||||
|
GBinderServiceManagerPriv* priv;
|
||||||
const char* dev;
|
const char* dev;
|
||||||
GBinderClient* client;
|
GBinderClient* client;
|
||||||
GUtilIdlePool* pool;
|
GUtilIdlePool* pool;
|
||||||
} GBinderServiceManager;
|
} 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 {
|
typedef struct gbinder_servicemanager_class {
|
||||||
GObjectClass parent;
|
GObjectClass parent;
|
||||||
GMutex mutex;
|
GMutex mutex;
|
||||||
GHashTable* table;
|
GHashTable* table;
|
||||||
|
|
||||||
guint32 handle;
|
|
||||||
const char* iface;
|
const char* iface;
|
||||||
const char* default_device;
|
const char* default_device;
|
||||||
|
const GBinderRpcProtocol* rpc_protocol;
|
||||||
|
|
||||||
/* Methods (synchronous) */
|
/* Methods (synchronous) */
|
||||||
char** (*list)(GBinderServiceManager* self);
|
char** (*list)(GBinderServiceManager* self);
|
||||||
@@ -62,6 +74,15 @@ typedef struct gbinder_servicemanager_class {
|
|||||||
int (*add_service)
|
int (*add_service)
|
||||||
(GBinderServiceManager* self, const char* name,
|
(GBinderServiceManager* self, const char* name,
|
||||||
GBinderLocalObject* obj);
|
GBinderLocalObject* obj);
|
||||||
|
|
||||||
|
/* 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;
|
} GBinderServiceManagerClass;
|
||||||
|
|
||||||
GType gbinder_servicemanager_get_type(void);
|
GType gbinder_servicemanager_get_type(void);
|
||||||
@@ -72,6 +93,11 @@ gbinder_servicemanager_new_with_type(
|
|||||||
GType type,
|
GType type,
|
||||||
const char* dev);
|
const char* dev);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_servicemanager_service_registered(
|
||||||
|
GBinderServiceManager* self,
|
||||||
|
const char* name);
|
||||||
|
|
||||||
#endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */
|
#endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
173
src/gbinder_servicename.c
Normal file
173
src/gbinder_servicename.c
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gbinder_types_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 */
|
||||||
|
|
||||||
|
typedef struct gbinder_servicename_priv {
|
||||||
|
GBinderServiceName pub;
|
||||||
|
gint refcount;
|
||||||
|
char* name;
|
||||||
|
GBinderLocalObject* object;
|
||||||
|
GBinderServiceManager* sm;
|
||||||
|
gulong presence_id;
|
||||||
|
gulong add_call_id;
|
||||||
|
} GBinderServiceNamePriv;
|
||||||
|
|
||||||
|
GBINDER_INLINE_FUNC GBinderServiceNamePriv*
|
||||||
|
gbinder_servicename_cast(GBinderServiceName* pub)
|
||||||
|
{ return G_CAST(pub, GBinderServiceNamePriv, pub); }
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* Implementation
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* 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);
|
||||||
|
g_free(priv->name);
|
||||||
|
g_slice_free(GBinderServiceName, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
268
src/gbinder_servicepoll.c
Normal file
268
src/gbinder_servicepoll.c
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* 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_servicepoll.h"
|
||||||
|
#include "gbinder_servicemanager.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;
|
||||||
|
guint timer_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
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_id = g_timeout_add(gbinder_servicepoll_interval_ms,
|
||||||
|
gbinder_servicepoll_timer, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_servicepoll_finalize(
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
GBinderServicePoll* self = GBINDER_SERVICEPOLL(object);
|
||||||
|
|
||||||
|
g_source_remove(self->timer_id);
|
||||||
|
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:
|
||||||
|
*/
|
||||||
88
src/gbinder_servicepoll.h
Normal file
88
src/gbinder_servicepoll.h
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GBINDER_SERVICEPOLL_H
|
||||||
|
#define GBINDER_SERVICEPOLL_H
|
||||||
|
|
||||||
|
#include "gbinder_types_p.h"
|
||||||
|
|
||||||
|
extern guint gbinder_servicepoll_interval_ms;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
void
|
||||||
|
(*GBinderServicePollFunc)(
|
||||||
|
GBinderServicePoll* poll,
|
||||||
|
const char* name_added,
|
||||||
|
void* user_data);
|
||||||
|
|
||||||
|
GBinderServicePoll*
|
||||||
|
gbinder_servicepoll_new(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
GBinderServicePoll** weakptr);
|
||||||
|
|
||||||
|
GBinderServicePoll*
|
||||||
|
gbinder_servicepoll_ref(
|
||||||
|
GBinderServicePoll* poll);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_servicepoll_unref(
|
||||||
|
GBinderServicePoll* poll);
|
||||||
|
|
||||||
|
GBinderServiceManager*
|
||||||
|
gbinder_servicepoll_manager(
|
||||||
|
GBinderServicePoll* poll);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gbinder_servicepoll_is_known_name(
|
||||||
|
GBinderServicePoll* poll,
|
||||||
|
const char* name);
|
||||||
|
|
||||||
|
gulong
|
||||||
|
gbinder_servicepoll_add_handler(
|
||||||
|
GBinderServicePoll* poll,
|
||||||
|
GBinderServicePollFunc func,
|
||||||
|
void* user_data);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_servicepoll_remove_handler(
|
||||||
|
GBinderServicePoll* poll,
|
||||||
|
gulong id);
|
||||||
|
|
||||||
|
#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.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -35,36 +35,16 @@
|
|||||||
|
|
||||||
#include <gbinder_types.h>
|
#include <gbinder_types.h>
|
||||||
|
|
||||||
|
typedef struct gbinder_buffer_contents GBinderBufferContents;
|
||||||
typedef struct gbinder_cleanup GBinderCleanup;
|
typedef struct gbinder_cleanup GBinderCleanup;
|
||||||
typedef struct gbinder_driver GBinderDriver;
|
typedef struct gbinder_driver GBinderDriver;
|
||||||
typedef struct gbinder_handler GBinderHandler;
|
typedef struct gbinder_handler GBinderHandler;
|
||||||
typedef struct gbinder_io GBinderIo;
|
typedef struct gbinder_io GBinderIo;
|
||||||
typedef struct gbinder_ipc GBinderIpc;
|
|
||||||
typedef struct gbinder_object_registry GBinderObjectRegistry;
|
typedef struct gbinder_object_registry GBinderObjectRegistry;
|
||||||
typedef struct gbinder_output_data GBinderOutputData;
|
typedef struct gbinder_output_data GBinderOutputData;
|
||||||
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;
|
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;
|
||||||
|
typedef struct gbinder_servicepoll GBinderServicePoll;
|
||||||
typedef struct hidl_vec {
|
typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
|
||||||
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)
|
|
||||||
|
|
||||||
#define GBINDER_INLINE_FUNC static inline
|
#define GBINDER_INLINE_FUNC static inline
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gbinder_writer_p.h"
|
#include "gbinder_writer_p.h"
|
||||||
|
#include "gbinder_buffer_p.h"
|
||||||
#include "gbinder_io.h"
|
#include "gbinder_io.h"
|
||||||
#include "gbinder_log.h"
|
#include "gbinder_log.h"
|
||||||
|
|
||||||
@@ -38,7 +39,10 @@
|
|||||||
#include <gutil_macros.h>
|
#include <gutil_macros.h>
|
||||||
#include <gutil_strv.h>
|
#include <gutil_strv.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
typedef struct gbinder_writer_priv {
|
typedef struct gbinder_writer_priv {
|
||||||
GBinderWriterData* data;
|
GBinderWriterData* data;
|
||||||
@@ -51,6 +55,55 @@ GBINDER_INLINE_FUNC GBinderWriterPriv* gbinder_writer_cast(GBinderWriter* pub)
|
|||||||
GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub)
|
GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub)
|
||||||
{ return G_LIKELY(pub) ? gbinder_writer_cast(pub)->data : NULL; }
|
{ return G_LIKELY(pub) ? gbinder_writer_cast(pub)->data : NULL; }
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_writer_data_buffer_cleanup(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
gbinder_buffer_contents_unref((GBinderBufferContents*)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_data_set_contents(
|
||||||
|
GBinderWriterData* data,
|
||||||
|
GBinderBuffer* buffer)
|
||||||
|
{
|
||||||
|
gsize bufsize;
|
||||||
|
const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize);
|
||||||
|
const GBinderIo* io = gbinder_buffer_io(buffer);
|
||||||
|
GBinderBufferContents* contents = gbinder_buffer_contents(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);
|
||||||
|
|
||||||
|
g_byte_array_append(data->bytes, bufdata, bufsize);
|
||||||
|
if (contents) {
|
||||||
|
void** objects = gbinder_buffer_objects(buffer);
|
||||||
|
|
||||||
|
data->cleanup = gbinder_cleanup_add(data->cleanup,
|
||||||
|
gbinder_writer_data_buffer_cleanup,
|
||||||
|
gbinder_buffer_contents_ref(contents));
|
||||||
|
if (objects && *objects) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
gbinder_writer_data_record_offset(
|
gbinder_writer_data_record_offset(
|
||||||
@@ -71,16 +124,16 @@ gbinder_writer_data_write_buffer_object(
|
|||||||
gsize size,
|
gsize size,
|
||||||
const GBinderParent* parent)
|
const GBinderParent* parent)
|
||||||
{
|
{
|
||||||
GByteArray* dest = data->bytes;
|
GByteArray* buf = data->bytes;
|
||||||
const guint offset = dest->len;
|
const guint offset = buf->len;
|
||||||
guint n;
|
guint n;
|
||||||
|
|
||||||
/* Preallocate enough space */
|
/* Preallocate enough space */
|
||||||
g_byte_array_set_size(dest, offset + GBINDER_MAX_BUFFER_OBJECT_SIZE);
|
g_byte_array_set_size(buf, offset + GBINDER_MAX_BUFFER_OBJECT_SIZE);
|
||||||
/* Write the object */
|
/* Write the object */
|
||||||
n = data->io->encode_buffer_object(dest->data + offset, ptr, size, parent);
|
n = data->io->encode_buffer_object(buf->data + offset, ptr, size, parent);
|
||||||
/* Fix the data size */
|
/* Fix the data size */
|
||||||
g_byte_array_set_size(dest, offset + n);
|
g_byte_array_set_size(buf, offset + n);
|
||||||
/* Record the offset */
|
/* Record the offset */
|
||||||
gbinder_writer_data_record_offset(data, offset);
|
gbinder_writer_data_record_offset(data, offset);
|
||||||
/* The driver seems to require each buffer to be 8-byte aligned */
|
/* The driver seems to require each buffer to be 8-byte aligned */
|
||||||
@@ -96,6 +149,14 @@ gbinder_writer_init(
|
|||||||
gbinder_writer_cast(self)->data = data;
|
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
|
void
|
||||||
gbinder_writer_append_bool(
|
gbinder_writer_append_bool(
|
||||||
GBinderWriter* self,
|
GBinderWriter* self,
|
||||||
@@ -117,7 +178,7 @@ gbinder_writer_data_append_bool(
|
|||||||
|
|
||||||
/* Boolean values are padded to 4-byte boundary */
|
/* Boolean values are padded to 4-byte boundary */
|
||||||
padded[0] = (value != FALSE);
|
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));
|
g_byte_array_append(data->bytes, padded, sizeof(padded));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,13 +199,34 @@ gbinder_writer_data_append_int32(
|
|||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
guint32 value)
|
guint32 value)
|
||||||
{
|
{
|
||||||
|
GByteArray* buf = data->bytes;
|
||||||
guint32* ptr;
|
guint32* ptr;
|
||||||
|
|
||||||
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
|
g_byte_array_set_size(buf, buf->len + sizeof(*ptr));
|
||||||
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
|
ptr = (void*)(buf->data + (buf->len - sizeof(*ptr)));
|
||||||
*ptr = value;
|
*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
|
void
|
||||||
gbinder_writer_append_int64(
|
gbinder_writer_append_int64(
|
||||||
GBinderWriter* self,
|
GBinderWriter* self,
|
||||||
@@ -162,10 +244,11 @@ gbinder_writer_data_append_int64(
|
|||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
guint64 value)
|
guint64 value)
|
||||||
{
|
{
|
||||||
|
GByteArray* buf = data->bytes;
|
||||||
guint64* ptr;
|
guint64* ptr;
|
||||||
|
|
||||||
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
|
g_byte_array_set_size(buf, buf->len + sizeof(*ptr));
|
||||||
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
|
ptr = (void*)(buf->data + (buf->len - sizeof(*ptr)));
|
||||||
*ptr = value;
|
*ptr = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,10 +269,11 @@ gbinder_writer_data_append_float(
|
|||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
gfloat value)
|
gfloat value)
|
||||||
{
|
{
|
||||||
|
GByteArray* buf = data->bytes;
|
||||||
gfloat* ptr;
|
gfloat* ptr;
|
||||||
|
|
||||||
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
|
g_byte_array_set_size(buf, buf->len + sizeof(*ptr));
|
||||||
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
|
ptr = (void*)(buf->data + (buf->len - sizeof(*ptr)));
|
||||||
*ptr = value;
|
*ptr = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,10 +294,11 @@ gbinder_writer_data_append_double(
|
|||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
gdouble value)
|
gdouble value)
|
||||||
{
|
{
|
||||||
|
GByteArray* buf = data->bytes;
|
||||||
gdouble* ptr;
|
gdouble* ptr;
|
||||||
|
|
||||||
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
|
g_byte_array_set_size(buf, buf->len + sizeof(*ptr));
|
||||||
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
|
ptr = (void*)(buf->data + (buf->len - sizeof(*ptr)));
|
||||||
*ptr = value;
|
*ptr = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,15 +338,16 @@ gbinder_writer_data_append_string8_len(
|
|||||||
gsize len)
|
gsize len)
|
||||||
{
|
{
|
||||||
if (G_LIKELY(str)) {
|
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);
|
gsize padded_len = G_ALIGN4(len + 1);
|
||||||
guint32* dest;
|
guint32* dest;
|
||||||
|
|
||||||
/* Preallocate space */
|
/* 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 */
|
/* Zero the last word */
|
||||||
dest = (guint32*)(data->bytes->data + old_size);
|
dest = (guint32*)(buf->data + old_size);
|
||||||
dest[padded_len/4 - 1] = 0;
|
dest[padded_len/4 - 1] = 0;
|
||||||
|
|
||||||
/* Copy the data */
|
/* Copy the data */
|
||||||
@@ -298,14 +384,36 @@ gbinder_writer_data_append_string16(
|
|||||||
gbinder_writer_data_append_string16_len(data, utf8, utf8? strlen(utf8) : 0);
|
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
|
void
|
||||||
gbinder_writer_data_append_string16_len(
|
gbinder_writer_data_append_string16_len(
|
||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
const char* utf8,
|
const char* utf8,
|
||||||
gssize num_bytes)
|
gssize num_bytes)
|
||||||
{
|
{
|
||||||
const gsize old_size = data->bytes->len;
|
|
||||||
|
|
||||||
if (utf8) {
|
if (utf8) {
|
||||||
const char* end = utf8;
|
const char* end = utf8;
|
||||||
|
|
||||||
@@ -316,14 +424,16 @@ gbinder_writer_data_append_string16_len(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (num_bytes > 0) {
|
if (num_bytes > 0) {
|
||||||
|
GByteArray* buf = data->bytes;
|
||||||
|
const gsize old_size = buf->len;
|
||||||
glong len = g_utf8_strlen(utf8, num_bytes);
|
glong len = g_utf8_strlen(utf8, num_bytes);
|
||||||
gsize padded_len = G_ALIGN4((len+1)*2);
|
gsize padded_len = G_ALIGN4((len+1)*2);
|
||||||
guint32* len_ptr;
|
guint32* len_ptr;
|
||||||
gunichar2* utf16_ptr;
|
gunichar2* utf16_ptr;
|
||||||
|
|
||||||
/* Preallocate space */
|
/* Preallocate space */
|
||||||
g_byte_array_set_size(data->bytes, old_size + padded_len + 4);
|
g_byte_array_set_size(buf, old_size + padded_len + 4);
|
||||||
len_ptr = (guint32*)(data->bytes->data + old_size);
|
len_ptr = (guint32*)(buf->data + old_size);
|
||||||
utf16_ptr = (gunichar2*)(len_ptr + 1);
|
utf16_ptr = (gunichar2*)(len_ptr + 1);
|
||||||
|
|
||||||
/* TODO: this could be optimized for ASCII strings, i.e. if
|
/* TODO: this could be optimized for ASCII strings, i.e. if
|
||||||
@@ -350,17 +460,72 @@ gbinder_writer_data_append_string16_len(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Correct the packet size if necessaary */
|
/* 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) {
|
} else if (utf8) {
|
||||||
/* Empty string */
|
/* Empty string */
|
||||||
guint16* ptr16;
|
gbinder_writer_data_append_string16_empty(data);
|
||||||
|
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
/* NULL string */
|
/* 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,6 +553,60 @@ gbinder_writer_data_prepare(
|
|||||||
return data->offsets->count;
|
return data->offsets->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gbinder_writer_data_close_fd(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
guint
|
guint
|
||||||
gbinder_writer_append_buffer_object_with_parent(
|
gbinder_writer_append_buffer_object_with_parent(
|
||||||
GBinderWriter* self,
|
GBinderWriter* self,
|
||||||
@@ -442,18 +661,66 @@ gbinder_writer_append_hidl_string(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = g_memdup(base, total);
|
||||||
|
|
||||||
|
/* Prepare parent descriptor for the string data */
|
||||||
|
vec_parent.index = gbinder_writer_data_prepare(data);
|
||||||
|
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* Write the buffer object pointing to the vector descriptor */
|
||||||
|
gbinder_writer_data_write_buffer_object(data, vec, sizeof(*vec), NULL);
|
||||||
|
|
||||||
|
/* Not sure what's the right way to deal with NULL vectors... */
|
||||||
|
if (buf) {
|
||||||
|
gbinder_writer_data_write_buffer_object(data, buf, total, &vec_parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
void
|
||||||
gbinder_writer_data_append_hidl_string(
|
gbinder_writer_data_append_hidl_string(
|
||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
const char* str)
|
const char* str)
|
||||||
{
|
{
|
||||||
GBinderParent str_parent;
|
GBinderParent str_parent;
|
||||||
HidlString* hidl_string = g_new0(HidlString, 1);
|
GBinderHidlString* hidl_string = g_new0(GBinderHidlString, 1);
|
||||||
const gsize len = str ? strlen(str) : 0;
|
const gsize len = str ? strlen(str) : 0;
|
||||||
|
|
||||||
/* Prepare parent descriptor for the string data */
|
/* Prepare parent descriptor for the string data */
|
||||||
str_parent.index = gbinder_writer_data_prepare(data);
|
str_parent.index = gbinder_writer_data_prepare(data);
|
||||||
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
|
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
|
||||||
|
|
||||||
/* Fill in the string descriptor and store it */
|
/* Fill in the string descriptor and store it */
|
||||||
hidl_string->data.str = str;
|
hidl_string->data.str = str;
|
||||||
@@ -495,8 +762,8 @@ gbinder_writer_data_append_hidl_string_vec(
|
|||||||
gssize count)
|
gssize count)
|
||||||
{
|
{
|
||||||
GBinderParent vec_parent;
|
GBinderParent vec_parent;
|
||||||
HidlVec* vec = g_new0(HidlVec, 1);
|
GBinderHidlVec* vec = g_new0(GBinderHidlVec, 1);
|
||||||
HidlString* strings = NULL;
|
GBinderHidlString* strings = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
@@ -506,11 +773,11 @@ gbinder_writer_data_append_hidl_string_vec(
|
|||||||
|
|
||||||
/* Prepare parent descriptor for the vector data */
|
/* Prepare parent descriptor for the vector data */
|
||||||
vec_parent.index = gbinder_writer_data_prepare(data);
|
vec_parent.index = gbinder_writer_data_prepare(data);
|
||||||
vec_parent.offset = HIDL_VEC_BUFFER_OFFSET;
|
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
|
||||||
|
|
||||||
/* Fill in the vector descriptor */
|
/* Fill in the vector descriptor */
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
strings = g_new0(HidlString, count);
|
strings = g_new0(GBinderHidlString, count);
|
||||||
vec->data.ptr = strings;
|
vec->data.ptr = strings;
|
||||||
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, strings);
|
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, strings);
|
||||||
}
|
}
|
||||||
@@ -521,7 +788,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
|||||||
/* Fill in string descriptors */
|
/* Fill in string descriptors */
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
const char* str = strv[i];
|
const char* str = strv[i];
|
||||||
HidlString* hidl_str = strings + i;
|
GBinderHidlString* hidl_str = strings + i;
|
||||||
|
|
||||||
if ((hidl_str->data.str = str) != NULL) {
|
if ((hidl_str->data.str = str) != NULL) {
|
||||||
hidl_str->len = strlen(str);
|
hidl_str->len = strlen(str);
|
||||||
@@ -536,7 +803,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
|||||||
|
|
||||||
/* Prepare parent descriptor for the string data */
|
/* Prepare parent descriptor for the string data */
|
||||||
str_parent.index = data->offsets->count;
|
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) */
|
/* Write the vector data (it's parent for the string data) */
|
||||||
gbinder_writer_data_write_buffer_object(data, strings,
|
gbinder_writer_data_write_buffer_object(data, strings,
|
||||||
@@ -544,7 +811,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
|||||||
|
|
||||||
/* Write the string data */
|
/* Write the string data */
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
HidlString* hidl_str = strings + i;
|
GBinderHidlString* hidl_str = strings + i;
|
||||||
|
|
||||||
if (hidl_str->data.str) {
|
if (hidl_str->data.str) {
|
||||||
gbinder_writer_data_write_buffer_object(data,
|
gbinder_writer_data_write_buffer_object(data,
|
||||||
@@ -553,7 +820,7 @@ gbinder_writer_data_append_hidl_string_vec(
|
|||||||
(guint)hidl_str->len, (guint)str_parent.index,
|
(guint)hidl_str->len, (guint)str_parent.index,
|
||||||
(guint)data->buffers_size);
|
(guint)data->buffers_size);
|
||||||
}
|
}
|
||||||
str_parent.offset += sizeof(HidlString);
|
str_parent.offset += sizeof(GBinderHidlString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -575,16 +842,16 @@ gbinder_writer_data_append_local_object(
|
|||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
GBinderLocalObject* obj)
|
GBinderLocalObject* obj)
|
||||||
{
|
{
|
||||||
GByteArray* dest = data->bytes;
|
GByteArray* buf = data->bytes;
|
||||||
const guint offset = dest->len;
|
const guint offset = buf->len;
|
||||||
guint n;
|
guint n;
|
||||||
|
|
||||||
/* Preallocate enough space */
|
/* 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 */
|
/* 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 */
|
/* Fix the data size */
|
||||||
g_byte_array_set_size(dest, offset + n);
|
g_byte_array_set_size(buf, offset + n);
|
||||||
/* Record the offset */
|
/* Record the offset */
|
||||||
gbinder_writer_data_record_offset(data, offset);
|
gbinder_writer_data_record_offset(data, offset);
|
||||||
}
|
}
|
||||||
@@ -601,25 +868,122 @@ 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
|
void
|
||||||
gbinder_writer_data_append_remote_object(
|
gbinder_writer_data_append_remote_object(
|
||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
GBinderRemoteObject* obj)
|
GBinderRemoteObject* obj)
|
||||||
{
|
{
|
||||||
GByteArray* dest = data->bytes;
|
GByteArray* buf = data->bytes;
|
||||||
const guint offset = dest->len;
|
const guint offset = buf->len;
|
||||||
guint n;
|
guint n;
|
||||||
|
|
||||||
/* Preallocate enough space */
|
/* 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 */
|
/* 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 */
|
/* Fix the data size */
|
||||||
g_byte_array_set_size(dest, offset + n);
|
g_byte_array_set_size(buf, offset + n);
|
||||||
/* Record the offset */
|
/* Record the offset */
|
||||||
gbinder_writer_data_record_offset(data, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
* Local Variables:
|
||||||
* mode: C
|
* mode: C
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -50,6 +50,11 @@ gbinder_writer_init(
|
|||||||
GBinderWriter* writer,
|
GBinderWriter* writer,
|
||||||
GBinderWriterData* data);
|
GBinderWriterData* data);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_data_set_contents(
|
||||||
|
GBinderWriterData* data,
|
||||||
|
GBinderBuffer* buffer);
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_writer_data_append_bool(
|
gbinder_writer_data_append_bool(
|
||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
@@ -104,6 +109,13 @@ gbinder_writer_data_append_buffer_object(
|
|||||||
gsize size,
|
gsize size,
|
||||||
const GBinderParent* parent);
|
const GBinderParent* parent);
|
||||||
|
|
||||||
|
void
|
||||||
|
gbinder_writer_data_append_hidl_vec(
|
||||||
|
GBinderWriterData* data,
|
||||||
|
const void* base,
|
||||||
|
guint count,
|
||||||
|
guint elemsize);
|
||||||
|
|
||||||
void
|
void
|
||||||
gbinder_writer_data_append_hidl_string(
|
gbinder_writer_data_append_hidl_string(
|
||||||
GBinderWriterData* data,
|
GBinderWriterData* data,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
all:
|
all:
|
||||||
%:
|
%:
|
||||||
@$(MAKE) -C binder-client $*
|
@$(MAKE) -C binder-client $*
|
||||||
|
@$(MAKE) -C binder-dump $*
|
||||||
@$(MAKE) -C binder-list $*
|
@$(MAKE) -C binder-list $*
|
||||||
@$(MAKE) -C binder-service $*
|
@$(MAKE) -C binder-service $*
|
||||||
@$(MAKE) -C rild-card-status $*
|
@$(MAKE) -C rild-card-status $*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -54,10 +54,15 @@ typedef struct app_options {
|
|||||||
|
|
||||||
typedef struct app {
|
typedef struct app {
|
||||||
const AppOptions* opt;
|
const AppOptions* opt;
|
||||||
|
char* fqname;
|
||||||
GMainLoop* loop;
|
GMainLoop* loop;
|
||||||
GBinderServiceManager* sm;
|
GBinderServiceManager* sm;
|
||||||
GBinderLocalObject* local;
|
GBinderLocalObject* local;
|
||||||
|
GBinderRemoteObject* remote;
|
||||||
|
gulong wait_id;
|
||||||
|
gulong death_id;
|
||||||
GBinderClient* client;
|
GBinderClient* client;
|
||||||
|
GThread* thread;
|
||||||
int ret;
|
int ret;
|
||||||
} App;
|
} App;
|
||||||
|
|
||||||
@@ -171,46 +176,80 @@ app_input_thread(
|
|||||||
return NULL;
|
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
|
static
|
||||||
void
|
void
|
||||||
app_run(
|
app_run(
|
||||||
App* app)
|
App* app)
|
||||||
{
|
{
|
||||||
const AppOptions* opt = app->opt;
|
const AppOptions* opt = app->opt;
|
||||||
char* fqname = opt->fqname ? g_strdup(opt->fqname) :
|
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
|
||||||
|
guint sigint = g_unix_signal_add(SIGINT, app_signal, app);
|
||||||
|
|
||||||
|
app->fqname = opt->fqname ? g_strdup(opt->fqname) :
|
||||||
strchr(opt->name, '/') ? g_strdup(opt->name) :
|
strchr(opt->name, '/') ? g_strdup(opt->name) :
|
||||||
g_strconcat(opt->iface, "/", opt->name, NULL);
|
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);
|
if (!app_connect_remote(app)) {
|
||||||
|
GINFO("Waiting for %s", app->fqname);
|
||||||
app->client = gbinder_client_new(remote, opt->iface);
|
app->wait_id = gbinder_servicemanager_add_registration_handler(app->sm,
|
||||||
app->ret = RET_OK;
|
app->fqname, app_registration_handler, app);
|
||||||
app->loop = g_main_loop_new(NULL, TRUE);
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
g_free(fqname);
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (app->thread) {
|
||||||
|
/* Not the cleanest of exits, just dropping the thread... */
|
||||||
|
g_thread_unref(app->thread);
|
||||||
|
}
|
||||||
|
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
|
static
|
||||||
@@ -311,8 +350,6 @@ int main(int argc, char* argv[])
|
|||||||
app.local = gbinder_servicemanager_new_local_object(app.sm,
|
app.local = gbinder_servicemanager_new_local_object(app.sm,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
app_run(&app);
|
app_run(&app);
|
||||||
gbinder_local_object_unref(app.local);
|
|
||||||
gbinder_client_unref(app.client);
|
|
||||||
gbinder_servicemanager_unref(app.sm);
|
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:
|
||||||
|
*/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -194,7 +194,7 @@ app_init(
|
|||||||
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
|
||||||
app_log_quiet, "Be quiet", NULL },
|
app_log_quiet, "Be quiet", NULL },
|
||||||
{ "async", 'a', 0, G_OPTION_ARG_NONE, &opt->async,
|
{ "async", 'a', 0, G_OPTION_ARG_NONE, &opt->async,
|
||||||
"Parform operations asynchronously", NULL },
|
"Perform operations asynchronously", NULL },
|
||||||
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
|
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
|
||||||
"Binder device [" DEV_DEFAULT "]", "DEVICE" },
|
"Binder device [" DEV_DEFAULT "]", "DEVICE" },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
@@ -245,7 +245,7 @@ int main(int argc, char* argv[])
|
|||||||
app.opt = &opt;
|
app.opt = &opt;
|
||||||
if (app_init(&opt, argc, argv)) {
|
if (app_init(&opt, argc, argv)) {
|
||||||
app.sm = gbinder_servicemanager_new(opt.dev);
|
app.sm = gbinder_servicemanager_new(opt.dev);
|
||||||
if (app.sm) {
|
if (gbinder_servicemanager_wait(app.sm, -1)) {
|
||||||
if (opt.async) {
|
if (opt.async) {
|
||||||
app_async(&app);
|
app_async(&app);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -36,6 +36,9 @@
|
|||||||
|
|
||||||
#include <glib-unix.h>
|
#include <glib-unix.h>
|
||||||
|
|
||||||
|
#define BINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
|
||||||
|
#define BINDER_DUMP_TRANSACTION BINDER_TRANSACTION('D','M','P')
|
||||||
|
|
||||||
#define RET_OK (0)
|
#define RET_OK (0)
|
||||||
#define RET_NOTFOUND (1)
|
#define RET_NOTFOUND (1)
|
||||||
#define RET_INVARG (2)
|
#define RET_INVARG (2)
|
||||||
@@ -49,6 +52,7 @@ typedef struct app_options {
|
|||||||
char* dev;
|
char* dev;
|
||||||
char* iface;
|
char* iface;
|
||||||
const char* name;
|
const char* name;
|
||||||
|
gboolean async;
|
||||||
} AppOptions;
|
} AppOptions;
|
||||||
|
|
||||||
typedef struct app {
|
typedef struct app {
|
||||||
@@ -59,6 +63,11 @@ typedef struct app {
|
|||||||
int ret;
|
int ret;
|
||||||
} App;
|
} App;
|
||||||
|
|
||||||
|
typedef struct response {
|
||||||
|
GBinderRemoteRequest* req;
|
||||||
|
GBinderLocalReply* reply;
|
||||||
|
} Response;
|
||||||
|
|
||||||
static const char pname[] = "binder-service";
|
static const char pname[] = "binder-service";
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -73,6 +82,29 @@ app_signal(
|
|||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
app_async_resp(
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Response* resp = user_data;
|
||||||
|
|
||||||
|
gbinder_remote_request_complete(resp->req, resp->reply, 0);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
app_async_free(
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Response* resp = user_data;
|
||||||
|
|
||||||
|
gbinder_local_reply_unref(resp->reply);
|
||||||
|
gbinder_remote_request_unref(resp->req);
|
||||||
|
g_free(resp);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
GBinderLocalReply*
|
GBinderLocalReply*
|
||||||
app_reply(
|
app_reply(
|
||||||
@@ -83,15 +115,52 @@ app_reply(
|
|||||||
int* status,
|
int* status,
|
||||||
void* user_data)
|
void* user_data)
|
||||||
{
|
{
|
||||||
char* str = gbinder_remote_request_read_string16(req);
|
App* app = user_data;
|
||||||
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
|
GBinderReader reader;
|
||||||
|
|
||||||
GVERBOSE("\"%s\" %u", gbinder_remote_request_interface(req), code);
|
gbinder_remote_request_init_reader(req, &reader);
|
||||||
GDEBUG("\"%s\"", str);
|
if (code == GBINDER_FIRST_CALL_TRANSACTION) {
|
||||||
gbinder_local_reply_append_string16(reply, str);
|
const AppOptions* opt = app->opt;
|
||||||
g_free(str);
|
const char* iface = gbinder_remote_request_interface(req);
|
||||||
*status = 0;
|
|
||||||
return reply;
|
if (!g_strcmp0(iface, opt->iface)) {
|
||||||
|
char* str = gbinder_reader_read_string16(&reader);
|
||||||
|
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
|
||||||
|
|
||||||
|
GVERBOSE("\"%s\" %u", iface, code);
|
||||||
|
GDEBUG("\"%s\"", str);
|
||||||
|
*status = 0;
|
||||||
|
gbinder_local_reply_append_string16(reply, str);
|
||||||
|
g_free(str);
|
||||||
|
if (opt->async) {
|
||||||
|
Response* resp = g_new0(Response, 1);
|
||||||
|
|
||||||
|
resp->reply = reply;
|
||||||
|
resp->req = gbinder_remote_request_ref(req);
|
||||||
|
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, app_async_resp,
|
||||||
|
resp, app_async_free);
|
||||||
|
gbinder_remote_request_block(resp->req);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GDEBUG("Unexpected interface \"%s\"", iface);
|
||||||
|
}
|
||||||
|
} else if (code == BINDER_DUMP_TRANSACTION) {
|
||||||
|
int fd = gbinder_reader_read_fd(&reader);
|
||||||
|
const char* dump = "Sorry, I've got nothing to dump...\n";
|
||||||
|
const gssize dump_len = strlen(dump);
|
||||||
|
|
||||||
|
GDEBUG("Dump request from %d", gbinder_remote_request_sender_pid(req));
|
||||||
|
if (write(fd, dump, dump_len) != dump_len) {
|
||||||
|
GERR("Failed to write dump: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
*status = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*status = -1;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -112,6 +181,23 @@ app_add_service_done(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
app_sm_presence_handler(
|
||||||
|
GBinderServiceManager* sm,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
App* app = user_data;
|
||||||
|
|
||||||
|
if (gbinder_servicemanager_is_present(app->sm)) {
|
||||||
|
GINFO("Service manager has reappeared");
|
||||||
|
gbinder_servicemanager_add_service(app->sm, app->opt->name, app->obj,
|
||||||
|
app_add_service_done, app);
|
||||||
|
} else {
|
||||||
|
GINFO("Service manager has died");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
app_run(
|
app_run(
|
||||||
@@ -120,6 +206,8 @@ app_run(
|
|||||||
const char* name = app->opt->name;
|
const char* name = app->opt->name;
|
||||||
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
|
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
|
||||||
guint sigint = g_unix_signal_add(SIGINT, app_signal, app);
|
guint sigint = g_unix_signal_add(SIGINT, app_signal, app);
|
||||||
|
gulong presence_id = gbinder_servicemanager_add_presence_handler
|
||||||
|
(app->sm, app_sm_presence_handler, app);
|
||||||
|
|
||||||
app->loop = g_main_loop_new(NULL, TRUE);
|
app->loop = g_main_loop_new(NULL, TRUE);
|
||||||
|
|
||||||
@@ -130,6 +218,7 @@ app_run(
|
|||||||
|
|
||||||
if (sigtrm) g_source_remove(sigtrm);
|
if (sigtrm) g_source_remove(sigtrm);
|
||||||
if (sigint) g_source_remove(sigint);
|
if (sigint) g_source_remove(sigint);
|
||||||
|
gbinder_servicemanager_remove_handler(app->sm, presence_id);
|
||||||
g_main_loop_unref(app->loop);
|
g_main_loop_unref(app->loop);
|
||||||
app->loop = NULL;
|
app->loop = NULL;
|
||||||
}
|
}
|
||||||
@@ -175,6 +264,8 @@ app_init(
|
|||||||
"Binder device [" DEFAULT_DEVICE "]", "DEVICE" },
|
"Binder device [" DEFAULT_DEVICE "]", "DEVICE" },
|
||||||
{ "interface", 'i', 0, G_OPTION_ARG_STRING, &opt->iface,
|
{ "interface", 'i', 0, G_OPTION_ARG_STRING, &opt->iface,
|
||||||
"Local interface [" DEFAULT_IFACE "]", "IFACE" },
|
"Local interface [" DEFAULT_IFACE "]", "IFACE" },
|
||||||
|
{ "async", 'a', 0, G_OPTION_ARG_NONE, &opt->async,
|
||||||
|
"Handle calls asynchronously", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -226,7 +317,7 @@ int main(int argc, char* argv[])
|
|||||||
app.opt = &opt;
|
app.opt = &opt;
|
||||||
if (app_init(&opt, argc, argv)) {
|
if (app_init(&opt, argc, argv)) {
|
||||||
app.sm = gbinder_servicemanager_new(opt.dev);
|
app.sm = gbinder_servicemanager_new(opt.dev);
|
||||||
if (app.sm) {
|
if (gbinder_servicemanager_wait(app.sm, -1)) {
|
||||||
app.obj = gbinder_servicemanager_new_local_object
|
app.obj = gbinder_servicemanager_new_local_object
|
||||||
(app.sm, opt.iface, app_reply, &app);
|
(app.sm, opt.iface, app_reply, &app);
|
||||||
app_run(&app);
|
app_run(&app);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
all:
|
all:
|
||||||
%:
|
%:
|
||||||
@$(MAKE) -C unit_buffer $*
|
@$(MAKE) -C unit_buffer $*
|
||||||
|
@$(MAKE) -C unit_cleanup $*
|
||||||
@$(MAKE) -C unit_client $*
|
@$(MAKE) -C unit_client $*
|
||||||
@$(MAKE) -C unit_driver $*
|
@$(MAKE) -C unit_driver $*
|
||||||
@$(MAKE) -C unit_ipc $*
|
@$(MAKE) -C unit_ipc $*
|
||||||
@@ -14,6 +15,9 @@ all:
|
|||||||
@$(MAKE) -C unit_remote_object $*
|
@$(MAKE) -C unit_remote_object $*
|
||||||
@$(MAKE) -C unit_remote_reply $*
|
@$(MAKE) -C unit_remote_reply $*
|
||||||
@$(MAKE) -C unit_remote_request $*
|
@$(MAKE) -C unit_remote_request $*
|
||||||
|
@$(MAKE) -C unit_servicemanager $*
|
||||||
|
@$(MAKE) -C unit_servicename $*
|
||||||
|
@$(MAKE) -C unit_servicepoll $*
|
||||||
@$(MAKE) -C unit_writer $*
|
@$(MAKE) -C unit_writer $*
|
||||||
|
|
||||||
clean: unitclean
|
clean: unitclean
|
||||||
|
|||||||
@@ -103,9 +103,13 @@ ifneq ($(strip $(DEPS)),)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(DEBUG_EXE) $(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
|
$(DEBUG_LIB): | debug_lib
|
||||||
$(RELEASE_EXE) $(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
|
$(RELEASE_LIB): | release_lib
|
||||||
$(COVERAGE_EXE) $(COVERAGE_OBJS): | $(COVERAGE_BUILD_DIR)
|
$(COVERAGE_LIB): | coverage_lib
|
||||||
|
|
||||||
|
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
|
||||||
|
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
|
||||||
|
$(COVERAGE_OBJS): | $(COVERAGE_BUILD_DIR)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Rules
|
# Rules
|
||||||
@@ -134,10 +138,10 @@ test_banner:
|
|||||||
@echo "===========" $(EXE) "=========== "
|
@echo "===========" $(EXE) "=========== "
|
||||||
|
|
||||||
test: test_banner debug
|
test: test_banner debug
|
||||||
@LD_LIBRARY_PATH="$(LIB_DIR)/$(DEBUG_LIB_PATH)" $(DEBUG_EXE)
|
@$(DEBUG_EXE)
|
||||||
|
|
||||||
valgrind: test_banner debug
|
valgrind: test_banner debug
|
||||||
@LD_LIBRARY_PATH="$(LIB_DIR)/$(DEBUG_LIB_PATH)" G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no $(DEBUG_EXE)
|
@G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no $(DEBUG_EXE)
|
||||||
|
|
||||||
$(DEBUG_BUILD_DIR):
|
$(DEBUG_BUILD_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
@@ -166,13 +170,13 @@ $(RELEASE_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
|
|||||||
$(COVERAGE_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
|
$(COVERAGE_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
|
||||||
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||||
|
|
||||||
$(DEBUG_EXE): $(DEBUG_PLUGIN_LIB) $(DEBUG_OBJS)
|
$(DEBUG_EXE): $(DEBUG_LIB) $(DEBUG_OBJS)
|
||||||
$(LD) $(DEBUG_LDFLAGS) $(DEBUG_OBJS) $(DEBUG_LIBS) -o $@
|
$(LD) $(DEBUG_LDFLAGS) $(DEBUG_OBJS) $(DEBUG_LIBS) -o $@
|
||||||
|
|
||||||
$(RELEASE_EXE): $(RELEASE_PLUGIN_LIB) $(RELEASE_OBJS)
|
$(RELEASE_EXE): $(RELEASE_LIB) $(RELEASE_OBJS)
|
||||||
$(LD) $(RELEASE_LDFLAGS) $(RELEASE_OBJS) $(RELEASE_LIBS) -o $@
|
$(LD) $(RELEASE_LDFLAGS) $(RELEASE_OBJS) $(RELEASE_LIBS) -o $@
|
||||||
|
|
||||||
$(COVERAGE_EXE): $(COVERAGE_PLUGIN_LIB) $(COVERAGE_OBJS)
|
$(COVERAGE_EXE): $(COVERAG_LIB) $(COVERAGE_OBJS)
|
||||||
$(LD) $(COVERAGE_LDFLAGS) $(COVERAGE_OBJS) $(COVERAGE_LIBS) -o $@
|
$(LD) $(COVERAGE_LDFLAGS) $(COVERAGE_OBJS) $(COVERAGE_LIBS) -o $@
|
||||||
|
|
||||||
debug_lib:
|
debug_lib:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -32,7 +32,9 @@
|
|||||||
|
|
||||||
#include "gbinder_system.h"
|
#include "gbinder_system.h"
|
||||||
|
|
||||||
|
#define GLOG_MODULE_NAME test_binder_log
|
||||||
#include <gutil_log.h>
|
#include <gutil_log.h>
|
||||||
|
GLOG_MODULE_DEFINE2("test_binder", gutil_log_default);
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -43,6 +45,7 @@
|
|||||||
|
|
||||||
static GHashTable* test_fd_map = NULL;
|
static GHashTable* test_fd_map = NULL;
|
||||||
static GHashTable* test_node_map = NULL;
|
static GHashTable* test_node_map = NULL;
|
||||||
|
static GPrivate test_looper;
|
||||||
|
|
||||||
#define public_fd fd[0]
|
#define public_fd fd[0]
|
||||||
#define private_fd fd[1]
|
#define private_fd fd[1]
|
||||||
@@ -56,15 +59,34 @@ static GHashTable* test_node_map = NULL;
|
|||||||
#define TF_ACCEPT_FDS 0x10
|
#define TF_ACCEPT_FDS 0x10
|
||||||
|
|
||||||
typedef struct test_binder_io TestBinderIo;
|
typedef struct test_binder_io TestBinderIo;
|
||||||
|
typedef struct test_binder TestBinder;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
void
|
||||||
|
(*TestBinderPushDataFunc)(
|
||||||
|
int fd,
|
||||||
|
const void* data);
|
||||||
|
|
||||||
|
typedef struct test_binder_submit_thread {
|
||||||
|
GThread* thread;
|
||||||
|
GCond cond;
|
||||||
|
GMutex mutex;
|
||||||
|
gboolean run;
|
||||||
|
GSList* queue;
|
||||||
|
TestBinder* binder;
|
||||||
|
} TestBinderSubmitThread;
|
||||||
|
|
||||||
typedef struct test_binder_node {
|
typedef struct test_binder_node {
|
||||||
char* path;
|
char* path;
|
||||||
int refcount;
|
int refcount;
|
||||||
const TestBinderIo* io;
|
const TestBinderIo* io;
|
||||||
|
GHashTable* destroy_map;
|
||||||
} TestBinderNode;
|
} TestBinderNode;
|
||||||
|
|
||||||
typedef struct test_binder {
|
typedef struct test_binder {
|
||||||
TestBinderNode* node;
|
TestBinderNode* node;
|
||||||
|
TestBinderSubmitThread* submit_thread;
|
||||||
|
gboolean looper_enabled;
|
||||||
int fd[2];
|
int fd[2];
|
||||||
} TestBinder;
|
} TestBinder;
|
||||||
|
|
||||||
@@ -101,6 +123,11 @@ typedef struct binder_pre_cookie_64 {
|
|||||||
guint64 cookie;
|
guint64 cookie;
|
||||||
} BinderPtrCookie64;
|
} BinderPtrCookie64;
|
||||||
|
|
||||||
|
typedef struct binder_handle_cookie_64 {
|
||||||
|
guint32 handle;
|
||||||
|
guint64 cookie;
|
||||||
|
} __attribute__((packed)) BinderHandleCookie64;
|
||||||
|
|
||||||
#define BC_TRANSACTION_64 _IOW('c', 0, BinderTransactionData64)
|
#define BC_TRANSACTION_64 _IOW('c', 0, BinderTransactionData64)
|
||||||
#define BC_REPLY_64 _IOW('c', 1, BinderTransactionData64)
|
#define BC_REPLY_64 _IOW('c', 1, BinderTransactionData64)
|
||||||
#define BC_FREE_BUFFER_64 _IOW('c', 3, guint64)
|
#define BC_FREE_BUFFER_64 _IOW('c', 3, guint64)
|
||||||
@@ -110,6 +137,8 @@ typedef struct binder_pre_cookie_64 {
|
|||||||
#define BC_DECREFS _IOW('c', 7, guint32)
|
#define BC_DECREFS _IOW('c', 7, guint32)
|
||||||
#define BC_ENTER_LOOPER _IO('c', 12)
|
#define BC_ENTER_LOOPER _IO('c', 12)
|
||||||
#define BC_EXIT_LOOPER _IO('c', 13)
|
#define BC_EXIT_LOOPER _IO('c', 13)
|
||||||
|
#define BC_REQUEST_DEATH_NOTIFICATION_64 _IOW('c', 14, BinderHandleCookie64)
|
||||||
|
#define BC_CLEAR_DEATH_NOTIFICATION_64 _IOW('c', 15, BinderHandleCookie64)
|
||||||
|
|
||||||
#define BR_TRANSACTION_64 _IOR('r', 2, BinderTransactionData64)
|
#define BR_TRANSACTION_64 _IOR('r', 2, BinderTransactionData64)
|
||||||
#define BR_REPLY_64 _IOR('r', 3, BinderTransactionData64)
|
#define BR_REPLY_64 _IOR('r', 3, BinderTransactionData64)
|
||||||
@@ -123,17 +152,140 @@ typedef struct binder_pre_cookie_64 {
|
|||||||
#define BR_DEAD_BINDER_64 _IOR('r', 15, guint64)
|
#define BR_DEAD_BINDER_64 _IOR('r', 15, guint64)
|
||||||
#define BR_FAILED_REPLY _IO('r', 17)
|
#define BR_FAILED_REPLY _IO('r', 17)
|
||||||
|
|
||||||
|
static
|
||||||
|
gpointer
|
||||||
|
test_binder_submit_thread_proc(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
TestBinderSubmitThread* submit = data;
|
||||||
|
TestBinder* binder = submit->binder;
|
||||||
|
GMutex* mutex = &submit->mutex;
|
||||||
|
GCond* cond = &submit->cond;
|
||||||
|
|
||||||
|
GDEBUG("Submit thread started");
|
||||||
|
g_mutex_lock(mutex);
|
||||||
|
while (submit->run) {
|
||||||
|
GBytes* next = NULL;
|
||||||
|
|
||||||
|
while (submit->run && !next) {
|
||||||
|
if (submit->queue) {
|
||||||
|
next = submit->queue->data;
|
||||||
|
submit->queue = g_slist_remove(submit->queue, next);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
g_cond_wait(cond, mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
int bytes_available = 0;
|
||||||
|
int err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
|
||||||
|
|
||||||
|
/* Wait until the queue is empty */
|
||||||
|
g_assert(err >= 0);
|
||||||
|
while (bytes_available > 0 && submit->run) {
|
||||||
|
/* Wait a bit between polls */
|
||||||
|
g_cond_wait_until(cond, mutex, g_get_monotonic_time () +
|
||||||
|
100 * G_TIME_SPAN_MILLISECOND);
|
||||||
|
err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
|
||||||
|
g_assert(err >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (submit->run) {
|
||||||
|
gsize len;
|
||||||
|
gconstpointer data = g_bytes_get_data(next, &len);
|
||||||
|
|
||||||
|
GDEBUG("Submitting command 0x%08x", *(guint32*)data);
|
||||||
|
g_assert(write(binder->private_fd, data, len) == len);
|
||||||
|
}
|
||||||
|
g_bytes_unref(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_mutex_unlock(mutex);
|
||||||
|
GDEBUG("Submit thread exiting");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
TestBinderSubmitThread*
|
||||||
|
test_binder_submit_thread_new(
|
||||||
|
TestBinder* binder)
|
||||||
|
{
|
||||||
|
TestBinderSubmitThread* submit = g_new0(TestBinderSubmitThread, 1);
|
||||||
|
|
||||||
|
submit->run = TRUE;
|
||||||
|
submit->binder = binder;
|
||||||
|
g_cond_init(&submit->cond);
|
||||||
|
g_mutex_init(&submit->mutex);
|
||||||
|
submit->thread = g_thread_new(binder->node->path,
|
||||||
|
test_binder_submit_thread_proc, submit);
|
||||||
|
return submit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_binder_submit_thread_free(
|
||||||
|
TestBinderSubmitThread* submit)
|
||||||
|
{
|
||||||
|
if (submit) {
|
||||||
|
g_mutex_lock(&submit->mutex);
|
||||||
|
submit->run = FALSE;
|
||||||
|
g_cond_signal(&submit->cond);
|
||||||
|
g_mutex_unlock(&submit->mutex);
|
||||||
|
g_thread_join(submit->thread);
|
||||||
|
|
||||||
|
g_slist_free_full(submit->queue, (GDestroyNotify) g_bytes_unref);
|
||||||
|
g_cond_clear(&submit->cond);
|
||||||
|
g_mutex_clear(&submit->mutex);
|
||||||
|
g_free(submit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_binder_submit_later(
|
||||||
|
TestBinderSubmitThread* submit,
|
||||||
|
const void* data)
|
||||||
|
{
|
||||||
|
const guint32* cmd = data;
|
||||||
|
|
||||||
|
g_mutex_lock(&submit->mutex);
|
||||||
|
submit->queue = g_slist_append(submit->queue,
|
||||||
|
g_bytes_new(cmd, sizeof(*cmd) + _IOC_SIZE(*cmd)));
|
||||||
|
g_cond_signal(&submit->cond);
|
||||||
|
g_mutex_unlock(&submit->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_io_free_buffer(
|
||||||
|
TestBinder* binder,
|
||||||
|
void* ptr)
|
||||||
|
{
|
||||||
|
if (ptr) {
|
||||||
|
TestBinderNode* node = binder->node;
|
||||||
|
GDestroyNotify destroy = g_hash_table_lookup(node->destroy_map, ptr);
|
||||||
|
|
||||||
|
if (destroy) {
|
||||||
|
g_hash_table_remove(node->destroy_map, ptr);
|
||||||
|
destroy(ptr);
|
||||||
|
} else {
|
||||||
|
g_free(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
test_io_handle_write_read_64(
|
test_io_handle_write_read_64(
|
||||||
TestBinder* binder,
|
TestBinder* binder,
|
||||||
void* data)
|
void* data)
|
||||||
{
|
{
|
||||||
int err, bytes_available = 0;
|
|
||||||
BinderWriteRead64* wr = data;
|
BinderWriteRead64* wr = data;
|
||||||
gssize bytes_left = wr->write_size - wr->write_consumed;
|
gssize bytes_left = wr->write_size - wr->write_consumed;
|
||||||
const guint8* write_ptr = (void*)(gsize)
|
const guint8* write_ptr = (void*)(gsize)
|
||||||
(wr->write_buffer + wr->write_consumed);
|
(wr->write_buffer + wr->write_consumed);
|
||||||
|
gboolean is_looper;
|
||||||
|
|
||||||
while (bytes_left >= sizeof(guint32)) {
|
while (bytes_left >= sizeof(guint32)) {
|
||||||
const guint cmd = *(guint32*)write_ptr;
|
const guint cmd = *(guint32*)write_ptr;
|
||||||
@@ -151,14 +303,21 @@ test_io_handle_write_read_64(
|
|||||||
/* Is there anything special about transactions and replies? */
|
/* Is there anything special about transactions and replies? */
|
||||||
break;
|
break;
|
||||||
case BC_FREE_BUFFER_64:
|
case BC_FREE_BUFFER_64:
|
||||||
g_free((void*)(gsize)(*(guint64*)write_ptr));
|
test_io_free_buffer(binder,
|
||||||
|
GSIZE_TO_POINTER(*(guint64*)write_ptr));
|
||||||
break;
|
break;
|
||||||
|
case BC_ENTER_LOOPER:
|
||||||
|
g_private_set(&test_looper, GINT_TO_POINTER(TRUE));
|
||||||
|
break;
|
||||||
|
case BC_EXIT_LOOPER:
|
||||||
|
g_private_set(&test_looper, NULL);
|
||||||
|
break;
|
||||||
|
case BC_REQUEST_DEATH_NOTIFICATION_64:
|
||||||
|
case BC_CLEAR_DEATH_NOTIFICATION_64:
|
||||||
case BC_INCREFS:
|
case BC_INCREFS:
|
||||||
case BC_ACQUIRE:
|
case BC_ACQUIRE:
|
||||||
case BC_RELEASE:
|
case BC_RELEASE:
|
||||||
case BC_DECREFS:
|
case BC_DECREFS:
|
||||||
case BC_ENTER_LOOPER:
|
|
||||||
case BC_EXIT_LOOPER:
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
#pragma message("TODO: implement more BINDER_WRITE_READ commands")
|
#pragma message("TODO: implement more BINDER_WRITE_READ commands")
|
||||||
@@ -175,24 +334,45 @@ test_io_handle_write_read_64(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now read the data from the socket */
|
is_looper = g_private_get(&test_looper) ? TRUE : FALSE;
|
||||||
err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
|
if (binder->looper_enabled || !is_looper) {
|
||||||
if (err >= 0) {
|
/* Now read the data from the socket */
|
||||||
int bytes_read = 0;
|
int bytes_available = 0;
|
||||||
if (bytes_available > 0) {
|
int err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
|
||||||
bytes_read = read(binder->public_fd,
|
|
||||||
(void*)(gsize)(wr->read_buffer + wr->read_consumed),
|
|
||||||
wr->read_size - wr->read_consumed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes_read >= 0) {
|
if (err >= 0) {
|
||||||
wr->read_consumed += bytes_read;
|
int bytes_read = 0;
|
||||||
return 0;
|
|
||||||
} else {
|
if (bytes_available >= 4) {
|
||||||
err = bytes_read;
|
bytes_read = read(binder->public_fd,
|
||||||
|
(void*)(gsize)(wr->read_buffer + wr->read_consumed),
|
||||||
|
wr->read_size - wr->read_consumed);
|
||||||
|
} else {
|
||||||
|
struct timespec wait;
|
||||||
|
|
||||||
|
wait.tv_sec = 0;
|
||||||
|
wait.tv_nsec = 10 * 1000000; /* 10 ms */
|
||||||
|
nanosleep(&wait, &wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_read >= 0) {
|
||||||
|
wr->read_consumed += bytes_read;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
err = bytes_read;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
if (wr->read_size > 0) {
|
||||||
|
struct timespec wait;
|
||||||
|
|
||||||
|
wait.tv_sec = 0;
|
||||||
|
wait.tv_nsec = 100 * 1000000; /* 100 ms */
|
||||||
|
nanosleep(&wait, &wait);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TestBinderIo test_io_64 = {
|
static const TestBinderIo test_io_64 = {
|
||||||
@@ -219,6 +399,7 @@ test_binder_node_unref(
|
|||||||
node->refcount--;
|
node->refcount--;
|
||||||
if (!node->refcount) {
|
if (!node->refcount) {
|
||||||
g_hash_table_remove(test_node_map, node->path);
|
g_hash_table_remove(test_node_map, node->path);
|
||||||
|
g_hash_table_destroy(node->destroy_map);
|
||||||
g_free(node->path);
|
g_free(node->path);
|
||||||
g_free(node);
|
g_free(node);
|
||||||
}
|
}
|
||||||
@@ -229,48 +410,84 @@ test_binder_node_unref(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
gboolean
|
TestBinder*
|
||||||
test_binder_push_data(
|
test_binder_from_fd(
|
||||||
int fd,
|
int fd)
|
||||||
const void* data)
|
|
||||||
{
|
{
|
||||||
|
TestBinder* binder = NULL;
|
||||||
GASSERT(test_fd_map);
|
GASSERT(test_fd_map);
|
||||||
if (test_fd_map) {
|
if (test_fd_map) {
|
||||||
gpointer key = GINT_TO_POINTER(fd);
|
binder = g_hash_table_lookup(test_fd_map, GINT_TO_POINTER(fd));
|
||||||
TestBinder* binder = g_hash_table_lookup(test_fd_map, key);
|
|
||||||
|
|
||||||
GASSERT(binder);
|
GASSERT(binder);
|
||||||
if (binder) {
|
|
||||||
const guint32* cmd = data;
|
|
||||||
const int len = sizeof(*cmd) + _IOC_SIZE(*cmd);
|
|
||||||
|
|
||||||
return write(binder->private_fd, data, len) == len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return FALSE;
|
return binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
test_binder_fill_transaction_data(
|
test_io_destroy_none(
|
||||||
BinderTransactionData64* tr,
|
gpointer data)
|
||||||
guint64 handle,
|
|
||||||
guint32 code,
|
|
||||||
const GByteArray* bytes)
|
|
||||||
{
|
{
|
||||||
g_assert(bytes);
|
GDEBUG("Not freeing %p", data);
|
||||||
|
|
||||||
memset(tr, 0, sizeof(*tr));
|
|
||||||
tr->handle = handle;
|
|
||||||
tr->code = code;
|
|
||||||
tr->data_size = bytes->len;
|
|
||||||
tr->sender_pid = getpid();
|
|
||||||
tr->sender_euid = geteuid();
|
|
||||||
/* This memory should eventually get deallocated with BC_FREE_BUFFER_64 */
|
|
||||||
tr->data_buffer = (gsize)g_memdup(bytes->data, bytes->len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
|
test_binder_set_looper_enabled(
|
||||||
|
int fd,
|
||||||
|
gboolean enabled)
|
||||||
|
{
|
||||||
|
TestBinder* binder = test_binder_from_fd(fd);
|
||||||
|
|
||||||
|
g_assert(binder);
|
||||||
|
binder->looper_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_set_destroy(
|
||||||
|
int fd,
|
||||||
|
gpointer ptr,
|
||||||
|
GDestroyNotify destroy)
|
||||||
|
{
|
||||||
|
TestBinder* binder = test_binder_from_fd(fd);
|
||||||
|
|
||||||
|
if (binder) {
|
||||||
|
TestBinderNode* node = binder->node;
|
||||||
|
|
||||||
|
g_hash_table_replace(node->destroy_map, ptr,
|
||||||
|
destroy ? destroy : test_io_destroy_none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_binder_push_data(
|
||||||
|
int fd,
|
||||||
|
const void* data)
|
||||||
|
{
|
||||||
|
const guint32* cmd = data;
|
||||||
|
const int len = sizeof(*cmd) + _IOC_SIZE(*cmd);
|
||||||
|
TestBinder* binder = test_binder_from_fd(fd);
|
||||||
|
|
||||||
|
g_assert(binder);
|
||||||
|
g_assert(write(binder->private_fd, data, len) == len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_binder_push_data_later(
|
||||||
|
int fd,
|
||||||
|
const void* data)
|
||||||
|
{
|
||||||
|
TestBinder* binder = test_binder_from_fd(fd);
|
||||||
|
|
||||||
|
g_assert(binder);
|
||||||
|
if (!binder->submit_thread) {
|
||||||
|
binder->submit_thread = test_binder_submit_thread_new(binder);
|
||||||
|
}
|
||||||
|
test_binder_submit_later(binder->submit_thread, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
test_binder_push_ptr_cookie(
|
test_binder_push_ptr_cookie(
|
||||||
int fd,
|
int fd,
|
||||||
guint32 cmd,
|
guint32 cmd,
|
||||||
@@ -282,60 +499,69 @@ test_binder_push_ptr_cookie(
|
|||||||
memcpy(buf, &cmd, sizeof(cmd));
|
memcpy(buf, &cmd, sizeof(cmd));
|
||||||
memset(data, 0, sizeof(*data));
|
memset(data, 0, sizeof(*data));
|
||||||
data->ptr = (gsize)ptr;
|
data->ptr = (gsize)ptr;
|
||||||
return test_binder_push_data(fd, buf);
|
test_binder_push_data(fd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_noop(
|
test_binder_br_noop(
|
||||||
int fd)
|
int fd)
|
||||||
{
|
{
|
||||||
guint32 cmd = BR_NOOP;
|
guint32 cmd = BR_NOOP;
|
||||||
|
|
||||||
return test_binder_push_data(fd, &cmd);
|
test_binder_push_data(fd, &cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_increfs(
|
test_binder_br_increfs(
|
||||||
int fd,
|
int fd,
|
||||||
void* ptr)
|
void* ptr)
|
||||||
{
|
{
|
||||||
return test_binder_push_ptr_cookie(fd, BR_INCREFS_64, ptr);
|
test_binder_push_ptr_cookie(fd, BR_INCREFS_64, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_acquire(
|
test_binder_br_acquire(
|
||||||
int fd,
|
int fd,
|
||||||
void* ptr)
|
void* ptr)
|
||||||
{
|
{
|
||||||
return test_binder_push_ptr_cookie(fd, BR_ACQUIRE_64, ptr);
|
test_binder_push_ptr_cookie(fd, BR_ACQUIRE_64, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_release(
|
test_binder_br_release(
|
||||||
int fd,
|
int fd,
|
||||||
void* ptr)
|
void* ptr)
|
||||||
{
|
{
|
||||||
return test_binder_push_ptr_cookie(fd, BR_RELEASE_64, ptr);
|
test_binder_push_ptr_cookie(fd, BR_RELEASE_64, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_decrefs(
|
test_binder_br_decrefs(
|
||||||
int fd,
|
int fd,
|
||||||
void* ptr)
|
void* ptr)
|
||||||
{
|
{
|
||||||
return test_binder_push_ptr_cookie(fd, BR_DECREFS_64, ptr);
|
test_binder_push_ptr_cookie(fd, BR_DECREFS_64, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_transaction_complete(
|
test_binder_br_transaction_complete(
|
||||||
int fd)
|
int fd)
|
||||||
{
|
{
|
||||||
guint32 cmd = BR_TRANSACTION_COMPLETE;
|
guint32 cmd = BR_TRANSACTION_COMPLETE;
|
||||||
|
|
||||||
return test_binder_push_data(fd, &cmd);
|
test_binder_push_data(fd, &cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
|
test_binder_br_transaction_complete_later(
|
||||||
|
int fd)
|
||||||
|
{
|
||||||
|
guint32 cmd = BR_TRANSACTION_COMPLETE;
|
||||||
|
|
||||||
|
test_binder_push_data_later(fd, &cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
test_binder_br_dead_binder(
|
test_binder_br_dead_binder(
|
||||||
int fd,
|
int fd,
|
||||||
guint handle)
|
guint handle)
|
||||||
@@ -346,28 +572,47 @@ test_binder_br_dead_binder(
|
|||||||
buf[0] = BR_DEAD_BINDER_64;
|
buf[0] = BR_DEAD_BINDER_64;
|
||||||
memcpy(buf + 1, &handle64, sizeof(handle64));
|
memcpy(buf + 1, &handle64, sizeof(handle64));
|
||||||
|
|
||||||
return test_binder_push_data(fd, buf);
|
test_binder_push_data(fd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_dead_reply(
|
test_binder_br_dead_reply(
|
||||||
int fd)
|
int fd)
|
||||||
{
|
{
|
||||||
guint32 cmd = BR_DEAD_REPLY;
|
guint32 cmd = BR_DEAD_REPLY;
|
||||||
|
|
||||||
return test_binder_push_data(fd, &cmd);
|
test_binder_push_data(fd, &cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_failed_reply(
|
test_binder_br_failed_reply(
|
||||||
int fd)
|
int fd)
|
||||||
{
|
{
|
||||||
guint32 cmd = BR_FAILED_REPLY;
|
guint32 cmd = BR_FAILED_REPLY;
|
||||||
|
|
||||||
return test_binder_push_data(fd, &cmd);
|
test_binder_push_data(fd, &cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
static
|
||||||
|
void
|
||||||
|
test_binder_fill_transaction_data(
|
||||||
|
BinderTransactionData64* tr,
|
||||||
|
guint64 handle,
|
||||||
|
guint32 code,
|
||||||
|
const GByteArray* bytes)
|
||||||
|
{
|
||||||
|
memset(tr, 0, sizeof(*tr));
|
||||||
|
tr->handle = handle;
|
||||||
|
tr->code = code;
|
||||||
|
tr->data_size = bytes ? bytes->len : 0;
|
||||||
|
tr->sender_pid = getpid();
|
||||||
|
tr->sender_euid = geteuid();
|
||||||
|
/* This memory should eventually get deallocated with BC_FREE_BUFFER_64 */
|
||||||
|
tr->data_buffer = (gsize)g_memdup(bytes ? (void*)bytes->data : (void*)"",
|
||||||
|
tr->data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
test_binder_br_transaction(
|
test_binder_br_transaction(
|
||||||
int fd,
|
int fd,
|
||||||
void* target,
|
void* target,
|
||||||
@@ -381,15 +626,17 @@ test_binder_br_transaction(
|
|||||||
test_binder_fill_transaction_data((void*)(buf + sizeof(cmd)),
|
test_binder_fill_transaction_data((void*)(buf + sizeof(cmd)),
|
||||||
(gsize)target, code, bytes);
|
(gsize)target, code, bytes);
|
||||||
|
|
||||||
return test_binder_push_data(fd, buf);
|
test_binder_push_data(fd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
static
|
||||||
test_binder_br_reply(
|
void
|
||||||
|
test_binder_br_reply1(
|
||||||
int fd,
|
int fd,
|
||||||
guint32 handle,
|
guint32 handle,
|
||||||
guint32 code,
|
guint32 code,
|
||||||
const GByteArray* bytes)
|
const GByteArray* bytes,
|
||||||
|
TestBinderPushDataFunc push)
|
||||||
{
|
{
|
||||||
guint32 cmd = BR_REPLY_64;
|
guint32 cmd = BR_REPLY_64;
|
||||||
guint8 buf[sizeof(guint32) + sizeof(BinderTransactionData64)];
|
guint8 buf[sizeof(guint32) + sizeof(BinderTransactionData64)];
|
||||||
@@ -398,13 +645,34 @@ test_binder_br_reply(
|
|||||||
test_binder_fill_transaction_data((void*)(buf + sizeof(cmd)),
|
test_binder_fill_transaction_data((void*)(buf + sizeof(cmd)),
|
||||||
handle, code, bytes);
|
handle, code, bytes);
|
||||||
|
|
||||||
return test_binder_push_data(fd, buf);
|
push(fd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_reply_status(
|
test_binder_br_reply(
|
||||||
int fd,
|
int fd,
|
||||||
gint32 status)
|
guint32 handle,
|
||||||
|
guint32 code,
|
||||||
|
const GByteArray* bytes)
|
||||||
|
{
|
||||||
|
test_binder_br_reply1(fd, handle, code, bytes, test_binder_push_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_br_reply_later(
|
||||||
|
int fd,
|
||||||
|
guint32 handle,
|
||||||
|
guint32 code,
|
||||||
|
const GByteArray* bytes)
|
||||||
|
{
|
||||||
|
test_binder_br_reply1(fd, handle, code, bytes, test_binder_push_data_later);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_br_reply_status1(
|
||||||
|
int fd,
|
||||||
|
gint32 status,
|
||||||
|
TestBinderPushDataFunc push)
|
||||||
{
|
{
|
||||||
guint8 buf[sizeof(guint32) + sizeof(BinderTransactionData64)];
|
guint8 buf[sizeof(guint32) + sizeof(BinderTransactionData64)];
|
||||||
guint32* cmd = (void*)buf;
|
guint32* cmd = (void*)buf;
|
||||||
@@ -416,7 +684,24 @@ test_binder_br_reply_status(
|
|||||||
tr->data_size = sizeof(status);
|
tr->data_size = sizeof(status);
|
||||||
/* This memory should eventually get deallocated with BC_FREE_BUFFER_64 */
|
/* This memory should eventually get deallocated with BC_FREE_BUFFER_64 */
|
||||||
tr->data_buffer = (gsize)g_memdup(&status, sizeof(status));
|
tr->data_buffer = (gsize)g_memdup(&status, sizeof(status));
|
||||||
return test_binder_push_data(fd, buf);
|
|
||||||
|
push(fd, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_br_reply_status(
|
||||||
|
int fd,
|
||||||
|
gint32 status)
|
||||||
|
{
|
||||||
|
test_binder_br_reply_status1(fd, status, test_binder_push_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_br_reply_status_later(
|
||||||
|
int fd,
|
||||||
|
gint32 status)
|
||||||
|
{
|
||||||
|
test_binder_br_reply_status1(fd, status, test_binder_push_data_later);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -440,6 +725,7 @@ gbinder_system_open(
|
|||||||
node->path = g_strdup(path);
|
node->path = g_strdup(path);
|
||||||
node->refcount = 1;
|
node->refcount = 1;
|
||||||
node->io = &test_io_64;
|
node->io = &test_io_64;
|
||||||
|
node->destroy_map = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
if (!test_node_map) {
|
if (!test_node_map) {
|
||||||
test_node_map = g_hash_table_new(g_str_hash, g_str_equal);
|
test_node_map = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
}
|
}
|
||||||
@@ -466,24 +752,20 @@ int
|
|||||||
gbinder_system_close(
|
gbinder_system_close(
|
||||||
int fd)
|
int fd)
|
||||||
{
|
{
|
||||||
GASSERT(test_fd_map);
|
TestBinder* binder = test_binder_from_fd(fd);
|
||||||
if (test_fd_map) {
|
|
||||||
gpointer key = GINT_TO_POINTER(fd);
|
|
||||||
TestBinder* binder = g_hash_table_lookup(test_fd_map, key);
|
|
||||||
|
|
||||||
GASSERT(binder);
|
if (binder) {
|
||||||
if (binder) {
|
g_hash_table_remove(test_fd_map, GINT_TO_POINTER(fd));
|
||||||
g_hash_table_remove(test_fd_map, key);
|
if (!g_hash_table_size(test_fd_map)) {
|
||||||
if (!g_hash_table_size(test_fd_map)) {
|
g_hash_table_unref(test_fd_map);
|
||||||
g_hash_table_unref(test_fd_map);
|
test_fd_map = NULL;
|
||||||
test_fd_map = NULL;
|
|
||||||
}
|
|
||||||
test_binder_node_unref(binder->node);
|
|
||||||
close(binder->public_fd);
|
|
||||||
close(binder->private_fd);
|
|
||||||
g_free(binder);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
test_binder_submit_thread_free(binder->submit_thread);
|
||||||
|
test_binder_node_unref(binder->node);
|
||||||
|
close(binder->public_fd);
|
||||||
|
close(binder->private_fd);
|
||||||
|
g_free(binder);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -495,27 +777,21 @@ gbinder_system_ioctl(
|
|||||||
int request,
|
int request,
|
||||||
void* data)
|
void* data)
|
||||||
{
|
{
|
||||||
GASSERT(test_fd_map);
|
TestBinder* binder = test_binder_from_fd(fd);
|
||||||
if (test_fd_map) {
|
if (binder) {
|
||||||
gpointer key = GINT_TO_POINTER(fd);
|
const TestBinderIo* io = binder->node->io;
|
||||||
TestBinder* binder = g_hash_table_lookup(test_fd_map, key);
|
|
||||||
|
|
||||||
GASSERT(binder);
|
switch (request) {
|
||||||
if (binder) {
|
case BINDER_VERSION:
|
||||||
const TestBinderIo* io = binder->node->io;
|
return test_binder_ioctl_version(binder, data);
|
||||||
|
case BINDER_SET_MAX_THREADS:
|
||||||
switch (request) {
|
return 0;
|
||||||
case BINDER_VERSION:
|
default:
|
||||||
return test_binder_ioctl_version(binder, data);
|
if (request == io->write_read_request) {
|
||||||
case BINDER_SET_MAX_THREADS:
|
return io->handle_write_read(binder, data);
|
||||||
return 0;
|
} else {
|
||||||
default:
|
errno = EINVAL;
|
||||||
if (request == io->write_read_request) {
|
return -1;
|
||||||
return io->handle_write_read(binder, data);
|
|
||||||
} else {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -35,66 +35,93 @@
|
|||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_noop(
|
test_binder_br_noop(
|
||||||
int fd);
|
int fd);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_increfs(
|
test_binder_br_increfs(
|
||||||
int fd,
|
int fd,
|
||||||
void* ptr);
|
void* ptr);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_acquire(
|
test_binder_br_acquire(
|
||||||
int fd,
|
int fd,
|
||||||
void* ptr);
|
void* ptr);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_release(
|
test_binder_br_release(
|
||||||
int fd,
|
int fd,
|
||||||
void* ptr);
|
void* ptr);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_decrefs(
|
test_binder_br_decrefs(
|
||||||
int fd,
|
int fd,
|
||||||
void* ptr);
|
void* ptr);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_transaction_complete(
|
test_binder_br_transaction_complete(
|
||||||
int fd);
|
int fd);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
|
test_binder_br_transaction_complete_later(
|
||||||
|
int fd);
|
||||||
|
|
||||||
|
void
|
||||||
test_binder_br_dead_binder(
|
test_binder_br_dead_binder(
|
||||||
int fd,
|
int fd,
|
||||||
guint handle);
|
guint handle);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_dead_reply(
|
test_binder_br_dead_reply(
|
||||||
int fd);
|
int fd);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_failed_reply(
|
test_binder_br_failed_reply(
|
||||||
int fd);
|
int fd);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_transaction(
|
test_binder_br_transaction(
|
||||||
int fd,
|
int fd,
|
||||||
void* target,
|
void* target,
|
||||||
guint32 code,
|
guint32 code,
|
||||||
const GByteArray* bytes);
|
const GByteArray* bytes);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_reply(
|
test_binder_br_reply(
|
||||||
int fd,
|
int fd,
|
||||||
guint32 handle,
|
guint32 handle,
|
||||||
guint32 code,
|
guint32 code,
|
||||||
const GByteArray* bytes);
|
const GByteArray* bytes);
|
||||||
|
|
||||||
gboolean
|
void
|
||||||
test_binder_br_reply_status(
|
test_binder_br_reply_status(
|
||||||
int fd,
|
int fd,
|
||||||
gint32 status);
|
gint32 status);
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_br_reply_later(
|
||||||
|
int fd,
|
||||||
|
guint32 handle,
|
||||||
|
guint32 code,
|
||||||
|
const GByteArray* bytes);
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_br_reply_status_later(
|
||||||
|
int fd,
|
||||||
|
gint32 status);
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_set_looper_enabled(
|
||||||
|
int fd,
|
||||||
|
gboolean enabled);
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binder_set_destroy(
|
||||||
|
int fd,
|
||||||
|
gpointer ptr,
|
||||||
|
GDestroyNotify destroy);
|
||||||
|
|
||||||
#endif /* TEST_BINDER_H */
|
#endif /* TEST_BINDER_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
TESTS="\
|
TESTS="\
|
||||||
unit_buffer \
|
unit_buffer \
|
||||||
|
unit_cleanup \
|
||||||
unit_client \
|
unit_client \
|
||||||
unit_driver \
|
unit_driver \
|
||||||
unit_ipc \
|
unit_ipc \
|
||||||
@@ -16,6 +17,9 @@ unit_reader \
|
|||||||
unit_remote_object \
|
unit_remote_object \
|
||||||
unit_remote_reply \
|
unit_remote_reply \
|
||||||
unit_remote_request \
|
unit_remote_request \
|
||||||
|
unit_servicemanager \
|
||||||
|
unit_servicename \
|
||||||
|
unit_servicepoll \
|
||||||
unit_writer"
|
unit_writer"
|
||||||
|
|
||||||
function err() {
|
function err() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -46,19 +46,22 @@ void
|
|||||||
test_null(
|
test_null(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderBuffer* buf = gbinder_buffer_new(NULL, NULL, 0);
|
GBinderBuffer* buf = gbinder_buffer_new(NULL, NULL, 0, NULL);
|
||||||
GBinderBuffer* buf2;
|
GBinderBuffer* buf2;
|
||||||
|
gsize size = 1;
|
||||||
|
|
||||||
gbinder_buffer_free(buf);
|
gbinder_buffer_free(buf);
|
||||||
|
|
||||||
/* No need to reference the driver if there's no data */
|
/* No need to reference the driver if there's no data */
|
||||||
buf = gbinder_buffer_new(driver, NULL, 0);
|
buf = gbinder_buffer_new(driver, NULL, 0, NULL);
|
||||||
g_assert(!gbinder_buffer_driver(buf));
|
g_assert(!gbinder_buffer_driver(buf));
|
||||||
gbinder_buffer_free(buf);
|
gbinder_buffer_free(buf);
|
||||||
|
|
||||||
buf = gbinder_buffer_new_with_parent(NULL, NULL, 0);
|
buf = gbinder_buffer_new_with_parent(NULL, NULL, 0);
|
||||||
buf2 = gbinder_buffer_new_with_parent(buf, NULL, 0);
|
buf2 = gbinder_buffer_new_with_parent(buf, NULL, 0);
|
||||||
|
g_assert(!gbinder_buffer_objects(buf));
|
||||||
|
g_assert(!gbinder_buffer_objects(buf2));
|
||||||
g_assert(!gbinder_buffer_driver(buf));
|
g_assert(!gbinder_buffer_driver(buf));
|
||||||
g_assert(!gbinder_buffer_driver(buf2));
|
g_assert(!gbinder_buffer_driver(buf2));
|
||||||
gbinder_buffer_free(buf);
|
gbinder_buffer_free(buf);
|
||||||
@@ -66,6 +69,11 @@ test_null(
|
|||||||
|
|
||||||
gbinder_buffer_free(NULL);
|
gbinder_buffer_free(NULL);
|
||||||
g_assert(!gbinder_buffer_driver(NULL));
|
g_assert(!gbinder_buffer_driver(NULL));
|
||||||
|
g_assert(!gbinder_buffer_objects(NULL));
|
||||||
|
g_assert(!gbinder_buffer_io(NULL));
|
||||||
|
g_assert(!gbinder_buffer_data(NULL, NULL));
|
||||||
|
g_assert(!gbinder_buffer_data(NULL, &size));
|
||||||
|
g_assert(!size);
|
||||||
gbinder_driver_unref(driver);
|
gbinder_driver_unref(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,12 +88,20 @@ test_parent(
|
|||||||
{
|
{
|
||||||
static const guint8 data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
|
static const guint8 data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
|
||||||
void* ptr = g_memdup(data, sizeof(data));
|
void* ptr = g_memdup(data, sizeof(data));
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
gsize size = 0;
|
||||||
GBinderBuffer* parent = gbinder_buffer_new(driver, ptr, sizeof(data));
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
|
GBinderBuffer* parent = gbinder_buffer_new(driver, ptr, sizeof(data), NULL);
|
||||||
GBinderBuffer* buf = gbinder_buffer_new_with_parent
|
GBinderBuffer* buf = gbinder_buffer_new_with_parent
|
||||||
(parent, ptr, sizeof(data));
|
(parent, ptr, sizeof(data));
|
||||||
|
|
||||||
g_assert(gbinder_buffer_driver(buf) == driver);
|
g_assert(gbinder_buffer_driver(buf) == driver);
|
||||||
|
g_assert(gbinder_buffer_io(buf));
|
||||||
|
g_assert(gbinder_buffer_io(buf) == gbinder_driver_io(driver));
|
||||||
|
g_assert(gbinder_buffer_contents(buf));
|
||||||
|
g_assert(gbinder_buffer_data(buf, NULL) == ptr);
|
||||||
|
g_assert(gbinder_buffer_data(buf, &size) == ptr);
|
||||||
|
g_assert(size == sizeof(data));
|
||||||
|
|
||||||
gbinder_buffer_free(buf);
|
gbinder_buffer_free(buf);
|
||||||
gbinder_buffer_free(parent);
|
gbinder_buffer_free(parent);
|
||||||
gbinder_driver_unref(driver);
|
gbinder_driver_unref(driver);
|
||||||
|
|||||||
5
unit/unit_cleanup/Makefile
Normal file
5
unit/unit_cleanup/Makefile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# -*- Mode: makefile-gmake -*-
|
||||||
|
|
||||||
|
EXE = unit_cleanup
|
||||||
|
|
||||||
|
include ../common/Makefile
|
||||||
126
unit/unit_cleanup/unit_cleanup.c
Normal file
126
unit/unit_cleanup/unit_cleanup.c
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* 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 "test_binder.h"
|
||||||
|
|
||||||
|
#include "gbinder_cleanup.h"
|
||||||
|
|
||||||
|
static TestOpt test_opt;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_cleanup_inc(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
(*((int*)data))++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* null
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_null(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
g_assert(!gbinder_cleanup_add(NULL, NULL, NULL));
|
||||||
|
gbinder_cleanup_free(NULL);
|
||||||
|
gbinder_cleanup_reset(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* basic
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_basic(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
int n1 = 0, n2 =0;
|
||||||
|
GBinderCleanup* cleanup = gbinder_cleanup_add(NULL, test_cleanup_inc, &n1);
|
||||||
|
|
||||||
|
g_assert(cleanup);
|
||||||
|
g_assert(gbinder_cleanup_add(cleanup, test_cleanup_inc, &n2) == cleanup);
|
||||||
|
gbinder_cleanup_free(cleanup);
|
||||||
|
g_assert(n1 == 1);
|
||||||
|
g_assert(n2 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* reset
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_reset(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
int n1 = 0, n2 =0;
|
||||||
|
GBinderCleanup* cleanup = gbinder_cleanup_add(NULL, test_cleanup_inc, &n1);
|
||||||
|
|
||||||
|
g_assert(cleanup);
|
||||||
|
g_assert(gbinder_cleanup_add(cleanup, test_cleanup_inc, &n2) == cleanup);
|
||||||
|
gbinder_cleanup_reset(cleanup);
|
||||||
|
g_assert(n1 == 1);
|
||||||
|
g_assert(n2 == 1);
|
||||||
|
|
||||||
|
gbinder_cleanup_free(cleanup);
|
||||||
|
g_assert(n1 == 1);
|
||||||
|
g_assert(n2 == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* Common
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
#define TEST_PREFIX "/cleanup/"
|
||||||
|
#define TEST_(t) TEST_PREFIX t
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
g_test_add_func(TEST_("null"), test_null);
|
||||||
|
g_test_add_func(TEST_("basic"), test_basic);
|
||||||
|
g_test_add_func(TEST_("reset"), test_reset);
|
||||||
|
test_init(&test_opt, argc, argv);
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -54,7 +54,7 @@ test_client_new(
|
|||||||
guint handle,
|
guint handle,
|
||||||
const char* iface)
|
const char* iface)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, handle);
|
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, handle);
|
||||||
GBinderClient* client = gbinder_client_new(obj, iface);
|
GBinderClient* client = gbinder_client_new(obj, iface);
|
||||||
@@ -74,16 +74,15 @@ void
|
|||||||
test_null(
|
test_null(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderClient* null = NULL;
|
|
||||||
|
|
||||||
g_assert(!gbinder_client_new(NULL, NULL));
|
g_assert(!gbinder_client_new(NULL, NULL));
|
||||||
g_assert(!gbinder_client_ref(null));
|
g_assert(!gbinder_client_ref(NULL));
|
||||||
gbinder_client_unref(null);
|
g_assert(!gbinder_client_interface(NULL));
|
||||||
|
gbinder_client_unref(NULL);
|
||||||
g_assert(!gbinder_client_new_request(NULL));
|
g_assert(!gbinder_client_new_request(NULL));
|
||||||
g_assert(!gbinder_client_transact_sync_reply(null, 0, NULL, NULL));
|
g_assert(!gbinder_client_transact_sync_reply(NULL, 0, NULL, NULL));
|
||||||
g_assert(gbinder_client_transact_sync_oneway(null, 0, NULL) == (-EINVAL));
|
g_assert(gbinder_client_transact_sync_oneway(NULL, 0, NULL) == (-EINVAL));
|
||||||
g_assert(!gbinder_client_transact(null, 0, 0, NULL, NULL, NULL, NULL));
|
g_assert(!gbinder_client_transact(NULL, 0, 0, NULL, NULL, NULL, NULL));
|
||||||
gbinder_client_cancel(null, 0);
|
gbinder_client_cancel(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
@@ -95,14 +94,15 @@ void
|
|||||||
test_basic(
|
test_basic(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0);
|
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0);
|
||||||
GBinderClient* client = gbinder_client_new(obj, "foo");
|
const char* iface = "foo";
|
||||||
|
GBinderClient* client = gbinder_client_new(obj, iface);
|
||||||
|
|
||||||
g_assert(!gbinder_client_new(obj, NULL));
|
|
||||||
g_assert(client);
|
g_assert(client);
|
||||||
g_assert(gbinder_client_ref(client) == client);
|
g_assert(gbinder_client_ref(client) == client);
|
||||||
|
g_assert(!g_strcmp0(gbinder_client_interface(client), iface));
|
||||||
gbinder_client_unref(client);
|
gbinder_client_unref(client);
|
||||||
gbinder_client_cancel(client, 0); /* does nothing */
|
gbinder_client_cancel(client, 0); /* does nothing */
|
||||||
|
|
||||||
@@ -111,6 +111,64 @@ test_basic(
|
|||||||
gbinder_ipc_unref(ipc);
|
gbinder_ipc_unref(ipc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* no_header
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_no_header(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
GBinderClient* client = test_client_new(0, NULL);
|
||||||
|
int fd = gbinder_driver_fd(gbinder_client_ipc(client)->driver);
|
||||||
|
|
||||||
|
test_binder_br_transaction_complete(fd);
|
||||||
|
g_assert(gbinder_client_transact_sync_oneway(client, 0, NULL) ==
|
||||||
|
GBINDER_STATUS_OK);
|
||||||
|
|
||||||
|
gbinder_client_unref(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* dead
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_dead_done(
|
||||||
|
GBinderRemoteObject* obj,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
GVERBOSE_("");
|
||||||
|
test_quit_later((GMainLoop*)user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_dead(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const guint handle = 1;
|
||||||
|
GBinderClient* client = test_client_new(handle, "foo");
|
||||||
|
GBinderRemoteObject* obj = client->remote;
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
const int fd = gbinder_driver_fd(gbinder_client_ipc(client)->driver);
|
||||||
|
gbinder_remote_object_add_death_handler(obj, test_dead_done, loop);
|
||||||
|
|
||||||
|
test_binder_br_dead_binder(fd, handle);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
g_assert(gbinder_remote_object_is_dead(obj));
|
||||||
|
|
||||||
|
g_assert(!gbinder_client_transact_sync_reply(client, 0, NULL, NULL));
|
||||||
|
g_assert(gbinder_client_transact_sync_oneway(client, 0, NULL) == -ESTALE);
|
||||||
|
g_assert(!gbinder_client_transact(client, 0, 0, NULL, NULL, NULL, NULL));
|
||||||
|
|
||||||
|
gbinder_client_unref(client);
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* sync_oneway
|
* sync_oneway
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -164,10 +222,10 @@ test_sync_reply_tx(
|
|||||||
data = gbinder_local_reply_data(reply);
|
data = gbinder_local_reply_data(reply);
|
||||||
g_assert(data);
|
g_assert(data);
|
||||||
|
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_transaction_complete(fd));
|
test_binder_br_transaction_complete(fd);
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
|
test_binder_br_reply(fd, handle, code, data->bytes);
|
||||||
|
|
||||||
tx_reply = gbinder_client_transact_sync_reply(client, 0, req, &status);
|
tx_reply = gbinder_client_transact_sync_reply(client, 0, req, &status);
|
||||||
g_assert(tx_reply);
|
g_assert(tx_reply);
|
||||||
@@ -265,10 +323,10 @@ test_reply_tx(
|
|||||||
data = gbinder_local_reply_data(reply);
|
data = gbinder_local_reply_data(reply);
|
||||||
g_assert(data);
|
g_assert(data);
|
||||||
|
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_transaction_complete(fd));
|
test_binder_br_transaction_complete(fd);
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
|
test_binder_br_reply(fd, handle, code, data->bytes);
|
||||||
|
|
||||||
id = gbinder_client_transact(client, 0, 0, req, done, destroy, loop);
|
id = gbinder_client_transact(client, 0, 0, req, done, destroy, loop);
|
||||||
g_assert(id);
|
g_assert(id);
|
||||||
@@ -326,17 +384,20 @@ test_reply_ok3(
|
|||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
#define TEST_PREFIX "/client/"
|
#define TEST_PREFIX "/client/"
|
||||||
|
#define TEST_(t) TEST_PREFIX t
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
g_test_add_func(TEST_PREFIX "null", test_null);
|
g_test_add_func(TEST_("null"), test_null);
|
||||||
g_test_add_func(TEST_PREFIX "basic", test_basic);
|
g_test_add_func(TEST_("basic"), test_basic);
|
||||||
g_test_add_func(TEST_PREFIX "sync_oneway", test_sync_oneway);
|
g_test_add_func(TEST_("dead"), test_dead);
|
||||||
g_test_add_func(TEST_PREFIX "sync_reply", test_sync_reply);
|
g_test_add_func(TEST_("no_header"), test_no_header);
|
||||||
g_test_add_func(TEST_PREFIX "reply/ok1", test_reply_ok1);
|
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);
|
||||||
g_test_add_func(TEST_PREFIX "reply/ok2", test_reply_ok2);
|
g_test_add_func(TEST_("sync_reply"), test_sync_reply);
|
||||||
g_test_add_func(TEST_PREFIX "reply/ok3", test_reply_ok3);
|
g_test_add_func(TEST_("reply/ok1"), test_reply_ok1);
|
||||||
|
g_test_add_func(TEST_("reply/ok2"), test_reply_ok2);
|
||||||
|
g_test_add_func(TEST_("reply/ok3"), test_reply_ok3);
|
||||||
test_init(&test_opt, argc, argv);
|
test_init(&test_opt, argc, argv);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -56,8 +56,8 @@ test_basic(
|
|||||||
GBinderDriver* driver;
|
GBinderDriver* driver;
|
||||||
const char* dev = GBINDER_DEFAULT_BINDER;
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
|
||||||
g_assert(!gbinder_driver_new(""));
|
g_assert(!gbinder_driver_new("", NULL));
|
||||||
driver = gbinder_driver_new(dev);
|
driver = gbinder_driver_new(dev, NULL);
|
||||||
g_assert(driver);
|
g_assert(driver);
|
||||||
g_assert(!g_strcmp0(dev, gbinder_driver_dev(driver)));
|
g_assert(!g_strcmp0(dev, gbinder_driver_dev(driver)));
|
||||||
g_assert(gbinder_driver_ref(driver) == driver);
|
g_assert(gbinder_driver_ref(driver) == driver);
|
||||||
@@ -86,12 +86,12 @@ void
|
|||||||
test_noop(
|
test_noop(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const int fd = gbinder_driver_fd(driver);
|
const int fd = gbinder_driver_fd(driver);
|
||||||
|
|
||||||
g_assert(driver);
|
g_assert(driver);
|
||||||
g_assert(fd >= 0);
|
g_assert(fd >= 0);
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(gbinder_driver_poll(driver, NULL) == POLLIN);
|
g_assert(gbinder_driver_poll(driver, NULL) == POLLIN);
|
||||||
g_assert(gbinder_driver_read(driver, NULL, NULL) == 0);
|
g_assert(gbinder_driver_read(driver, NULL, NULL) == 0);
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ test_local_request(
|
|||||||
0x00, 0x00, 0x00, 0x00
|
0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderLocalRequest* req = gbinder_driver_local_request_new(driver, iface);
|
GBinderLocalRequest* req = gbinder_driver_local_request_new(driver, iface);
|
||||||
GBinderOutputData* data = gbinder_local_request_data(req);
|
GBinderOutputData* data = gbinder_local_request_data(req);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived
|
||||||
* without specific prior written permission.
|
* from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -52,6 +52,24 @@
|
|||||||
|
|
||||||
static TestOpt test_opt;
|
static TestOpt test_opt;
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
test_unref_ipc(
|
||||||
|
gpointer ipc)
|
||||||
|
{
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_quit_when_destroyed(
|
||||||
|
gpointer loop,
|
||||||
|
GObject* obj)
|
||||||
|
{
|
||||||
|
test_quit_later((GMainLoop*)loop);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* null
|
* null
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -91,8 +109,8 @@ void
|
|||||||
test_basic(
|
test_basic(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
|
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
|
||||||
|
|
||||||
g_assert(ipc);
|
g_assert(ipc);
|
||||||
g_assert(ipc2);
|
g_assert(ipc2);
|
||||||
@@ -101,14 +119,54 @@ test_basic(
|
|||||||
gbinder_ipc_unref(ipc2);
|
gbinder_ipc_unref(ipc2);
|
||||||
|
|
||||||
/* Second gbinder_ipc_new returns the same (default) object */
|
/* Second gbinder_ipc_new returns the same (default) object */
|
||||||
g_assert(gbinder_ipc_new(NULL) == ipc);
|
g_assert(gbinder_ipc_new(NULL, NULL) == ipc);
|
||||||
g_assert(gbinder_ipc_new("") == ipc);
|
g_assert(gbinder_ipc_new("", NULL) == ipc);
|
||||||
gbinder_ipc_unref(ipc);
|
gbinder_ipc_unref(ipc);
|
||||||
gbinder_ipc_unref(ipc);
|
gbinder_ipc_unref(ipc);
|
||||||
gbinder_ipc_unref(ipc);
|
gbinder_ipc_unref(ipc);
|
||||||
|
|
||||||
/* Invalid path */
|
/* Invalid path */
|
||||||
g_assert(!gbinder_ipc_new("invalid path"));
|
g_assert(!gbinder_ipc_new("invalid path", NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* async_oneway
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_async_oneway_done(
|
||||||
|
GBinderIpc* ipc,
|
||||||
|
GBinderRemoteReply* reply,
|
||||||
|
int status,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
g_assert(!status);
|
||||||
|
g_assert(!reply);
|
||||||
|
test_quit_later((GMainLoop*)user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_async_oneway(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
gulong id;
|
||||||
|
|
||||||
|
test_binder_br_transaction_complete(fd);
|
||||||
|
id = gbinder_ipc_transact(ipc, 0, 1, GBINDER_TX_FLAG_ONEWAY,
|
||||||
|
req, test_async_oneway_done, NULL, loop);
|
||||||
|
g_assert(id);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
g_main_loop_unref(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
@@ -120,12 +178,12 @@ void
|
|||||||
test_sync_oneway(
|
test_sync_oneway(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
|
|
||||||
g_assert(test_binder_br_transaction_complete(fd));
|
test_binder_br_transaction_complete(fd);
|
||||||
g_assert(gbinder_ipc_transact_sync_oneway(ipc, 0, 1, req) ==
|
g_assert(gbinder_ipc_transact_sync_oneway(ipc, 0, 1, req) ==
|
||||||
GBINDER_STATUS_OK);
|
GBINDER_STATUS_OK);
|
||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
@@ -141,7 +199,7 @@ void
|
|||||||
test_sync_reply_ok_status(
|
test_sync_reply_ok_status(
|
||||||
int* status)
|
int* status)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
@@ -157,10 +215,10 @@ test_sync_reply_ok_status(
|
|||||||
data = gbinder_local_reply_data(reply);
|
data = gbinder_local_reply_data(reply);
|
||||||
g_assert(data);
|
g_assert(data);
|
||||||
|
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_transaction_complete(fd));
|
test_binder_br_transaction_complete(fd);
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
|
test_binder_br_reply(fd, handle, code, data->bytes);
|
||||||
|
|
||||||
tx_reply = gbinder_ipc_transact_sync_reply(ipc, handle, code, req, status);
|
tx_reply = gbinder_ipc_transact_sync_reply(ipc, handle, code, req, status);
|
||||||
g_assert(tx_reply);
|
g_assert(tx_reply);
|
||||||
@@ -196,7 +254,7 @@ void
|
|||||||
test_sync_reply_error(
|
test_sync_reply_error(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
@@ -205,10 +263,10 @@ test_sync_reply_error(
|
|||||||
const gint expected_status = GBINDER_STATUS_FAILED;
|
const gint expected_status = GBINDER_STATUS_FAILED;
|
||||||
int status = INT_MAX;
|
int status = INT_MAX;
|
||||||
|
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_transaction_complete(fd));
|
test_binder_br_transaction_complete(fd);
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_reply_status(fd, expected_status));
|
test_binder_br_reply_status(fd, expected_status);
|
||||||
|
|
||||||
g_assert(!gbinder_ipc_transact_sync_reply(ipc, handle, code, req, &status));
|
g_assert(!gbinder_ipc_transact_sync_reply(ipc, handle, code, req, &status));
|
||||||
g_assert(status == expected_status);
|
g_assert(status == expected_status);
|
||||||
@@ -253,7 +311,7 @@ void
|
|||||||
test_transact_ok(
|
test_transact_ok(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
@@ -268,10 +326,10 @@ test_transact_ok(
|
|||||||
data = gbinder_local_reply_data(reply);
|
data = gbinder_local_reply_data(reply);
|
||||||
g_assert(data);
|
g_assert(data);
|
||||||
|
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_transaction_complete(fd));
|
test_binder_br_transaction_complete(fd);
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
|
test_binder_br_reply(fd, handle, code, data->bytes);
|
||||||
|
|
||||||
id = gbinder_ipc_transact(ipc, handle, code, 0, req,
|
id = gbinder_ipc_transact(ipc, handle, code, 0, req,
|
||||||
test_transact_ok_done, test_transact_ok_destroy, loop);
|
test_transact_ok_done, test_transact_ok_destroy, loop);
|
||||||
@@ -310,15 +368,15 @@ void
|
|||||||
test_transact_dead(
|
test_transact_dead(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
gulong id;
|
gulong id;
|
||||||
|
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_dead_reply(fd));
|
test_binder_br_dead_reply(fd);
|
||||||
|
|
||||||
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_dead_done,
|
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_dead_done,
|
||||||
NULL, loop);
|
NULL, loop);
|
||||||
@@ -356,15 +414,15 @@ void
|
|||||||
test_transact_failed(
|
test_transact_failed(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
gulong id;
|
gulong id;
|
||||||
|
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_failed_reply(fd));
|
test_binder_br_failed_reply(fd);
|
||||||
|
|
||||||
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_failed_done,
|
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_failed_done,
|
||||||
NULL, loop);
|
NULL, loop);
|
||||||
@@ -404,15 +462,15 @@ void
|
|||||||
test_transact_status(
|
test_transact_status(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
gulong id;
|
gulong id;
|
||||||
|
|
||||||
g_assert(test_binder_br_noop(fd));
|
test_binder_br_noop(fd);
|
||||||
g_assert(test_binder_br_reply_status(fd, EXPECTED_STATUS));
|
test_binder_br_reply_status(fd, EXPECTED_STATUS);
|
||||||
|
|
||||||
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_status_done,
|
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_status_done,
|
||||||
NULL, loop);
|
NULL, loop);
|
||||||
@@ -445,7 +503,7 @@ void
|
|||||||
test_transact_custom(
|
test_transact_custom(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
gulong id = gbinder_ipc_transact_custom(ipc, NULL,
|
gulong id = gbinder_ipc_transact_custom(ipc, NULL,
|
||||||
test_transact_custom_done, NULL, loop);
|
test_transact_custom_done, NULL, loop);
|
||||||
@@ -475,7 +533,7 @@ void
|
|||||||
test_transact_custom2(
|
test_transact_custom2(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
gulong id = gbinder_ipc_transact_custom(ipc, NULL, NULL,
|
gulong id = gbinder_ipc_transact_custom(ipc, NULL, NULL,
|
||||||
test_transact_custom_destroy, loop);
|
test_transact_custom_destroy, loop);
|
||||||
@@ -487,6 +545,38 @@ test_transact_custom2(
|
|||||||
g_main_loop_unref(loop);
|
g_main_loop_unref(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* transact_custom3
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_transact_custom3_exec(
|
||||||
|
const GBinderIpcTx* tx)
|
||||||
|
{
|
||||||
|
GVERBOSE_("");
|
||||||
|
gbinder_ipc_unref(tx->ipc);
|
||||||
|
test_quit_later((GMainLoop*)tx->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_transact_custom3(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
/* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
|
||||||
|
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_custom3_exec,
|
||||||
|
NULL, NULL, loop);
|
||||||
|
|
||||||
|
g_assert(id);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
/* Reference to GBinderIpc is released by test_transact_custom3_exec */
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* transact_cancel
|
* transact_cancel
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -522,7 +612,7 @@ void
|
|||||||
test_transact_cancel(
|
test_transact_cancel(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel_exec,
|
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel_exec,
|
||||||
test_transact_cancel_done, test_transact_cancel_destroy, loop);
|
test_transact_cancel_done, test_transact_cancel_destroy, loop);
|
||||||
@@ -566,7 +656,7 @@ void
|
|||||||
test_transact_cancel2(
|
test_transact_cancel2(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
/* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
|
/* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
|
||||||
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel2_exec,
|
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel2_exec,
|
||||||
@@ -606,37 +696,20 @@ test_transact_incoming_proc(
|
|||||||
return gbinder_local_object_new_reply(obj);
|
return gbinder_local_object_new_reply(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
gboolean
|
|
||||||
test_transact_unref_ipc(
|
|
||||||
gpointer ipc)
|
|
||||||
{
|
|
||||||
gbinder_ipc_unref(ipc);
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
test_transact_done(
|
|
||||||
gpointer loop,
|
|
||||||
GObject* ipc)
|
|
||||||
{
|
|
||||||
test_quit_later((GMainLoop*)loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
test_transact_incoming(
|
test_transact_incoming(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
const char* dev = gbinder_driver_dev(ipc->driver);
|
const char* dev = gbinder_driver_dev(ipc->driver);
|
||||||
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
|
const char* const ifaces[] = { "test", NULL };
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object
|
GBinderLocalObject* obj = gbinder_local_object_new
|
||||||
(ipc, "test", test_transact_incoming_proc, loop);
|
(ipc, ifaces, test_transact_incoming_proc, loop);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
GBinderOutputData* data;
|
GBinderOutputData* data;
|
||||||
GBinderWriter writer;
|
GBinderWriter writer;
|
||||||
@@ -647,21 +720,22 @@ test_transact_incoming(
|
|||||||
data = gbinder_local_request_data(req);
|
data = gbinder_local_request_data(req);
|
||||||
|
|
||||||
test_binder_br_transaction(fd, obj, 1, data->bytes);
|
test_binder_br_transaction(fd, obj, 1, data->bytes);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
/* Now we need to wait until GBinderIpc is destroyed */
|
/* Now we need to wait until GBinderIpc is destroyed */
|
||||||
GDEBUG("waiting for GBinderIpc to get destroyed");
|
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||||
g_object_weak_ref(G_OBJECT(ipc), test_transact_done, loop);
|
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||||
gbinder_local_object_unref(obj);
|
gbinder_local_object_unref(obj);
|
||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
g_idle_add(test_transact_unref_ipc, ipc);
|
g_idle_add(test_unref_ipc, ipc);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
g_main_loop_unref(loop);
|
g_main_loop_unref(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* transact_incoming_status
|
* transact_status_reply
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -690,14 +764,15 @@ void
|
|||||||
test_transact_status_reply(
|
test_transact_status_reply(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
const int fd = gbinder_driver_fd(ipc->driver);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
const char* dev = gbinder_driver_dev(ipc->driver);
|
const char* dev = gbinder_driver_dev(ipc->driver);
|
||||||
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
|
const char* const ifaces[] = { "test", NULL };
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object
|
GBinderLocalObject* obj = gbinder_local_object_new
|
||||||
(ipc, "test", test_transact_status_reply_proc, loop);
|
(ipc, ifaces, test_transact_status_reply_proc, loop);
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
GBinderOutputData* data;
|
GBinderOutputData* data;
|
||||||
GBinderWriter writer;
|
GBinderWriter writer;
|
||||||
@@ -708,14 +783,193 @@ test_transact_status_reply(
|
|||||||
data = gbinder_local_request_data(req);
|
data = gbinder_local_request_data(req);
|
||||||
|
|
||||||
test_binder_br_transaction(fd, obj, 1, data->bytes);
|
test_binder_br_transaction(fd, obj, 1, data->bytes);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
/* Now we need to wait until GBinderIpc is destroyed */
|
/* Now we need to wait until GBinderIpc is destroyed */
|
||||||
GDEBUG("waiting for GBinderIpc to get destroyed");
|
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||||
g_object_weak_ref(G_OBJECT(ipc), test_transact_done, loop);
|
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||||
gbinder_local_object_unref(obj);
|
gbinder_local_object_unref(obj);
|
||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
g_idle_add(test_transact_unref_ipc, ipc);
|
g_idle_add(test_unref_ipc, ipc);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* transact_async
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
typedef struct test_transact_async_req {
|
||||||
|
GBinderLocalObject* obj;
|
||||||
|
GBinderRemoteRequest* req;
|
||||||
|
GMainLoop* loop;
|
||||||
|
} TestTransactAsyncReq;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_transact_async_done(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
TestTransactAsyncReq* test = data;
|
||||||
|
|
||||||
|
gbinder_local_object_unref(test->obj);
|
||||||
|
gbinder_remote_request_unref(test->req);
|
||||||
|
test_quit_later(test->loop);
|
||||||
|
g_free(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
test_transact_async_reply(
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
TestTransactAsyncReq* test = data;
|
||||||
|
GBinderLocalReply* reply = gbinder_local_object_new_reply(test->obj);
|
||||||
|
|
||||||
|
gbinder_remote_request_complete(test->req, reply, 0);
|
||||||
|
gbinder_local_reply_unref(reply);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderLocalReply*
|
||||||
|
test_transact_async_proc(
|
||||||
|
GBinderLocalObject* obj,
|
||||||
|
GBinderRemoteRequest* req,
|
||||||
|
guint code,
|
||||||
|
guint flags,
|
||||||
|
int* status,
|
||||||
|
void* loop)
|
||||||
|
{
|
||||||
|
TestTransactAsyncReq* test = g_new(TestTransactAsyncReq, 1);
|
||||||
|
|
||||||
|
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
|
||||||
|
g_assert(!flags);
|
||||||
|
g_assert(gbinder_remote_request_sender_pid(req) == getpid());
|
||||||
|
g_assert(gbinder_remote_request_sender_euid(req) == geteuid());
|
||||||
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), "test"));
|
||||||
|
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "message"));
|
||||||
|
g_assert(code == 1);
|
||||||
|
|
||||||
|
test->obj = gbinder_local_object_ref(obj);
|
||||||
|
test->req = gbinder_remote_request_ref(req);
|
||||||
|
test->loop = (GMainLoop*)loop;
|
||||||
|
|
||||||
|
gbinder_remote_request_block(req);
|
||||||
|
gbinder_remote_request_block(req); /* wrong state; has no effect */
|
||||||
|
|
||||||
|
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_transact_async_reply, test,
|
||||||
|
test_transact_async_done);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_transact_async(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
const char* dev = gbinder_driver_dev(ipc->driver);
|
||||||
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
|
const char* const ifaces[] = { "test", NULL };
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderLocalObject* obj = gbinder_local_object_new
|
||||||
|
(ipc, ifaces, test_transact_async_proc, loop);
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GBinderWriter writer;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
prot->write_rpc_header(&writer, "test");
|
||||||
|
gbinder_writer_append_string8(&writer, "message");
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
|
||||||
|
test_binder_br_transaction(fd, obj, 1, data->bytes);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
/* Now we need to wait until GBinderIpc is destroyed */
|
||||||
|
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||||
|
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
g_idle_add(test_unref_ipc, ipc);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* transact_async_sync
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderLocalReply*
|
||||||
|
test_transact_async_sync_proc(
|
||||||
|
GBinderLocalObject* obj,
|
||||||
|
GBinderRemoteRequest* req,
|
||||||
|
guint code,
|
||||||
|
guint flags,
|
||||||
|
int* status,
|
||||||
|
void* loop)
|
||||||
|
{
|
||||||
|
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
|
||||||
|
|
||||||
|
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
|
||||||
|
g_assert(!flags);
|
||||||
|
g_assert(gbinder_remote_request_sender_pid(req) == getpid());
|
||||||
|
g_assert(gbinder_remote_request_sender_euid(req) == geteuid());
|
||||||
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), "test"));
|
||||||
|
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "message"));
|
||||||
|
g_assert(code == 1);
|
||||||
|
|
||||||
|
/* Block and immediately complete the call */
|
||||||
|
gbinder_remote_request_block(req);
|
||||||
|
gbinder_remote_request_complete(req, reply, 0);
|
||||||
|
gbinder_remote_request_complete(req, reply, 0); /* This one is ignored */
|
||||||
|
gbinder_local_reply_unref(reply);
|
||||||
|
|
||||||
|
test_quit_later((GMainLoop*)loop);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_transact_async_sync(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
|
const GBinderIo* io = gbinder_driver_io(ipc->driver);
|
||||||
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
const char* dev = gbinder_driver_dev(ipc->driver);
|
||||||
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
|
const char* const ifaces[] = { "test", NULL };
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderLocalObject* obj = gbinder_local_object_new
|
||||||
|
(ipc, ifaces, test_transact_async_sync_proc, loop);
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GBinderWriter writer;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
prot->write_rpc_header(&writer, "test");
|
||||||
|
gbinder_writer_append_string8(&writer, "message");
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
|
||||||
|
test_binder_br_transaction(fd, obj, 1, data->bytes);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
/* Now we need to wait until GBinderIpc is destroyed */
|
||||||
|
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||||
|
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
g_idle_add(test_unref_ipc, ipc);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
g_main_loop_unref(loop);
|
g_main_loop_unref(loop);
|
||||||
@@ -726,26 +980,30 @@ test_transact_status_reply(
|
|||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
#define TEST_PREFIX "/ipc/"
|
#define TEST_PREFIX "/ipc/"
|
||||||
|
#define TEST_(t) TEST_PREFIX t
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
g_test_add_func(TEST_PREFIX "null", test_null);
|
g_test_add_func(TEST_("null"), test_null);
|
||||||
g_test_add_func(TEST_PREFIX "basic", test_basic);
|
g_test_add_func(TEST_("basic"), test_basic);
|
||||||
g_test_add_func(TEST_PREFIX "sync_oneway", test_sync_oneway);
|
g_test_add_func(TEST_("async_oneway"), test_async_oneway);
|
||||||
g_test_add_func(TEST_PREFIX "sync_reply_ok", test_sync_reply_ok);
|
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);
|
||||||
g_test_add_func(TEST_PREFIX "sync_reply_error", test_sync_reply_error);
|
g_test_add_func(TEST_("sync_reply_ok"), test_sync_reply_ok);
|
||||||
g_test_add_func(TEST_PREFIX "transact_ok", test_transact_ok);
|
g_test_add_func(TEST_("sync_reply_error"), test_sync_reply_error);
|
||||||
g_test_add_func(TEST_PREFIX "transact_dead", test_transact_dead);
|
g_test_add_func(TEST_("transact_ok"), test_transact_ok);
|
||||||
g_test_add_func(TEST_PREFIX "transact_failed", test_transact_failed);
|
g_test_add_func(TEST_("transact_dead"), test_transact_dead);
|
||||||
g_test_add_func(TEST_PREFIX "transact_status", test_transact_status);
|
g_test_add_func(TEST_("transact_failed"), test_transact_failed);
|
||||||
g_test_add_func(TEST_PREFIX "transact_custom", test_transact_custom);
|
g_test_add_func(TEST_("transact_status"), test_transact_status);
|
||||||
g_test_add_func(TEST_PREFIX "transact_custom2", test_transact_custom2);
|
g_test_add_func(TEST_("transact_custom"), test_transact_custom);
|
||||||
g_test_add_func(TEST_PREFIX "transact_cancel", test_transact_cancel);
|
g_test_add_func(TEST_("transact_custom2"), test_transact_custom2);
|
||||||
g_test_add_func(TEST_PREFIX "transact_cancel2", test_transact_cancel2);
|
g_test_add_func(TEST_("transact_custom3"), test_transact_custom3);
|
||||||
g_test_add_func(TEST_PREFIX "transact_incoming", test_transact_incoming);
|
g_test_add_func(TEST_("transact_cancel"), test_transact_cancel);
|
||||||
g_test_add_func(TEST_PREFIX "transact_status_reply",
|
g_test_add_func(TEST_("transact_cancel2"), test_transact_cancel2);
|
||||||
test_transact_status_reply);
|
g_test_add_func(TEST_("transact_incoming"), test_transact_incoming);
|
||||||
|
g_test_add_func(TEST_("transact_status_reply"), test_transact_status_reply);
|
||||||
|
g_test_add_func(TEST_("transact_async"), test_transact_async);
|
||||||
|
g_test_add_func(TEST_("transact_async_sync"), test_transact_async_sync);
|
||||||
test_init(&test_opt, argc, argv);
|
test_init(&test_opt, argc, argv);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -73,7 +73,8 @@ test_reader_data_init_for_reply(
|
|||||||
GUtilIntArray* offsets = gbinder_output_data_offsets(out);
|
GUtilIntArray* offsets = gbinder_output_data_offsets(out);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
|
||||||
g_memdup(out->bytes->data, out->bytes->len), out->bytes->len);
|
g_memdup(out->bytes->data, out->bytes->len),
|
||||||
|
out->bytes->len, NULL);
|
||||||
|
|
||||||
memset(data, 0, sizeof(*data));
|
memset(data, 0, sizeof(*data));
|
||||||
data->buffer = buf;
|
data->buffer = buf;
|
||||||
@@ -149,7 +150,9 @@ void
|
|||||||
test_basic(
|
test_basic(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
const char* const ifaces_foo[] = { "foo", NULL };
|
||||||
|
const char* const ifaces_bar[] = { "bar", NULL };
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderLocalObject* foo;
|
GBinderLocalObject* foo;
|
||||||
GBinderLocalObject* bar;
|
GBinderLocalObject* bar;
|
||||||
@@ -158,8 +161,8 @@ test_basic(
|
|||||||
g_assert(!gbinder_object_registry_get_local(reg, ipc));
|
g_assert(!gbinder_object_registry_get_local(reg, ipc));
|
||||||
|
|
||||||
/* Create a new local objects */
|
/* Create a new local objects */
|
||||||
foo = gbinder_ipc_new_local_object(ipc, "foo", NULL, NULL);
|
foo = gbinder_local_object_new(ipc, ifaces_foo, NULL, NULL);
|
||||||
bar = gbinder_ipc_new_local_object(ipc, "bar", NULL, NULL);
|
bar = gbinder_local_object_new(ipc, ifaces_bar, NULL, NULL);
|
||||||
|
|
||||||
/* But ipc is still not a local object! */
|
/* But ipc is still not a local object! */
|
||||||
g_assert(!gbinder_object_registry_get_local(reg, ipc));
|
g_assert(!gbinder_object_registry_get_local(reg, ipc));
|
||||||
@@ -186,6 +189,150 @@ test_basic(
|
|||||||
gbinder_local_object_unref(bar);
|
gbinder_local_object_unref(bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* ping
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_ping(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
int status = INT_MAX;
|
||||||
|
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
||||||
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
||||||
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
|
||||||
|
GBinderLocalReply* reply;
|
||||||
|
GBinderOutputData* out_data;
|
||||||
|
static const guint8 result[] = { 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
g_assert(gbinder_local_object_can_handle_transaction(obj, NULL,
|
||||||
|
GBINDER_PING_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||||
|
|
||||||
|
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
|
||||||
|
* handled by handle_looper_transaction() */
|
||||||
|
g_assert(!gbinder_local_object_handle_transaction(obj, req,
|
||||||
|
GBINDER_PING_TRANSACTION, 0, &status));
|
||||||
|
g_assert(status == (-EBADMSG));
|
||||||
|
reply = gbinder_local_object_handle_looper_transaction(obj, req,
|
||||||
|
GBINDER_PING_TRANSACTION, 0, &status);
|
||||||
|
g_assert(reply);
|
||||||
|
g_assert(status == GBINDER_STATUS_OK);
|
||||||
|
|
||||||
|
out_data = gbinder_local_reply_data(reply);
|
||||||
|
g_assert(out_data);
|
||||||
|
g_assert(out_data->bytes);
|
||||||
|
g_assert(out_data->bytes->len == sizeof(result));
|
||||||
|
g_assert(!memcmp(out_data->bytes->data, result, sizeof(result)));
|
||||||
|
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_local_reply_unref(reply);
|
||||||
|
gbinder_remote_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* interface
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_interface(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
int status = INT_MAX;
|
||||||
|
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
||||||
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
|
const char* const ifaces[] = { "x", NULL };
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
||||||
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
|
||||||
|
GBinderLocalReply* reply;
|
||||||
|
GBinderOutputData* out_data;
|
||||||
|
static const guint8 result[] = {
|
||||||
|
TEST_INT32_BYTES(1),
|
||||||
|
TEST_INT16_BYTES('x'), 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
g_assert(gbinder_local_object_can_handle_transaction(obj, NULL,
|
||||||
|
GBINDER_INTERFACE_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||||
|
|
||||||
|
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
|
||||||
|
* handled by handle_looper_transaction() */
|
||||||
|
g_assert(!gbinder_local_object_handle_transaction(obj, req,
|
||||||
|
GBINDER_INTERFACE_TRANSACTION, 0, &status));
|
||||||
|
g_assert(status == (-EBADMSG));
|
||||||
|
reply = gbinder_local_object_handle_looper_transaction(obj, req,
|
||||||
|
GBINDER_INTERFACE_TRANSACTION, 0, &status);
|
||||||
|
g_assert(reply);
|
||||||
|
g_assert(status == GBINDER_STATUS_OK);
|
||||||
|
|
||||||
|
out_data = gbinder_local_reply_data(reply);
|
||||||
|
g_assert(out_data);
|
||||||
|
g_assert(out_data->bytes);
|
||||||
|
g_assert(out_data->bytes->len == sizeof(result));
|
||||||
|
g_assert(!memcmp(out_data->bytes->data, result, sizeof(result)));
|
||||||
|
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_local_reply_unref(reply);
|
||||||
|
gbinder_remote_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* hidl_ping
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_hidl_ping(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
static const guint8 req_data [] = { TEST_BASE_INTERFACE_HEADER_BYTES };
|
||||||
|
int status = INT_MAX;
|
||||||
|
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
||||||
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
|
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
||||||
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
|
||||||
|
GBinderLocalReply* reply;
|
||||||
|
GBinderOutputData* out_data;
|
||||||
|
static const guint8 result[] = { 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||||
|
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
|
sizeof(req_data), NULL));
|
||||||
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
|
||||||
|
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
||||||
|
HIDL_PING_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||||
|
|
||||||
|
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
|
||||||
|
* handled by handle_looper_transaction() */
|
||||||
|
g_assert(!gbinder_local_object_handle_transaction(obj, req,
|
||||||
|
HIDL_PING_TRANSACTION, 0, &status));
|
||||||
|
g_assert(status == (-EBADMSG));
|
||||||
|
reply = gbinder_local_object_handle_looper_transaction(obj, req,
|
||||||
|
HIDL_PING_TRANSACTION, 0, &status);
|
||||||
|
g_assert(reply);
|
||||||
|
g_assert(status == GBINDER_STATUS_OK);
|
||||||
|
|
||||||
|
out_data = gbinder_local_reply_data(reply);
|
||||||
|
g_assert(out_data);
|
||||||
|
g_assert(out_data->bytes);
|
||||||
|
g_assert(out_data->bytes->len == sizeof(result));
|
||||||
|
g_assert(!memcmp(out_data->bytes->data, result, sizeof(result)));
|
||||||
|
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_local_reply_unref(reply);
|
||||||
|
gbinder_remote_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* get_descriptor
|
* get_descriptor
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -195,21 +342,19 @@ void
|
|||||||
test_get_descriptor(
|
test_get_descriptor(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 req_data [] = {
|
static const guint8 req_data [] = { TEST_BASE_INTERFACE_HEADER_BYTES };
|
||||||
TEST_BASE_INTERFACE_HEADER_BYTES
|
|
||||||
};
|
|
||||||
int status = INT_MAX;
|
int status = INT_MAX;
|
||||||
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
||||||
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(dev);
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
||||||
GBinderLocalObject* obj =
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
|
||||||
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
|
|
||||||
GBinderLocalReply* reply;
|
GBinderLocalReply* reply;
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
|
sizeof(req_data), NULL));
|
||||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
|
||||||
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
||||||
HIDL_GET_DESCRIPTOR_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
HIDL_GET_DESCRIPTOR_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||||
@@ -255,16 +400,18 @@ test_descriptor_chain(
|
|||||||
};
|
};
|
||||||
int status = INT_MAX;
|
int status = INT_MAX;
|
||||||
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
||||||
|
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
|
||||||
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(dev);
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
||||||
GBinderLocalObject* obj =
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
|
||||||
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
|
|
||||||
GBinderLocalReply* reply;
|
GBinderLocalReply* reply;
|
||||||
|
GBinderOutputData* reply_data;
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
gbinder_remote_request_set_data(req, HIDL_DESCRIPTOR_CHAIN_TRANSACTION,
|
||||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
|
sizeof(req_data), NULL));
|
||||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
|
||||||
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
||||||
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||||
@@ -279,6 +426,11 @@ test_descriptor_chain(
|
|||||||
g_assert(reply);
|
g_assert(reply);
|
||||||
g_assert(status == GBINDER_STATUS_OK);
|
g_assert(status == GBINDER_STATUS_OK);
|
||||||
|
|
||||||
|
/* Should get 3 buffers - vector, string and its contents */
|
||||||
|
reply_data = gbinder_local_reply_data(reply);
|
||||||
|
g_assert(gbinder_output_data_offsets(reply_data)->count == 3);
|
||||||
|
g_assert(gbinder_output_data_buffers_size(reply_data) == 64);
|
||||||
|
|
||||||
gbinder_ipc_unref(ipc);
|
gbinder_ipc_unref(ipc);
|
||||||
gbinder_local_object_unref(obj);
|
gbinder_local_object_unref(obj);
|
||||||
gbinder_local_reply_unref(reply);
|
gbinder_local_reply_unref(reply);
|
||||||
@@ -320,13 +472,14 @@ test_custom_iface(
|
|||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
|
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
|
||||||
|
const char* const ifaces[] = { custom_iface, NULL };
|
||||||
int count = 0, status = INT_MAX;
|
int count = 0, status = INT_MAX;
|
||||||
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
||||||
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(dev);
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
||||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object(ipc, custom_iface,
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
|
||||||
test_custom_iface_handler, &count);
|
test_custom_iface_handler, &count);
|
||||||
GBinderLocalReply* reply;
|
GBinderLocalReply* reply;
|
||||||
GBinderReaderData reader_data;
|
GBinderReaderData reader_data;
|
||||||
@@ -334,8 +487,9 @@ test_custom_iface(
|
|||||||
char** strv;
|
char** strv;
|
||||||
char* str;
|
char* str;
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
|
sizeof(req_data), NULL));
|
||||||
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
|
||||||
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
|
||||||
g_assert(gbinder_local_object_can_handle_transaction(obj, custom_iface,
|
g_assert(gbinder_local_object_can_handle_transaction(obj, custom_iface,
|
||||||
@@ -425,17 +579,19 @@ test_reply_status(
|
|||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
|
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
|
||||||
|
const char* const ifaces[] = { custom_iface, NULL };
|
||||||
int count = 0, status = 0;
|
int count = 0, status = 0;
|
||||||
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
const char* dev = GBINDER_DEFAULT_HWBINDER;
|
||||||
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(dev);
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
|
||||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object(ipc, custom_iface,
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
|
||||||
test_reply_status_handler, &count);
|
test_reply_status_handler, &count);
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
|
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
|
||||||
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
|
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
|
sizeof(req_data), NULL));
|
||||||
|
|
||||||
/* Execute the custom transaction */
|
/* Execute the custom transaction */
|
||||||
g_assert(!gbinder_local_object_handle_transaction(obj, req,
|
g_assert(!gbinder_local_object_handle_transaction(obj, req,
|
||||||
@@ -468,8 +624,8 @@ void
|
|||||||
test_increfs(
|
test_increfs(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object
|
GBinderLocalObject* obj = gbinder_local_object_new
|
||||||
(ipc, NULL, NULL, NULL);
|
(ipc, NULL, NULL, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
int fd = gbinder_driver_fd(ipc->driver);
|
int fd = gbinder_driver_fd(ipc->driver);
|
||||||
@@ -479,7 +635,7 @@ test_increfs(
|
|||||||
/* ipc is not an object, will be ignored */
|
/* ipc is not an object, will be ignored */
|
||||||
test_binder_br_increfs(fd, ipc);
|
test_binder_br_increfs(fd, ipc);
|
||||||
test_binder_br_increfs(fd, obj);
|
test_binder_br_increfs(fd, obj);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
g_assert(obj->weak_refs == 1);
|
g_assert(obj->weak_refs == 1);
|
||||||
@@ -510,8 +666,8 @@ void
|
|||||||
test_decrefs(
|
test_decrefs(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object
|
GBinderLocalObject* obj = gbinder_local_object_new
|
||||||
(ipc, NULL, NULL, NULL);
|
(ipc, NULL, NULL, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
int fd = gbinder_driver_fd(ipc->driver);
|
int fd = gbinder_driver_fd(ipc->driver);
|
||||||
@@ -522,7 +678,7 @@ test_decrefs(
|
|||||||
test_binder_br_decrefs(fd, ipc);
|
test_binder_br_decrefs(fd, ipc);
|
||||||
test_binder_br_increfs(fd, obj);
|
test_binder_br_increfs(fd, obj);
|
||||||
test_binder_br_decrefs(fd, obj);
|
test_binder_br_decrefs(fd, obj);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
g_assert(obj->weak_refs == 0);
|
g_assert(obj->weak_refs == 0);
|
||||||
@@ -552,8 +708,8 @@ void
|
|||||||
test_acquire(
|
test_acquire(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object
|
GBinderLocalObject* obj = gbinder_local_object_new
|
||||||
(ipc, NULL, NULL, NULL);
|
(ipc, NULL, NULL, NULL);
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
int fd = gbinder_driver_fd(ipc->driver);
|
int fd = gbinder_driver_fd(ipc->driver);
|
||||||
@@ -563,7 +719,7 @@ test_acquire(
|
|||||||
/* ipc is not an object, will be ignored */
|
/* ipc is not an object, will be ignored */
|
||||||
test_binder_br_acquire(fd, ipc);
|
test_binder_br_acquire(fd, ipc);
|
||||||
test_binder_br_acquire(fd, obj);
|
test_binder_br_acquire(fd, obj);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
g_assert(obj->strong_refs == 1);
|
g_assert(obj->strong_refs == 1);
|
||||||
@@ -594,9 +750,8 @@ void
|
|||||||
test_release(
|
test_release(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderLocalObject* obj = gbinder_ipc_new_local_object
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
|
||||||
(ipc, NULL, NULL, NULL);
|
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
int fd = gbinder_driver_fd(ipc->driver);
|
int fd = gbinder_driver_fd(ipc->driver);
|
||||||
gulong id = gbinder_local_object_add_strong_refs_changed_handler(obj,
|
gulong id = gbinder_local_object_add_strong_refs_changed_handler(obj,
|
||||||
@@ -606,7 +761,7 @@ test_release(
|
|||||||
test_binder_br_release(fd, ipc);
|
test_binder_br_release(fd, ipc);
|
||||||
test_binder_br_acquire(fd, obj);
|
test_binder_br_acquire(fd, obj);
|
||||||
test_binder_br_release(fd, obj);
|
test_binder_br_release(fd, obj);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
g_assert(obj->strong_refs == 0);
|
g_assert(obj->strong_refs == 0);
|
||||||
@@ -627,6 +782,9 @@ int main(int argc, char* argv[])
|
|||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
g_test_add_func(TEST_PREFIX "null", test_null);
|
g_test_add_func(TEST_PREFIX "null", test_null);
|
||||||
g_test_add_func(TEST_PREFIX "basic", test_basic);
|
g_test_add_func(TEST_PREFIX "basic", test_basic);
|
||||||
|
g_test_add_func(TEST_PREFIX "ping", test_ping);
|
||||||
|
g_test_add_func(TEST_PREFIX "interface", test_interface);
|
||||||
|
g_test_add_func(TEST_PREFIX "hidl_ping", test_hidl_ping);
|
||||||
g_test_add_func(TEST_PREFIX "get_descriptor", test_get_descriptor);
|
g_test_add_func(TEST_PREFIX "get_descriptor", test_get_descriptor);
|
||||||
g_test_add_func(TEST_PREFIX "descriptor_chain", test_descriptor_chain);
|
g_test_add_func(TEST_PREFIX "descriptor_chain", test_descriptor_chain);
|
||||||
g_test_add_func(TEST_PREFIX "custom_iface", test_custom_iface);
|
g_test_add_func(TEST_PREFIX "custom_iface", test_custom_iface);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -31,10 +31,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
#include "test_binder.h"
|
||||||
|
|
||||||
#include "gbinder_local_object.h"
|
#include "gbinder_local_object.h"
|
||||||
#include "gbinder_local_reply_p.h"
|
#include "gbinder_local_reply_p.h"
|
||||||
#include "gbinder_output_data.h"
|
#include "gbinder_output_data.h"
|
||||||
|
#include "gbinder_buffer_p.h"
|
||||||
|
#include "gbinder_driver.h"
|
||||||
#include "gbinder_writer.h"
|
#include "gbinder_writer.h"
|
||||||
#include "gbinder_io.h"
|
#include "gbinder_io.h"
|
||||||
#include "gbinder_ipc.h"
|
#include "gbinder_ipc.h"
|
||||||
@@ -56,6 +59,17 @@ test_int_inc(
|
|||||||
(*((int*)data))++;
|
(*((int*)data))++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderBuffer*
|
||||||
|
test_buffer_from_bytes(
|
||||||
|
GBinderDriver* driver,
|
||||||
|
const GByteArray* bytes)
|
||||||
|
{
|
||||||
|
/* Prevent double free */
|
||||||
|
test_binder_set_destroy(gbinder_driver_fd(driver), bytes->data, NULL);
|
||||||
|
return gbinder_buffer_new(driver, bytes->data, bytes->len, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* null
|
* null
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -74,6 +88,7 @@ test_null(
|
|||||||
gbinder_local_reply_init_writer(NULL, NULL);
|
gbinder_local_reply_init_writer(NULL, NULL);
|
||||||
gbinder_local_reply_init_writer(NULL, &writer);
|
gbinder_local_reply_init_writer(NULL, &writer);
|
||||||
g_assert(!gbinder_local_reply_data(NULL));
|
g_assert(!gbinder_local_reply_data(NULL));
|
||||||
|
g_assert(!gbinder_local_reply_new_from_data(NULL));
|
||||||
|
|
||||||
gbinder_local_reply_cleanup(NULL, NULL, &count);
|
gbinder_local_reply_cleanup(NULL, NULL, &count);
|
||||||
gbinder_local_reply_cleanup(NULL, test_int_inc, &count);
|
gbinder_local_reply_cleanup(NULL, test_int_inc, &count);
|
||||||
@@ -122,8 +137,8 @@ void
|
|||||||
test_bool(
|
test_bool(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 output_true[] = { 0x01, 0xff, 0xff, 0xff };
|
static const guint8 output_true[] = { 0x01, 0x00, 0x00, 0x00 };
|
||||||
static const guint8 output_false[] = { 0x00, 0xff, 0xff, 0xff };
|
static const guint8 output_false[] = { 0x00, 0x00, 0x00, 0x00 };
|
||||||
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
|
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
|
||||||
GBinderOutputData* data;
|
GBinderOutputData* data;
|
||||||
|
|
||||||
@@ -344,7 +359,7 @@ test_hidl_string(
|
|||||||
offsets = gbinder_output_data_offsets(data);
|
offsets = gbinder_output_data_offsets(data);
|
||||||
g_assert(offsets->count == 1);
|
g_assert(offsets->count == 1);
|
||||||
g_assert(offsets->data[0] == 0);
|
g_assert(offsets->data[0] == 0);
|
||||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlString));
|
g_assert(gbinder_output_data_buffers_size(data)==sizeof(GBinderHidlString));
|
||||||
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
||||||
gbinder_local_reply_unref(reply);
|
gbinder_local_reply_unref(reply);
|
||||||
}
|
}
|
||||||
@@ -367,7 +382,7 @@ test_hidl_string_vec(
|
|||||||
offsets = gbinder_output_data_offsets(data);
|
offsets = gbinder_output_data_offsets(data);
|
||||||
g_assert(offsets->count == 1);
|
g_assert(offsets->count == 1);
|
||||||
g_assert(offsets->data[0] == 0);
|
g_assert(offsets->data[0] == 0);
|
||||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlVec));
|
g_assert(gbinder_output_data_buffers_size(data) == sizeof(GBinderHidlVec));
|
||||||
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
||||||
gbinder_local_reply_unref(reply);
|
gbinder_local_reply_unref(reply);
|
||||||
}
|
}
|
||||||
@@ -384,9 +399,9 @@ test_local_object(
|
|||||||
GBinderLocalReply* reply;
|
GBinderLocalReply* reply;
|
||||||
GBinderOutputData* data;
|
GBinderOutputData* data;
|
||||||
GUtilIntArray* offsets;
|
GUtilIntArray* offsets;
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(NULL);
|
GBinderIpc* ipc = gbinder_ipc_new(NULL, NULL);
|
||||||
GBinderLocalObject* obj =
|
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
|
||||||
gbinder_ipc_new_local_object(ipc, "foo", NULL, NULL);
|
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
|
||||||
|
|
||||||
/* Append a real object (64-bit I/O is used by test_binder.c) */
|
/* Append a real object (64-bit I/O is used by test_binder.c) */
|
||||||
reply = gbinder_local_object_new_reply(obj);
|
reply = gbinder_local_object_new_reply(obj);
|
||||||
@@ -438,6 +453,47 @@ test_remote_object(
|
|||||||
gbinder_local_reply_unref(reply);
|
gbinder_local_reply_unref(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* remote_reply
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_remote_reply(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* The size of the string gets aligned at 4-byte boundary */
|
||||||
|
static const char input[] = "test";
|
||||||
|
static const guint8 output[] = { 't', 'e', 's', 't', 0, 0, 0, 0 };
|
||||||
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
|
const GBinderIo* io = gbinder_driver_io(driver);
|
||||||
|
GBinderLocalReply* req = gbinder_local_reply_new(io);
|
||||||
|
GBinderLocalReply* req2;
|
||||||
|
GBinderOutputData* data2;
|
||||||
|
const GByteArray* bytes;
|
||||||
|
const GByteArray* bytes2;
|
||||||
|
GBinderBuffer* buffer;
|
||||||
|
|
||||||
|
gbinder_local_reply_append_string8(req, input);
|
||||||
|
bytes = gbinder_local_reply_data(req)->bytes;
|
||||||
|
|
||||||
|
/* Copy flat structures (no binder objects) */
|
||||||
|
buffer = test_buffer_from_bytes(driver, bytes);
|
||||||
|
req2 = gbinder_local_reply_new_from_data(buffer);
|
||||||
|
gbinder_buffer_free(buffer);
|
||||||
|
|
||||||
|
data2 = gbinder_local_reply_data(req2);
|
||||||
|
bytes2 = data2->bytes;
|
||||||
|
g_assert(!gbinder_output_data_offsets(data2));
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data2));
|
||||||
|
g_assert(bytes2->len == sizeof(output));
|
||||||
|
g_assert(!memcmp(bytes2->data, output, bytes2->len));
|
||||||
|
|
||||||
|
gbinder_local_reply_unref(req2);
|
||||||
|
gbinder_local_reply_unref(req);
|
||||||
|
gbinder_driver_unref(driver);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* Common
|
* Common
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -460,6 +516,7 @@ int main(int argc, char* argv[])
|
|||||||
g_test_add_func(TEST_PREFIX "hidl_string_vec", test_hidl_string_vec);
|
g_test_add_func(TEST_PREFIX "hidl_string_vec", test_hidl_string_vec);
|
||||||
g_test_add_func(TEST_PREFIX "local_object", test_local_object);
|
g_test_add_func(TEST_PREFIX "local_object", test_local_object);
|
||||||
g_test_add_func(TEST_PREFIX "remote_object", test_remote_object);
|
g_test_add_func(TEST_PREFIX "remote_object", test_remote_object);
|
||||||
|
g_test_add_func(TEST_PREFIX "remote_reply", test_remote_reply);
|
||||||
test_init(&test_opt, argc, argv);
|
test_init(&test_opt, argc, argv);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -31,9 +31,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
#include "test_binder.h"
|
||||||
|
|
||||||
#include "gbinder_local_request_p.h"
|
#include "gbinder_local_request_p.h"
|
||||||
#include "gbinder_output_data.h"
|
#include "gbinder_output_data.h"
|
||||||
|
#include "gbinder_buffer_p.h"
|
||||||
|
#include "gbinder_driver.h"
|
||||||
#include "gbinder_writer.h"
|
#include "gbinder_writer.h"
|
||||||
#include "gbinder_io.h"
|
#include "gbinder_io.h"
|
||||||
|
|
||||||
@@ -54,6 +57,29 @@ test_int_inc(
|
|||||||
(*((int*)data))++;
|
(*((int*)data))++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderBuffer*
|
||||||
|
test_buffer_from_bytes(
|
||||||
|
GBinderDriver* driver,
|
||||||
|
const GByteArray* bytes)
|
||||||
|
{
|
||||||
|
/* Prevent double free */
|
||||||
|
test_binder_set_destroy(gbinder_driver_fd(driver), bytes->data, NULL);
|
||||||
|
return gbinder_buffer_new(driver, bytes->data, bytes->len, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderBuffer*
|
||||||
|
test_buffer_from_bytes_and_objects(
|
||||||
|
GBinderDriver* driver,
|
||||||
|
const GByteArray* bytes,
|
||||||
|
void** objects)
|
||||||
|
{
|
||||||
|
/* Prevent double free */
|
||||||
|
test_binder_set_destroy(gbinder_driver_fd(driver), bytes->data, NULL);
|
||||||
|
return gbinder_buffer_new(driver, bytes->data, bytes->len, objects);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* null
|
* null
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -68,6 +94,7 @@ test_null(
|
|||||||
|
|
||||||
g_assert(!gbinder_local_request_new(NULL, NULL));
|
g_assert(!gbinder_local_request_new(NULL, NULL));
|
||||||
g_assert(!gbinder_local_request_ref(NULL));
|
g_assert(!gbinder_local_request_ref(NULL));
|
||||||
|
g_assert(!gbinder_local_request_new_from_data(NULL));
|
||||||
gbinder_local_request_unref(NULL);
|
gbinder_local_request_unref(NULL);
|
||||||
gbinder_local_request_init_writer(NULL, NULL);
|
gbinder_local_request_init_writer(NULL, NULL);
|
||||||
gbinder_local_request_init_writer(NULL, &writer);
|
gbinder_local_request_init_writer(NULL, &writer);
|
||||||
@@ -152,8 +179,8 @@ void
|
|||||||
test_bool(
|
test_bool(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 output_true[] = { 0x01, 0xff, 0xff, 0xff };
|
static const guint8 output_true[] = { 0x01, 0x00, 0x00, 0x00 };
|
||||||
static const guint8 output_false[] = { 0x00, 0xff, 0xff, 0xff };
|
static const guint8 output_false[] = { 0x00, 0x00, 0x00, 0x00 };
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||||
GBinderOutputData* data;
|
GBinderOutputData* data;
|
||||||
|
|
||||||
@@ -360,7 +387,7 @@ test_hidl_string(
|
|||||||
offsets = gbinder_output_data_offsets(data);
|
offsets = gbinder_output_data_offsets(data);
|
||||||
g_assert(offsets->count == 1);
|
g_assert(offsets->count == 1);
|
||||||
g_assert(offsets->data[0] == 0);
|
g_assert(offsets->data[0] == 0);
|
||||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlString));
|
g_assert(gbinder_output_data_buffers_size(data)==sizeof(GBinderHidlString));
|
||||||
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
@@ -383,7 +410,7 @@ test_hidl_string_vec(
|
|||||||
offsets = gbinder_output_data_offsets(data);
|
offsets = gbinder_output_data_offsets(data);
|
||||||
g_assert(offsets->count == 1);
|
g_assert(offsets->count == 1);
|
||||||
g_assert(offsets->data[0] == 0);
|
g_assert(offsets->data[0] == 0);
|
||||||
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlVec));
|
g_assert(gbinder_output_data_buffers_size(data) == sizeof(GBinderHidlVec));
|
||||||
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
|
||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
@@ -436,6 +463,126 @@ test_remote_object(
|
|||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* remote_request
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_remote_request(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* The size of the string gets aligned at 4-byte boundary */
|
||||||
|
static const char input[] = "test";
|
||||||
|
static const guint8 output[] = { 't', 'e', 's', 't', 0, 0, 0, 0 };
|
||||||
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
|
const GBinderIo* io = gbinder_driver_io(driver);
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
|
GBinderLocalRequest* req2;
|
||||||
|
GBinderOutputData* data2;
|
||||||
|
const GByteArray* bytes;
|
||||||
|
const GByteArray* bytes2;
|
||||||
|
GBinderBuffer* buffer;
|
||||||
|
void** no_obj = g_new0(void*, 1);
|
||||||
|
|
||||||
|
gbinder_local_request_append_string8(req, input);
|
||||||
|
bytes = gbinder_local_request_data(req)->bytes;
|
||||||
|
|
||||||
|
/* Copy flat structures (no binder objects) */
|
||||||
|
buffer = test_buffer_from_bytes(driver, bytes);
|
||||||
|
req2 = gbinder_local_request_new_from_data(buffer);
|
||||||
|
gbinder_buffer_free(buffer);
|
||||||
|
|
||||||
|
data2 = gbinder_local_request_data(req2);
|
||||||
|
bytes2 = data2->bytes;
|
||||||
|
g_assert(!gbinder_output_data_offsets(data2));
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data2));
|
||||||
|
g_assert(bytes2->len == sizeof(output));
|
||||||
|
g_assert(!memcmp(bytes2->data, output, bytes2->len));
|
||||||
|
gbinder_local_request_unref(req2);
|
||||||
|
|
||||||
|
/* Same thing but with non-NULL (albeit empty) array of objects */
|
||||||
|
buffer = test_buffer_from_bytes_and_objects(driver, bytes, no_obj);
|
||||||
|
req2 = gbinder_local_request_new_from_data(buffer);
|
||||||
|
gbinder_buffer_free(buffer);
|
||||||
|
|
||||||
|
data2 = gbinder_local_request_data(req2);
|
||||||
|
bytes2 = data2->bytes;
|
||||||
|
g_assert(!gbinder_output_data_offsets(data2));
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data2));
|
||||||
|
g_assert(bytes2->len == sizeof(output));
|
||||||
|
g_assert(!memcmp(bytes2->data, output, bytes2->len));
|
||||||
|
gbinder_local_request_unref(req2);
|
||||||
|
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
gbinder_driver_unref(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* remote_request_obj
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_remote_request_obj_validate_data(
|
||||||
|
GBinderOutputData* data)
|
||||||
|
{
|
||||||
|
const GByteArray* bytes = data->bytes;
|
||||||
|
GUtilIntArray* offsets = gbinder_output_data_offsets(data);
|
||||||
|
|
||||||
|
offsets = gbinder_output_data_offsets(data);
|
||||||
|
g_assert(offsets);
|
||||||
|
g_assert(offsets->count == 3);
|
||||||
|
g_assert(offsets->data[0] == 4);
|
||||||
|
g_assert(offsets->data[1] == 4 + BUFFER_OBJECT_SIZE_64);
|
||||||
|
g_assert(offsets->data[2] == 4 + 2*BUFFER_OBJECT_SIZE_64);
|
||||||
|
g_assert(bytes->len == 4 + 2*BUFFER_OBJECT_SIZE_64 + BINDER_OBJECT_SIZE_64);
|
||||||
|
/* GBinderHidlString + the contents (2 bytes) aligned at 8-byte boundary */
|
||||||
|
g_assert(gbinder_output_data_buffers_size(data) ==
|
||||||
|
(sizeof(GBinderHidlString) + 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_remote_request_obj(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
|
const GBinderIo* io = gbinder_driver_io(driver);
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
|
GBinderLocalRequest* req2;
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GUtilIntArray* offsets;
|
||||||
|
GBinderBuffer* buffer;
|
||||||
|
const GByteArray* bytes;
|
||||||
|
void** objects;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
gbinder_local_request_append_int32(req, 1);
|
||||||
|
gbinder_local_request_append_hidl_string(req, "2");
|
||||||
|
gbinder_local_request_append_local_object(req, NULL);
|
||||||
|
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
test_remote_request_obj_validate_data(data);
|
||||||
|
bytes = data->bytes;
|
||||||
|
offsets = gbinder_output_data_offsets(data);
|
||||||
|
objects = g_new0(void*, offsets->count + 1);
|
||||||
|
for (i = 0; i < offsets->count; i++) {
|
||||||
|
objects[i] = bytes->data + offsets->data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = test_buffer_from_bytes_and_objects(driver, data->bytes, objects);
|
||||||
|
req2 = gbinder_local_request_new_from_data(buffer);
|
||||||
|
gbinder_buffer_free(buffer);
|
||||||
|
|
||||||
|
test_remote_request_obj_validate_data(gbinder_local_request_data(req2));
|
||||||
|
|
||||||
|
/* req2 has to be freed first because req owns data */
|
||||||
|
gbinder_local_request_unref(req2);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
gbinder_driver_unref(driver);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* Common
|
* Common
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -459,6 +606,8 @@ int main(int argc, char* argv[])
|
|||||||
g_test_add_func(TEST_PREFIX "hidl_string_vec", test_hidl_string_vec);
|
g_test_add_func(TEST_PREFIX "hidl_string_vec", test_hidl_string_vec);
|
||||||
g_test_add_func(TEST_PREFIX "local_object", test_local_object);
|
g_test_add_func(TEST_PREFIX "local_object", test_local_object);
|
||||||
g_test_add_func(TEST_PREFIX "remote_object", test_remote_object);
|
g_test_add_func(TEST_PREFIX "remote_object", test_remote_object);
|
||||||
|
g_test_add_func(TEST_PREFIX "remote_request", test_remote_request);
|
||||||
|
g_test_add_func(TEST_PREFIX "remote_request_obj", test_remote_request_obj);
|
||||||
test_init(&test_opt, argc, argv);
|
test_init(&test_opt, argc, argv);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -74,39 +74,61 @@ static const TestHeaderData test_header_tests[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* default
|
* device
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
test_default(
|
test_device(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
const GBinderRpcProtocol* p1 = gbinder_rpc_protocol_for_device(NULL);
|
g_assert(gbinder_rpc_protocol_for_device(NULL) ==
|
||||||
const GBinderRpcProtocol* p2 = gbinder_rpc_protocol_for_device
|
&gbinder_rpc_protocol_binder);
|
||||||
(GBINDER_DEFAULT_BINDER);
|
g_assert(gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER) ==
|
||||||
|
&gbinder_rpc_protocol_binder);
|
||||||
g_assert(p1);
|
g_assert(gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_HWBINDER) ==
|
||||||
g_assert(p1 == p2);
|
&gbinder_rpc_protocol_hwbinder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* no_header
|
* no_header1
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
test_no_header(
|
test_no_header1(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||||
gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER), 0, 0);
|
gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_BINDER), 0, 0);
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, NULL, NULL);
|
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION, NULL);
|
||||||
g_assert(!gbinder_remote_request_interface(req));
|
g_assert(!gbinder_remote_request_interface(req));
|
||||||
gbinder_remote_request_unref(req);
|
gbinder_remote_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* no_header2
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_no_header2(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const GBinderRpcProtocol* p = &gbinder_rpc_protocol_binder;
|
||||||
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, p);
|
||||||
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL, p, 0, 0);
|
||||||
|
|
||||||
|
gbinder_remote_request_set_data(req, GBINDER_DUMP_TRANSACTION,
|
||||||
|
gbinder_buffer_new(driver,
|
||||||
|
g_memdup(TEST_ARRAY_AND_SIZE(test_header_binder)),
|
||||||
|
sizeof(test_header_binder), NULL));
|
||||||
|
g_assert(!gbinder_remote_request_interface(req));
|
||||||
|
gbinder_remote_request_unref(req);
|
||||||
|
gbinder_driver_unref(driver);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* write_header
|
* write_header
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -140,42 +162,43 @@ test_read_header(
|
|||||||
gconstpointer test_data)
|
gconstpointer test_data)
|
||||||
{
|
{
|
||||||
const TestHeaderData* test = test_data;
|
const TestHeaderData* test = test_data;
|
||||||
GBinderDriver* driver = gbinder_driver_new(test->dev);
|
GBinderDriver* driver = gbinder_driver_new(test->dev, NULL);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||||
gbinder_rpc_protocol_for_device(test->dev), 0, 0);
|
gbinder_rpc_protocol_for_device(test->dev), 0, 0);
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||||
g_memdup(test->header, test->header_size), test->header_size), NULL);
|
gbinder_buffer_new(driver, g_memdup(test->header, test->header_size),
|
||||||
|
test->header_size, NULL));
|
||||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), test->iface));
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), test->iface));
|
||||||
gbinder_remote_request_unref(req);
|
gbinder_remote_request_unref(req);
|
||||||
gbinder_driver_unref(driver);
|
gbinder_driver_unref(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* Common
|
* Common
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
#define TEST_PREFIX "/protocol/"
|
#define TEST_PREFIX "/protocol/"
|
||||||
|
#define TEST_(t) TEST_PREFIX t
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
g_test_add_func(TEST_PREFIX "default", test_default);
|
g_test_add_func(TEST_("device"), test_device);
|
||||||
g_test_add_func(TEST_PREFIX "no_header", test_no_header);
|
g_test_add_func(TEST_("no_header1"), test_no_header1);
|
||||||
|
g_test_add_func(TEST_("no_header2"), test_no_header2);
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(test_header_tests); i++) {
|
for (i = 0; i < G_N_ELEMENTS(test_header_tests); i++) {
|
||||||
const TestHeaderData* test = test_header_tests + i;
|
const TestHeaderData* test = test_header_tests + i;
|
||||||
char* path = g_strconcat(TEST_PREFIX, "/", test->name,
|
char* path;
|
||||||
"/read_header", NULL);
|
|
||||||
|
|
||||||
|
path = g_strconcat(TEST_PREFIX, test->name, "/read_header", NULL);
|
||||||
g_test_add_data_func(path, test, test_read_header);
|
g_test_add_data_func(path, test, test_read_header);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
|
|
||||||
path = g_strconcat(TEST_PREFIX, "/", test->name,
|
path = g_strconcat(TEST_PREFIX, test->name, "/write_header", NULL);
|
||||||
"/write_header", NULL);
|
|
||||||
|
|
||||||
g_test_add_data_func(path, test, test_write_header);
|
g_test_add_data_func(path, test, test_write_header);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -50,8 +50,9 @@ void
|
|||||||
test_null(
|
test_null(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
g_assert(!gbinder_remote_object_new(NULL, 0));
|
g_assert(!gbinder_remote_object_new(NULL, 0, FALSE));
|
||||||
g_assert(!gbinder_remote_object_ref(NULL));
|
g_assert(!gbinder_remote_object_ref(NULL));
|
||||||
|
g_assert(!gbinder_remote_object_ipc(NULL));
|
||||||
gbinder_remote_object_unref(NULL);
|
gbinder_remote_object_unref(NULL);
|
||||||
g_assert(gbinder_remote_object_is_dead(NULL));
|
g_assert(gbinder_remote_object_is_dead(NULL));
|
||||||
g_assert(!gbinder_remote_object_add_death_handler(NULL, NULL, NULL));
|
g_assert(!gbinder_remote_object_add_death_handler(NULL, NULL, NULL));
|
||||||
@@ -67,7 +68,7 @@ void
|
|||||||
test_basic(
|
test_basic(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
|
||||||
GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg, 1);
|
GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg, 1);
|
||||||
GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg, 2);
|
GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg, 2);
|
||||||
@@ -76,11 +77,14 @@ test_basic(
|
|||||||
g_assert(obj2);
|
g_assert(obj2);
|
||||||
g_assert(obj1->handle == 1u);
|
g_assert(obj1->handle == 1u);
|
||||||
g_assert(obj2->handle == 2u);
|
g_assert(obj2->handle == 2u);
|
||||||
|
g_assert(gbinder_remote_object_ipc(obj1) == ipc);
|
||||||
|
g_assert(gbinder_remote_object_ipc(obj2) == ipc);
|
||||||
g_assert(!gbinder_remote_object_is_dead(obj1));
|
g_assert(!gbinder_remote_object_is_dead(obj1));
|
||||||
|
g_assert(gbinder_remote_object_reanimate(obj1));
|
||||||
g_assert(gbinder_remote_object_ref(obj1) == obj1);
|
g_assert(gbinder_remote_object_ref(obj1) == obj1);
|
||||||
gbinder_remote_object_unref(obj1); /* Compensate the above reference */
|
gbinder_remote_object_unref(obj1); /* Compensate the above reference */
|
||||||
g_assert(!gbinder_remote_object_add_death_handler(obj1, NULL, NULL));
|
g_assert(!gbinder_remote_object_add_death_handler(obj1, NULL, NULL));
|
||||||
g_assert(gbinder_ipc_get_remote_object(ipc, 1) == obj1);
|
g_assert(gbinder_ipc_get_remote_object(ipc, 1, TRUE) == obj1);
|
||||||
gbinder_remote_object_unref(obj1); /* Compensate the above reference */
|
gbinder_remote_object_unref(obj1); /* Compensate the above reference */
|
||||||
gbinder_remote_object_unref(obj1);
|
gbinder_remote_object_unref(obj1);
|
||||||
gbinder_remote_object_unref(obj2);
|
gbinder_remote_object_unref(obj2);
|
||||||
@@ -108,12 +112,15 @@ test_dead(
|
|||||||
{
|
{
|
||||||
const guint handle = 1;
|
const guint handle = 1;
|
||||||
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
|
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderRemoteObject* obj = gbinder_ipc_get_remote_object(ipc, handle);
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
GBinderRemoteObject* obj = gbinder_ipc_get_remote_object
|
||||||
|
(ipc, handle, FALSE);
|
||||||
gulong id = gbinder_remote_object_add_death_handler
|
gulong id = gbinder_remote_object_add_death_handler
|
||||||
(obj, test_dead_done, loop);
|
(obj, test_dead_done, loop);
|
||||||
|
|
||||||
test_binder_br_dead_binder(gbinder_driver_fd(ipc->driver), handle);
|
test_binder_br_dead_binder(fd, handle);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
test_run(&test_opt, loop);
|
test_run(&test_opt, loop);
|
||||||
g_assert(gbinder_remote_object_is_dead(obj));
|
g_assert(gbinder_remote_object_is_dead(obj));
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -35,10 +35,17 @@
|
|||||||
#include "gbinder_buffer_p.h"
|
#include "gbinder_buffer_p.h"
|
||||||
#include "gbinder_driver.h"
|
#include "gbinder_driver.h"
|
||||||
#include "gbinder_reader.h"
|
#include "gbinder_reader.h"
|
||||||
|
#include "gbinder_local_reply_p.h"
|
||||||
#include "gbinder_remote_reply_p.h"
|
#include "gbinder_remote_reply_p.h"
|
||||||
|
#include "gbinder_output_data.h"
|
||||||
|
|
||||||
|
#include <gutil_intarray.h>
|
||||||
|
|
||||||
static TestOpt test_opt;
|
static TestOpt test_opt;
|
||||||
|
|
||||||
|
#define BINDER_TYPE_BINDER GBINDER_FOURCC('s', 'b', '*', 0x85)
|
||||||
|
#define BINDER_OBJECT_SIZE_64 (GBINDER_MAX_BINDER_OBJECT_SIZE)
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* null
|
* null
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -52,10 +59,11 @@ test_null(
|
|||||||
|
|
||||||
g_assert(!gbinder_remote_reply_ref(NULL));
|
g_assert(!gbinder_remote_reply_ref(NULL));
|
||||||
gbinder_remote_reply_unref(NULL);
|
gbinder_remote_reply_unref(NULL);
|
||||||
gbinder_remote_reply_set_data(NULL, NULL, NULL);
|
gbinder_remote_reply_set_data(NULL, NULL);
|
||||||
gbinder_remote_reply_init_reader(NULL, &reader);
|
gbinder_remote_reply_init_reader(NULL, &reader);
|
||||||
g_assert(gbinder_reader_at_end(&reader));
|
g_assert(gbinder_reader_at_end(&reader));
|
||||||
g_assert(gbinder_remote_reply_is_empty(NULL));
|
g_assert(gbinder_remote_reply_is_empty(NULL));
|
||||||
|
g_assert(!gbinder_remote_reply_copy_to_local(NULL));
|
||||||
g_assert(!gbinder_remote_reply_read_int32(NULL, NULL));
|
g_assert(!gbinder_remote_reply_read_int32(NULL, NULL));
|
||||||
g_assert(!gbinder_remote_reply_read_uint32(NULL, NULL));
|
g_assert(!gbinder_remote_reply_read_uint32(NULL, NULL));
|
||||||
g_assert(!gbinder_remote_reply_read_int64(NULL, NULL));
|
g_assert(!gbinder_remote_reply_read_int64(NULL, NULL));
|
||||||
@@ -74,11 +82,11 @@ void
|
|||||||
test_empty(
|
test_empty(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||||
|
|
||||||
gbinder_remote_reply_set_data
|
gbinder_remote_reply_set_data(reply,
|
||||||
(reply, gbinder_buffer_new(driver, NULL, 0), NULL);
|
gbinder_buffer_new(driver, NULL, 0, NULL));
|
||||||
|
|
||||||
g_assert(gbinder_remote_reply_is_empty(reply));
|
g_assert(gbinder_remote_reply_is_empty(reply));
|
||||||
gbinder_remote_reply_unref(reply);
|
gbinder_remote_reply_unref(reply);
|
||||||
@@ -120,12 +128,11 @@ test_int32(
|
|||||||
};
|
};
|
||||||
guint32 out1 = 0;
|
guint32 out1 = 0;
|
||||||
gint32 out2 = 0;
|
gint32 out2 = 0;
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||||
|
|
||||||
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
||||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
|
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_assert(!gbinder_remote_reply_is_empty(reply));
|
g_assert(!gbinder_remote_reply_is_empty(reply));
|
||||||
g_assert(gbinder_remote_reply_read_uint32(reply, &out1));
|
g_assert(gbinder_remote_reply_read_uint32(reply, &out1));
|
||||||
@@ -151,12 +158,11 @@ test_int64(
|
|||||||
};
|
};
|
||||||
guint64 out1 = 0;
|
guint64 out1 = 0;
|
||||||
gint64 out2 = 0;
|
gint64 out2 = 0;
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||||
|
|
||||||
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
||||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
|
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_assert(!gbinder_remote_reply_is_empty(reply));
|
g_assert(!gbinder_remote_reply_is_empty(reply));
|
||||||
g_assert(gbinder_remote_reply_read_uint64(reply, &out1));
|
g_assert(gbinder_remote_reply_read_uint64(reply, &out1));
|
||||||
@@ -180,12 +186,11 @@ test_string8(
|
|||||||
static const guint8 reply_data [] = {
|
static const guint8 reply_data [] = {
|
||||||
'b', 'a', 'r', 0x00
|
'b', 'a', 'r', 0x00
|
||||||
};
|
};
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||||
|
|
||||||
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
||||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
|
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_assert(!gbinder_remote_reply_is_empty(reply));
|
g_assert(!gbinder_remote_reply_is_empty(reply));
|
||||||
g_assert(!g_strcmp0(gbinder_remote_reply_read_string8(reply), "bar"));
|
g_assert(!g_strcmp0(gbinder_remote_reply_read_string8(reply), "bar"));
|
||||||
@@ -208,13 +213,12 @@ test_string16(
|
|||||||
TEST_INT16_BYTES('b'), TEST_INT16_BYTES('a'),
|
TEST_INT16_BYTES('b'), TEST_INT16_BYTES('a'),
|
||||||
TEST_INT16_BYTES('r'), 0x00, 0x00
|
TEST_INT16_BYTES('r'), 0x00, 0x00
|
||||||
};
|
};
|
||||||
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
|
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
|
||||||
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
|
||||||
char* str;
|
char* str;
|
||||||
|
|
||||||
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
|
||||||
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
|
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_assert(!gbinder_remote_reply_is_empty(reply));
|
g_assert(!gbinder_remote_reply_is_empty(reply));
|
||||||
str = gbinder_remote_reply_read_string16(reply);
|
str = gbinder_remote_reply_read_string16(reply);
|
||||||
@@ -225,6 +229,55 @@ test_string16(
|
|||||||
gbinder_driver_unref(driver);
|
gbinder_driver_unref(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* to_local
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_to_local(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
static const guint8 reply_data [] = {
|
||||||
|
/* 32-bit integer */
|
||||||
|
TEST_INT32_BYTES(42),
|
||||||
|
/* 64-bit NULL flat_binder_object */
|
||||||
|
TEST_INT32_BYTES(BINDER_TYPE_BINDER), /* hdr.type */
|
||||||
|
TEST_INT32_BYTES(0x17f), /* flags */
|
||||||
|
TEST_INT64_BYTES(0), /* handle */
|
||||||
|
TEST_INT64_BYTES(0) /* cookie */
|
||||||
|
};
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderDriver* driver = gbinder_driver_new(dev, NULL);
|
||||||
|
GBinderRemoteReply* req = gbinder_remote_reply_new(NULL);
|
||||||
|
GBinderLocalReply* req2;
|
||||||
|
GBinderOutputData* data;
|
||||||
|
const GByteArray* bytes;
|
||||||
|
GUtilIntArray* offsets;
|
||||||
|
guint8* req_data = g_memdup(reply_data, sizeof(reply_data));
|
||||||
|
void** objects = g_new0(void*, 2);
|
||||||
|
|
||||||
|
/* Skip the 32-bit integer */
|
||||||
|
objects[0] = req_data + 4;
|
||||||
|
gbinder_remote_reply_set_data(req, gbinder_buffer_new(driver, req_data,
|
||||||
|
sizeof(reply_data), objects));
|
||||||
|
|
||||||
|
/* Convert to GBinderLocalReply */
|
||||||
|
req2 = gbinder_remote_reply_copy_to_local(req);
|
||||||
|
data = gbinder_local_reply_data(req2);
|
||||||
|
offsets = gbinder_output_data_offsets(data);
|
||||||
|
bytes = data->bytes;
|
||||||
|
g_assert(offsets);
|
||||||
|
g_assert(offsets->count == 1);
|
||||||
|
g_assert(offsets->data[0] == 4);
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(bytes->len == sizeof(reply_data));
|
||||||
|
|
||||||
|
gbinder_remote_reply_unref(req);
|
||||||
|
gbinder_local_reply_unref(req2);
|
||||||
|
gbinder_driver_unref(driver);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* Common
|
* Common
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -241,6 +294,7 @@ int main(int argc, char* argv[])
|
|||||||
g_test_add_func(TEST_PREFIX "int64", test_int64);
|
g_test_add_func(TEST_PREFIX "int64", test_int64);
|
||||||
g_test_add_func(TEST_PREFIX "string8", test_string8);
|
g_test_add_func(TEST_PREFIX "string8", test_string8);
|
||||||
g_test_add_func(TEST_PREFIX "string16", test_string16);
|
g_test_add_func(TEST_PREFIX "string16", test_string16);
|
||||||
|
g_test_add_func(TEST_PREFIX "to_local", test_to_local);
|
||||||
test_init(&test_opt, argc, argv);
|
test_init(&test_opt, argc, argv);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* 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:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -37,6 +37,11 @@
|
|||||||
#include "gbinder_reader.h"
|
#include "gbinder_reader.h"
|
||||||
#include "gbinder_remote_request_p.h"
|
#include "gbinder_remote_request_p.h"
|
||||||
#include "gbinder_rpc_protocol.h"
|
#include "gbinder_rpc_protocol.h"
|
||||||
|
#include "gbinder_local_request_p.h"
|
||||||
|
#include "gbinder_output_data.h"
|
||||||
|
#include "gbinder_io.h"
|
||||||
|
|
||||||
|
#include <gutil_intarray.h>
|
||||||
|
|
||||||
static TestOpt test_opt;
|
static TestOpt test_opt;
|
||||||
|
|
||||||
@@ -50,6 +55,9 @@ static TestOpt test_opt;
|
|||||||
TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'), \
|
TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'), \
|
||||||
TEST_INT16_BYTES('o'), 0x00, 0x00
|
TEST_INT16_BYTES('o'), 0x00, 0x00
|
||||||
|
|
||||||
|
#define BINDER_TYPE_BINDER GBINDER_FOURCC('s', 'b', '*', 0x85)
|
||||||
|
#define BINDER_OBJECT_SIZE_64 (GBINDER_MAX_BINDER_OBJECT_SIZE)
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* null
|
* null
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -63,10 +71,13 @@ test_null(
|
|||||||
|
|
||||||
g_assert(!gbinder_remote_request_ref(NULL));
|
g_assert(!gbinder_remote_request_ref(NULL));
|
||||||
gbinder_remote_request_unref(NULL);
|
gbinder_remote_request_unref(NULL);
|
||||||
gbinder_remote_request_set_data(NULL, NULL, NULL);
|
gbinder_remote_request_set_data(NULL, 0, NULL);
|
||||||
gbinder_remote_request_init_reader(NULL, &reader);
|
gbinder_remote_request_init_reader(NULL, &reader);
|
||||||
|
gbinder_remote_request_block(NULL);
|
||||||
|
gbinder_remote_request_complete(NULL, NULL, 0);
|
||||||
g_assert(gbinder_reader_at_end(&reader));
|
g_assert(gbinder_reader_at_end(&reader));
|
||||||
g_assert(!gbinder_remote_request_interface(NULL));
|
g_assert(!gbinder_remote_request_interface(NULL));
|
||||||
|
g_assert(!gbinder_remote_request_copy_to_local(NULL));
|
||||||
g_assert(gbinder_remote_request_sender_pid(NULL) == (pid_t)(-1));
|
g_assert(gbinder_remote_request_sender_pid(NULL) == (pid_t)(-1));
|
||||||
g_assert(gbinder_remote_request_sender_euid(NULL) == (uid_t)(-1));
|
g_assert(gbinder_remote_request_sender_euid(NULL) == (uid_t)(-1));
|
||||||
g_assert(!gbinder_remote_request_read_int32(NULL, NULL));
|
g_assert(!gbinder_remote_request_read_int32(NULL, NULL));
|
||||||
@@ -91,6 +102,10 @@ test_basic(
|
|||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||||
gbinder_rpc_protocol_for_device(NULL), 0, 0);
|
gbinder_rpc_protocol_for_device(NULL), 0, 0);
|
||||||
|
|
||||||
|
/* These two calls are wrong but won't cause problems: */
|
||||||
|
gbinder_remote_request_block(req);
|
||||||
|
gbinder_remote_request_complete(req, NULL, 0);
|
||||||
|
|
||||||
gbinder_remote_request_init_reader(req, &reader);
|
gbinder_remote_request_init_reader(req, &reader);
|
||||||
g_assert(gbinder_reader_at_end(&reader));
|
g_assert(gbinder_reader_at_end(&reader));
|
||||||
g_assert(!gbinder_remote_request_interface(req));
|
g_assert(!gbinder_remote_request_interface(req));
|
||||||
@@ -109,20 +124,20 @@ void
|
|||||||
test_int32(
|
test_int32(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 request_data [] = {
|
static const guint8 req_data [] = {
|
||||||
TEST_RPC_HEADER,
|
TEST_RPC_HEADER,
|
||||||
TEST_INT32_BYTES(42)
|
TEST_INT32_BYTES(42)
|
||||||
};
|
};
|
||||||
guint32 out1 = 0;
|
guint32 out1 = 0;
|
||||||
gint32 out2 = 0;
|
gint32 out2 = 0;
|
||||||
const char* dev = GBINDER_DEFAULT_BINDER;
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
GBinderDriver* driver = gbinder_driver_new(dev);
|
GBinderDriver* driver = gbinder_driver_new(dev, NULL);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||||
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||||
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
|
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
NULL);
|
sizeof(req_data), NULL));
|
||||||
|
|
||||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||||
g_assert(gbinder_remote_request_read_uint32(req, &out1));
|
g_assert(gbinder_remote_request_read_uint32(req, &out1));
|
||||||
@@ -143,20 +158,20 @@ void
|
|||||||
test_int64(
|
test_int64(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 request_data [] = {
|
static const guint8 req_data [] = {
|
||||||
TEST_RPC_HEADER,
|
TEST_RPC_HEADER,
|
||||||
TEST_INT64_BYTES(42)
|
TEST_INT64_BYTES(42)
|
||||||
};
|
};
|
||||||
guint64 out1 = 0;
|
guint64 out1 = 0;
|
||||||
gint64 out2 = 0;
|
gint64 out2 = 0;
|
||||||
const char* dev = GBINDER_DEFAULT_BINDER;
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
GBinderDriver* driver = gbinder_driver_new(dev);
|
GBinderDriver* driver = gbinder_driver_new(dev, NULL);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||||
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||||
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
|
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
NULL);
|
sizeof(req_data), NULL));
|
||||||
|
|
||||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||||
g_assert(gbinder_remote_request_read_uint64(req, &out1));
|
g_assert(gbinder_remote_request_read_uint64(req, &out1));
|
||||||
@@ -177,18 +192,18 @@ void
|
|||||||
test_string8(
|
test_string8(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 request_data [] = {
|
static const guint8 req_data [] = {
|
||||||
TEST_RPC_HEADER,
|
TEST_RPC_HEADER,
|
||||||
'b', 'a', 'r', 0x00
|
'b', 'a', 'r', 0x00
|
||||||
};
|
};
|
||||||
const char* dev = GBINDER_DEFAULT_BINDER;
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
GBinderDriver* driver = gbinder_driver_new(dev);
|
GBinderDriver* driver = gbinder_driver_new(dev, NULL);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||||
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||||
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
|
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
NULL);
|
sizeof(req_data), NULL));
|
||||||
|
|
||||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||||
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "bar"));
|
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "bar"));
|
||||||
@@ -206,21 +221,21 @@ void
|
|||||||
test_string16(
|
test_string16(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
static const guint8 request_data [] = {
|
static const guint8 req_data [] = {
|
||||||
TEST_RPC_HEADER,
|
TEST_RPC_HEADER,
|
||||||
TEST_INT32_BYTES(3),
|
TEST_INT32_BYTES(3),
|
||||||
TEST_INT16_BYTES('b'), TEST_INT16_BYTES('a'),
|
TEST_INT16_BYTES('b'), TEST_INT16_BYTES('a'),
|
||||||
TEST_INT16_BYTES('r'), 0x00, 0x00
|
TEST_INT16_BYTES('r'), 0x00, 0x00
|
||||||
};
|
};
|
||||||
const char* dev = GBINDER_DEFAULT_BINDER;
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
GBinderDriver* driver = gbinder_driver_new(dev);
|
GBinderDriver* driver = gbinder_driver_new(dev, NULL);
|
||||||
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||||
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||||
char* str;
|
char* str;
|
||||||
|
|
||||||
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
|
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||||
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
|
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
|
||||||
NULL);
|
sizeof(req_data), NULL));
|
||||||
|
|
||||||
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||||
str = gbinder_remote_request_read_string16(req);
|
str = gbinder_remote_request_read_string16(req);
|
||||||
@@ -231,6 +246,59 @@ test_string16(
|
|||||||
gbinder_driver_unref(driver);
|
gbinder_driver_unref(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* to_local
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_to_local(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
static const guint8 request_data [] = {
|
||||||
|
TEST_RPC_HEADER,
|
||||||
|
/* 32-bit integer */
|
||||||
|
TEST_INT32_BYTES(42),
|
||||||
|
/* 64-bit NULL flat_binder_object */
|
||||||
|
TEST_INT32_BYTES(BINDER_TYPE_BINDER), /* hdr.type */
|
||||||
|
TEST_INT32_BYTES(0x17f), /* flags */
|
||||||
|
TEST_INT64_BYTES(0), /* handle */
|
||||||
|
TEST_INT64_BYTES(0) /* cookie */
|
||||||
|
};
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderDriver* driver = gbinder_driver_new(dev, NULL);
|
||||||
|
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
|
||||||
|
gbinder_rpc_protocol_for_device(dev), 0, 0);
|
||||||
|
GBinderLocalRequest* req2;
|
||||||
|
GBinderOutputData* data;
|
||||||
|
const GByteArray* bytes;
|
||||||
|
GUtilIntArray* offsets;
|
||||||
|
guint8* req_data = g_memdup(request_data, sizeof(request_data));
|
||||||
|
void** objects = g_new0(void*, 2);
|
||||||
|
|
||||||
|
/* Skip the 32-bit integer */
|
||||||
|
objects[0] = req_data + 4;
|
||||||
|
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
|
||||||
|
gbinder_buffer_new(driver, req_data, sizeof(request_data), objects));
|
||||||
|
|
||||||
|
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
|
||||||
|
|
||||||
|
/* Convert to GBinderLocalRequest */
|
||||||
|
req2 = gbinder_remote_request_copy_to_local(req);
|
||||||
|
data = gbinder_local_request_data(req2);
|
||||||
|
offsets = gbinder_output_data_offsets(data);
|
||||||
|
bytes = data->bytes;
|
||||||
|
g_assert(offsets);
|
||||||
|
g_assert(offsets->count == 1);
|
||||||
|
g_assert(offsets->data[0] == 4);
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(bytes->len == sizeof(request_data));
|
||||||
|
|
||||||
|
gbinder_remote_request_unref(req);
|
||||||
|
gbinder_local_request_unref(req2);
|
||||||
|
gbinder_driver_unref(driver);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* Common
|
* Common
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -246,6 +314,7 @@ int main(int argc, char* argv[])
|
|||||||
g_test_add_func(TEST_PREFIX "int64", test_int64);
|
g_test_add_func(TEST_PREFIX "int64", test_int64);
|
||||||
g_test_add_func(TEST_PREFIX "string8", test_string8);
|
g_test_add_func(TEST_PREFIX "string8", test_string8);
|
||||||
g_test_add_func(TEST_PREFIX "string16", test_string16);
|
g_test_add_func(TEST_PREFIX "string16", test_string16);
|
||||||
|
g_test_add_func(TEST_PREFIX "to_local", test_to_local);
|
||||||
test_init(&test_opt, argc, argv);
|
test_init(&test_opt, argc, argv);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|||||||
5
unit/unit_servicemanager/Makefile
Normal file
5
unit/unit_servicemanager/Makefile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# -*- Mode: makefile-gmake -*-
|
||||||
|
|
||||||
|
EXE = unit_servicemanager
|
||||||
|
|
||||||
|
include ../common/Makefile
|
||||||
1072
unit/unit_servicemanager/unit_servicemanager.c
Normal file
1072
unit/unit_servicemanager/unit_servicemanager.c
Normal file
File diff suppressed because it is too large
Load Diff
5
unit/unit_servicename/Makefile
Normal file
5
unit/unit_servicename/Makefile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# -*- Mode: makefile-gmake -*-
|
||||||
|
|
||||||
|
EXE = unit_servicename
|
||||||
|
|
||||||
|
include ../common/Makefile
|
||||||
500
unit/unit_servicename/unit_servicename.c
Normal file
500
unit/unit_servicename/unit_servicename.c
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test_binder.h"
|
||||||
|
|
||||||
|
#include "gbinder_servicename.h"
|
||||||
|
#include "gbinder_servicemanager_p.h"
|
||||||
|
#include "gbinder_local_object.h"
|
||||||
|
#include "gbinder_rpc_protocol.h"
|
||||||
|
#include "gbinder_driver.h"
|
||||||
|
#include "gbinder_ipc.h"
|
||||||
|
|
||||||
|
#include <gutil_strv.h>
|
||||||
|
#include <gutil_log.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static TestOpt test_opt;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_quit(
|
||||||
|
GBinderServiceManager* sm,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
test_quit_later((GMainLoop*)user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_quit_when_destroyed(
|
||||||
|
gpointer loop,
|
||||||
|
GObject* obj)
|
||||||
|
{
|
||||||
|
test_quit_later((GMainLoop*)loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_setup_ping(
|
||||||
|
GBinderIpc* ipc)
|
||||||
|
{
|
||||||
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
|
||||||
|
test_binder_br_noop(fd);
|
||||||
|
test_binder_br_transaction_complete(fd);
|
||||||
|
test_binder_br_reply(fd, 0, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* TestServiceManager
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
typedef GBinderServiceManagerClass TestServiceManagerClass;
|
||||||
|
typedef struct test_servicemanager {
|
||||||
|
GBinderServiceManager manager;
|
||||||
|
GCond cond;
|
||||||
|
GMutex mutex;
|
||||||
|
char** services;
|
||||||
|
gboolean block_add;
|
||||||
|
int add_result;
|
||||||
|
} TestServiceManager;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(TestServiceManager, test_servicemanager,
|
||||||
|
GBINDER_TYPE_SERVICEMANAGER)
|
||||||
|
|
||||||
|
#define TEST_SERVICEMANAGER_IFACE "android.os.IServiceManager"
|
||||||
|
#define TEST_TYPE_SERVICEMANAGER (test_servicemanager_get_type())
|
||||||
|
#define TEST_SERVICEMANAGER(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||||
|
TEST_TYPE_SERVICEMANAGER, TestServiceManager)
|
||||||
|
|
||||||
|
static
|
||||||
|
char**
|
||||||
|
test_servicemanager_list(
|
||||||
|
GBinderServiceManager* manager)
|
||||||
|
{
|
||||||
|
char** ret;
|
||||||
|
TestServiceManager* self = TEST_SERVICEMANAGER(manager);
|
||||||
|
|
||||||
|
g_mutex_lock(&self->mutex);
|
||||||
|
ret = g_strdupv(self->services);
|
||||||
|
GDEBUG("%u", gutil_strv_length(ret));
|
||||||
|
g_mutex_unlock(&self->mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderRemoteObject*
|
||||||
|
test_servicemanager_get_service(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name,
|
||||||
|
int* status)
|
||||||
|
{
|
||||||
|
*status = (-ENOENT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
test_servicemanager_add_service(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name,
|
||||||
|
GBinderLocalObject* obj)
|
||||||
|
{
|
||||||
|
TestServiceManager* self = TEST_SERVICEMANAGER(manager);
|
||||||
|
|
||||||
|
g_mutex_lock(&self->mutex);
|
||||||
|
if (!gutil_strv_contains(self->services, name)) {
|
||||||
|
self->services = gutil_strv_add(self->services, name);
|
||||||
|
}
|
||||||
|
while (self->block_add) {
|
||||||
|
g_cond_wait(&self->cond, &self->mutex);
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&self->mutex);
|
||||||
|
return self->add_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBINDER_SERVICEMANAGER_NAME_CHECK
|
||||||
|
test_servicemanager_check_name(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
return name ?
|
||||||
|
GBINDER_SERVICEMANAGER_NAME_INVALID :
|
||||||
|
GBINDER_SERVICEMANAGER_NAME_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
test_servicemanager_watch(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_servicemanager_unwatch(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_servicemanager_init(
|
||||||
|
TestServiceManager* self)
|
||||||
|
{
|
||||||
|
g_cond_init(&self->cond);
|
||||||
|
g_mutex_init(&self->mutex);
|
||||||
|
self->add_result = GBINDER_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_servicemanager_finalize(
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
TestServiceManager* self = TEST_SERVICEMANAGER(object);
|
||||||
|
|
||||||
|
g_cond_clear(&self->cond);
|
||||||
|
g_mutex_clear(&self->mutex);
|
||||||
|
g_strfreev(self->services);
|
||||||
|
G_OBJECT_CLASS(test_servicemanager_parent_class)->finalize(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_servicemanager_class_init(
|
||||||
|
TestServiceManagerClass* klass)
|
||||||
|
{
|
||||||
|
klass->iface = TEST_SERVICEMANAGER_IFACE;
|
||||||
|
klass->default_device = GBINDER_DEFAULT_HWBINDER;
|
||||||
|
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
|
||||||
|
klass->list = test_servicemanager_list;
|
||||||
|
klass->get_service = test_servicemanager_get_service;
|
||||||
|
klass->add_service = test_servicemanager_add_service;
|
||||||
|
klass->check_name = test_servicemanager_check_name;
|
||||||
|
klass->watch = test_servicemanager_watch;
|
||||||
|
klass->unwatch = test_servicemanager_unwatch;
|
||||||
|
G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
GBinderServiceManager*
|
||||||
|
gbinder_defaultservicemanager_new(
|
||||||
|
const char* dev)
|
||||||
|
{
|
||||||
|
return gbinder_servicemanager_new_with_type(TEST_TYPE_SERVICEMANAGER, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBinderServiceManager*
|
||||||
|
gbinder_hwservicemanager_new(
|
||||||
|
const char* dev)
|
||||||
|
{
|
||||||
|
return gbinder_servicemanager_new(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* null
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_null(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GBinderServiceManager* sm;
|
||||||
|
|
||||||
|
test_setup_ping(ipc);
|
||||||
|
sm = gbinder_servicemanager_new(dev);
|
||||||
|
|
||||||
|
g_assert(!gbinder_servicename_new(NULL, NULL, NULL));
|
||||||
|
g_assert(!gbinder_servicename_new(sm, NULL, NULL));
|
||||||
|
g_assert(!gbinder_servicename_ref(NULL));
|
||||||
|
gbinder_servicename_unref(NULL);
|
||||||
|
|
||||||
|
gbinder_servicemanager_unref(sm);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* basic
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_basic(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char* obj_name = "test";
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
const char* const ifaces[] = { "interface", NULL };
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderLocalObject* obj;
|
||||||
|
GBinderServiceManager* sm;
|
||||||
|
GBinderServiceName* sn;
|
||||||
|
|
||||||
|
test_setup_ping(ipc);
|
||||||
|
sm = gbinder_servicemanager_new(dev);
|
||||||
|
obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
|
||||||
|
g_assert(!gbinder_servicename_new(sm, obj, NULL));
|
||||||
|
|
||||||
|
sn = gbinder_servicename_new(sm, obj, obj_name);
|
||||||
|
g_assert(sn);
|
||||||
|
g_assert(!g_strcmp0(sn->name, obj_name));
|
||||||
|
|
||||||
|
g_assert(gbinder_servicename_ref(sn) == sn);
|
||||||
|
gbinder_servicename_unref(sn);
|
||||||
|
|
||||||
|
gbinder_servicename_unref(sn);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_servicemanager_unref(sm);
|
||||||
|
|
||||||
|
/* We need to wait until GBinderIpc is destroyed */
|
||||||
|
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||||
|
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* present
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_present(
|
||||||
|
int add_result)
|
||||||
|
{
|
||||||
|
const char* obj_name = "test";
|
||||||
|
const char* const ifaces[] = { "interface", NULL };
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderLocalObject* obj;
|
||||||
|
GBinderServiceManager* sm;
|
||||||
|
GBinderServiceName* sn;
|
||||||
|
gulong id;
|
||||||
|
|
||||||
|
test_setup_ping(ipc);
|
||||||
|
sm = gbinder_servicemanager_new(dev);
|
||||||
|
TEST_SERVICEMANAGER(sm)->add_result = add_result;
|
||||||
|
obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
|
||||||
|
|
||||||
|
sn = gbinder_servicename_new(sm, obj, obj_name);
|
||||||
|
g_assert(sn);
|
||||||
|
g_assert(!g_strcmp0(sn->name, obj_name));
|
||||||
|
|
||||||
|
/* Immediately generate death notification (need looper for that) */
|
||||||
|
test_binder_br_dead_binder(fd, 0);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
|
id = gbinder_servicemanager_add_presence_handler(sm, test_quit, loop);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
gbinder_servicename_unref(sn);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_servicemanager_remove_handler(sm, id);
|
||||||
|
gbinder_servicemanager_unref(sm);
|
||||||
|
|
||||||
|
/* We need to wait until GBinderIpc is destroyed */
|
||||||
|
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||||
|
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_present_ok(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
test_present(GBINDER_STATUS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_present_err(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
test_present(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* not_present
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_not_present(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char* obj_name = "test";
|
||||||
|
const char* const ifaces[] = { "interface", NULL };
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderLocalObject* obj;
|
||||||
|
GBinderServiceManager* sm;
|
||||||
|
GBinderServiceName* sn;
|
||||||
|
gulong id;
|
||||||
|
|
||||||
|
/* This makes presence detection PING fail */
|
||||||
|
test_binder_br_reply_status(fd, -1);
|
||||||
|
sm = gbinder_servicemanager_new(dev);
|
||||||
|
g_assert(!gbinder_servicemanager_is_present(sm));
|
||||||
|
id = gbinder_servicemanager_add_presence_handler(sm, test_quit, loop);
|
||||||
|
obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
|
||||||
|
|
||||||
|
sn = gbinder_servicename_new(sm, obj, obj_name);
|
||||||
|
g_assert(sn);
|
||||||
|
g_assert(!g_strcmp0(sn->name, obj_name));
|
||||||
|
|
||||||
|
/* Make the next presence detection PING succeed */
|
||||||
|
test_binder_br_transaction_complete_later(fd);
|
||||||
|
test_binder_br_reply_later(fd, 0, 0, NULL);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
gbinder_servicename_unref(sn);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_servicemanager_remove_handler(sm, id);
|
||||||
|
gbinder_servicemanager_unref(sm);
|
||||||
|
|
||||||
|
/* We need to wait until GBinderIpc is destroyed */
|
||||||
|
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||||
|
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* cancel
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_cancel(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char* obj_name = "test";
|
||||||
|
const char* const ifaces[] = { "interface", NULL };
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderLocalObject* obj;
|
||||||
|
GBinderServiceManager* sm;
|
||||||
|
TestServiceManager* test;
|
||||||
|
GBinderServiceName* sn;
|
||||||
|
gulong id;
|
||||||
|
|
||||||
|
test_setup_ping(ipc);
|
||||||
|
sm = gbinder_servicemanager_new(dev);
|
||||||
|
obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
|
||||||
|
|
||||||
|
/* Block name add calls */
|
||||||
|
test = TEST_SERVICEMANAGER(sm);
|
||||||
|
g_mutex_lock(&test->mutex);
|
||||||
|
test->block_add = TRUE;
|
||||||
|
g_mutex_unlock(&test->mutex);
|
||||||
|
|
||||||
|
/* This adds the name but the call blocks */
|
||||||
|
sn = gbinder_servicename_new(sm, obj, obj_name);
|
||||||
|
g_assert(sn);
|
||||||
|
g_assert(!g_strcmp0(sn->name, obj_name));
|
||||||
|
|
||||||
|
/* Immediately generate death notification (need looper for that) */
|
||||||
|
test_binder_br_dead_binder(fd, 0);
|
||||||
|
test_binder_set_looper_enabled(fd, TRUE);
|
||||||
|
id = gbinder_servicemanager_add_presence_handler(sm, test_quit, loop);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
/* Add call is supposed to be cancelled */
|
||||||
|
gbinder_servicename_unref(sn);
|
||||||
|
gbinder_local_object_unref(obj);
|
||||||
|
gbinder_servicemanager_remove_handler(sm, id);
|
||||||
|
gbinder_servicemanager_unref(sm);
|
||||||
|
|
||||||
|
/* Unblock pending add */
|
||||||
|
g_mutex_lock(&test->mutex);
|
||||||
|
test->block_add = FALSE;
|
||||||
|
g_cond_signal(&test->cond);
|
||||||
|
g_mutex_unlock(&test->mutex);
|
||||||
|
|
||||||
|
/* We need to wait until GBinderIpc is destroyed */
|
||||||
|
GDEBUG("waiting for GBinderIpc to get destroyed");
|
||||||
|
g_object_weak_ref(G_OBJECT(ipc), test_quit_when_destroyed, loop);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* Common
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
#define TEST_(test) "/servicename/" test
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
g_test_add_func(TEST_("null"), test_null);
|
||||||
|
g_test_add_func(TEST_("basic"), test_basic);
|
||||||
|
g_test_add_func(TEST_("present_ok"), test_present_ok);
|
||||||
|
g_test_add_func(TEST_("present_err"), test_present_err);
|
||||||
|
g_test_add_func(TEST_("not_present"), test_not_present);
|
||||||
|
g_test_add_func(TEST_("cancel"), test_cancel);
|
||||||
|
test_init(&test_opt, argc, argv);
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
5
unit/unit_servicepoll/Makefile
Normal file
5
unit/unit_servicepoll/Makefile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# -*- Mode: makefile-gmake -*-
|
||||||
|
|
||||||
|
EXE = unit_servicepoll
|
||||||
|
|
||||||
|
include ../common/Makefile
|
||||||
488
unit/unit_servicepoll/unit_servicepoll.c
Normal file
488
unit/unit_servicepoll/unit_servicepoll.c
Normal file
@@ -0,0 +1,488 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
|
*
|
||||||
|
* You may use this file under the terms of BSD license as follows:
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test_binder.h"
|
||||||
|
|
||||||
|
#include "gbinder_driver.h"
|
||||||
|
#include "gbinder_ipc.h"
|
||||||
|
#include "gbinder_servicemanager_p.h"
|
||||||
|
#include "gbinder_servicepoll.h"
|
||||||
|
#include "gbinder_rpc_protocol.h"
|
||||||
|
|
||||||
|
#include <gutil_strv.h>
|
||||||
|
#include <gutil_log.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static TestOpt test_opt;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_setup_ping(
|
||||||
|
GBinderIpc* ipc)
|
||||||
|
{
|
||||||
|
const int fd = gbinder_driver_fd(ipc->driver);
|
||||||
|
|
||||||
|
test_binder_br_noop(fd);
|
||||||
|
test_binder_br_transaction_complete(fd);
|
||||||
|
test_binder_br_reply(fd, 0, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* TestServiceManager
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
typedef GBinderServiceManagerClass TestServiceManagerClass;
|
||||||
|
typedef struct test_servicemanager {
|
||||||
|
GBinderServiceManager manager;
|
||||||
|
GMutex mutex;
|
||||||
|
char** services;
|
||||||
|
} TestServiceManager;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(TestServiceManager, test_servicemanager,
|
||||||
|
GBINDER_TYPE_SERVICEMANAGER)
|
||||||
|
|
||||||
|
#define TEST_SERVICEMANAGER_IFACE "android.os.IServiceManager"
|
||||||
|
#define TEST_TYPE_SERVICEMANAGER (test_servicemanager_get_type())
|
||||||
|
#define TEST_SERVICEMANAGER(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||||
|
TEST_TYPE_SERVICEMANAGER, TestServiceManager)
|
||||||
|
|
||||||
|
static
|
||||||
|
char**
|
||||||
|
test_servicemanager_list(
|
||||||
|
GBinderServiceManager* manager)
|
||||||
|
{
|
||||||
|
char** ret;
|
||||||
|
TestServiceManager* self = TEST_SERVICEMANAGER(manager);
|
||||||
|
|
||||||
|
g_mutex_lock(&self->mutex);
|
||||||
|
ret = g_strdupv(self->services);
|
||||||
|
GDEBUG("%u", gutil_strv_length(ret));
|
||||||
|
g_mutex_unlock(&self->mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBinderRemoteObject*
|
||||||
|
test_servicemanager_get_service(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name,
|
||||||
|
int* status)
|
||||||
|
{
|
||||||
|
*status = (-ENOENT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
test_servicemanager_add_service(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name,
|
||||||
|
GBinderLocalObject* obj)
|
||||||
|
{
|
||||||
|
TestServiceManager* self = TEST_SERVICEMANAGER(manager);
|
||||||
|
|
||||||
|
g_mutex_lock(&self->mutex);
|
||||||
|
if (!gutil_strv_contains(self->services, name)) {
|
||||||
|
self->services = gutil_strv_add(self->services, name);
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&self->mutex);
|
||||||
|
return GBINDER_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
GBINDER_SERVICEMANAGER_NAME_CHECK
|
||||||
|
test_servicemanager_check_name(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
return name ?
|
||||||
|
GBINDER_SERVICEMANAGER_NAME_INVALID :
|
||||||
|
GBINDER_SERVICEMANAGER_NAME_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
test_servicemanager_watch(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_servicemanager_unwatch(
|
||||||
|
GBinderServiceManager* manager,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_servicemanager_init(
|
||||||
|
TestServiceManager* self)
|
||||||
|
{
|
||||||
|
g_mutex_init(&self->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_servicemanager_finalize(
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
TestServiceManager* self = TEST_SERVICEMANAGER(object);
|
||||||
|
|
||||||
|
g_mutex_clear(&self->mutex);
|
||||||
|
g_strfreev(self->services);
|
||||||
|
G_OBJECT_CLASS(test_servicemanager_parent_class)->finalize(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_servicemanager_class_init(
|
||||||
|
TestServiceManagerClass* klass)
|
||||||
|
{
|
||||||
|
klass->iface = TEST_SERVICEMANAGER_IFACE;
|
||||||
|
klass->default_device = GBINDER_DEFAULT_HWBINDER;
|
||||||
|
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
|
||||||
|
klass->list = test_servicemanager_list;
|
||||||
|
klass->get_service = test_servicemanager_get_service;
|
||||||
|
klass->add_service = test_servicemanager_add_service;
|
||||||
|
klass->check_name = test_servicemanager_check_name;
|
||||||
|
klass->watch = test_servicemanager_watch;
|
||||||
|
klass->unwatch = test_servicemanager_unwatch;
|
||||||
|
G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
GBinderServiceManager*
|
||||||
|
gbinder_defaultservicemanager_new(
|
||||||
|
const char* dev)
|
||||||
|
{
|
||||||
|
return gbinder_servicemanager_new_with_type(TEST_TYPE_SERVICEMANAGER, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBinderServiceManager*
|
||||||
|
gbinder_hwservicemanager_new(
|
||||||
|
const char* dev)
|
||||||
|
{
|
||||||
|
return gbinder_servicemanager_new(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* null
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_null(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
g_assert(!gbinder_servicepoll_ref(NULL));
|
||||||
|
g_assert(!gbinder_servicepoll_manager(NULL));
|
||||||
|
g_assert(!gbinder_servicepoll_is_known_name(NULL, ""));
|
||||||
|
g_assert(!gbinder_servicepoll_add_handler(NULL, NULL, NULL));
|
||||||
|
gbinder_servicepoll_remove_handler(NULL, 0);
|
||||||
|
gbinder_servicepoll_unref(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* basic
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_basic(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GBinderServicePoll* weakptr = NULL;
|
||||||
|
GBinderServiceManager* manager;
|
||||||
|
GBinderServicePoll* poll;
|
||||||
|
|
||||||
|
test_setup_ping(ipc);
|
||||||
|
manager = gbinder_servicemanager_new(dev);
|
||||||
|
poll = gbinder_servicepoll_new(manager, NULL);
|
||||||
|
g_assert(poll);
|
||||||
|
g_assert(gbinder_servicepoll_manager(poll) == manager);
|
||||||
|
g_assert(!gbinder_servicepoll_is_known_name(poll, "foo"));
|
||||||
|
g_assert(!gbinder_servicepoll_add_handler(poll, NULL, NULL));
|
||||||
|
gbinder_servicepoll_remove_handler(poll, 0); /* this does nothing */
|
||||||
|
gbinder_servicepoll_unref(poll);
|
||||||
|
|
||||||
|
poll = gbinder_servicepoll_new(manager, &weakptr);
|
||||||
|
g_assert(poll == weakptr);
|
||||||
|
g_assert(poll == gbinder_servicepoll_new(manager, &weakptr));
|
||||||
|
gbinder_servicepoll_unref(poll);
|
||||||
|
gbinder_servicepoll_unref(poll);
|
||||||
|
|
||||||
|
gbinder_servicemanager_unref(manager);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* notify1
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_notify_proc(
|
||||||
|
GBinderServicePoll* poll,
|
||||||
|
const char* name_added,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
GDEBUG("\"%s\" added", name_added);
|
||||||
|
if (!g_strcmp0(name_added, "foo")) {
|
||||||
|
test_quit_later((GMainLoop*)user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
test_notify1_foo(
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
TestServiceManager* test = user_data;
|
||||||
|
|
||||||
|
g_mutex_lock(&test->mutex);
|
||||||
|
GDEBUG("adding \"foo\"");
|
||||||
|
test->services = gutil_strv_add(test->services, "foo");
|
||||||
|
g_mutex_unlock(&test->mutex);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
test_notify1_bar(
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
TestServiceManager* test = user_data;
|
||||||
|
|
||||||
|
g_mutex_lock(&test->mutex);
|
||||||
|
GDEBUG("adding \"bar\"");
|
||||||
|
test->services = gutil_strv_add(test->services, "bar");
|
||||||
|
g_mutex_unlock(&test->mutex);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_notify1(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderServicePoll* weakptr = NULL;
|
||||||
|
GBinderServiceManager* manager;
|
||||||
|
TestServiceManager* test;
|
||||||
|
GBinderServicePoll* poll;
|
||||||
|
gulong id;
|
||||||
|
|
||||||
|
test_setup_ping(ipc);
|
||||||
|
manager = gbinder_servicemanager_new(dev);
|
||||||
|
test = TEST_SERVICEMANAGER(manager);
|
||||||
|
|
||||||
|
gbinder_servicepoll_interval_ms = 100;
|
||||||
|
poll = gbinder_servicepoll_new(manager, &weakptr);
|
||||||
|
g_timeout_add(2 * gbinder_servicepoll_interval_ms,
|
||||||
|
test_notify1_bar, test);
|
||||||
|
g_timeout_add(4 * gbinder_servicepoll_interval_ms,
|
||||||
|
test_notify1_foo, test);
|
||||||
|
|
||||||
|
id = gbinder_servicepoll_add_handler(poll, test_notify_proc, loop);
|
||||||
|
g_assert(id);
|
||||||
|
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
g_assert(gbinder_servicepoll_is_known_name(poll, "foo"));
|
||||||
|
g_assert(gbinder_servicepoll_is_known_name(poll, "bar"));
|
||||||
|
gbinder_servicepoll_remove_handler(poll, id);
|
||||||
|
gbinder_servicepoll_unref(poll);
|
||||||
|
g_assert(!weakptr);
|
||||||
|
gbinder_servicemanager_unref(manager);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* notify2
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
test_notify2_foo(
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
TestServiceManager* test = user_data;
|
||||||
|
|
||||||
|
g_mutex_lock(&test->mutex);
|
||||||
|
GDEBUG("services = [\"bar\",\"foo\"]");
|
||||||
|
g_strfreev(test->services);
|
||||||
|
test->services = g_strsplit("bar,bar3,foo", ",", -1);
|
||||||
|
g_mutex_unlock(&test->mutex);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
gboolean
|
||||||
|
test_notify2_bar(
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
TestServiceManager* test = user_data;
|
||||||
|
|
||||||
|
g_mutex_lock(&test->mutex);
|
||||||
|
GDEBUG("services = [\"bar1\",\"bar2\",\"bar3\"]");
|
||||||
|
g_strfreev(test->services);
|
||||||
|
test->services = g_strsplit("bar1,bar2,bar3", ",", -1);
|
||||||
|
g_mutex_unlock(&test->mutex);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_notify2(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderServicePoll* weakptr = NULL;
|
||||||
|
GBinderServiceManager* manager;
|
||||||
|
TestServiceManager* test;
|
||||||
|
GBinderServicePoll* poll;
|
||||||
|
gulong id;
|
||||||
|
|
||||||
|
test_setup_ping(ipc);
|
||||||
|
manager = gbinder_servicemanager_new(dev);
|
||||||
|
test = TEST_SERVICEMANAGER(manager);
|
||||||
|
|
||||||
|
gbinder_servicepoll_interval_ms = 100;
|
||||||
|
poll = gbinder_servicepoll_new(manager, &weakptr);
|
||||||
|
g_timeout_add(2 * gbinder_servicepoll_interval_ms,
|
||||||
|
test_notify2_bar, test);
|
||||||
|
g_timeout_add(4 * gbinder_servicepoll_interval_ms,
|
||||||
|
test_notify2_foo, test);
|
||||||
|
|
||||||
|
/* Reusing test_notify_proc */
|
||||||
|
id = gbinder_servicepoll_add_handler(poll, test_notify_proc, loop);
|
||||||
|
g_assert(id);
|
||||||
|
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
g_assert(gbinder_servicepoll_is_known_name(poll, "foo"));
|
||||||
|
g_assert(gbinder_servicepoll_is_known_name(poll, "bar"));
|
||||||
|
g_assert(gbinder_servicepoll_is_known_name(poll, "bar3"));
|
||||||
|
g_assert(!gbinder_servicepoll_is_known_name(poll, "bar1"));
|
||||||
|
g_assert(!gbinder_servicepoll_is_known_name(poll, "bar2"));
|
||||||
|
gbinder_servicepoll_remove_handler(poll, id);
|
||||||
|
gbinder_servicepoll_unref(poll);
|
||||||
|
g_assert(!weakptr);
|
||||||
|
gbinder_servicemanager_unref(manager);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* already_there
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_already_there_proc(
|
||||||
|
GBinderServicePoll* poll,
|
||||||
|
const char* name_added,
|
||||||
|
void* user_data)
|
||||||
|
{
|
||||||
|
g_assert(!g_strcmp0(name_added, "foo"));
|
||||||
|
test_quit_later((GMainLoop*)user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_already_there(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char* dev = GBINDER_DEFAULT_BINDER;
|
||||||
|
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
|
||||||
|
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
GBinderServicePoll* weakptr = NULL;
|
||||||
|
GBinderServiceManager* manager;
|
||||||
|
TestServiceManager* test;
|
||||||
|
GBinderServicePoll* poll;
|
||||||
|
gulong id;
|
||||||
|
|
||||||
|
test_setup_ping(ipc);
|
||||||
|
manager = gbinder_servicemanager_new(dev);
|
||||||
|
poll = gbinder_servicepoll_new(manager, &weakptr);
|
||||||
|
test = TEST_SERVICEMANAGER(manager);
|
||||||
|
|
||||||
|
test->services = gutil_strv_add(test->services, "foo");
|
||||||
|
id = gbinder_servicepoll_add_handler(poll, test_already_there_proc, loop);
|
||||||
|
|
||||||
|
g_assert(id);
|
||||||
|
test_run(&test_opt, loop);
|
||||||
|
|
||||||
|
gbinder_servicepoll_remove_handler(poll, id);
|
||||||
|
gbinder_servicepoll_unref(poll);
|
||||||
|
g_assert(!weakptr);
|
||||||
|
gbinder_servicemanager_unref(manager);
|
||||||
|
gbinder_ipc_unref(ipc);
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* Common
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
#define TEST_(t) "/servicepoll/" t
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
g_test_add_func(TEST_("null"), test_null);
|
||||||
|
g_test_add_func(TEST_("basic"), test_basic);
|
||||||
|
g_test_add_func(TEST_("notify1"), test_notify1);
|
||||||
|
g_test_add_func(TEST_("notify2"), test_notify2);
|
||||||
|
g_test_add_func(TEST_("already_there"), test_already_there);
|
||||||
|
test_init(&test_opt, argc, argv);
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local Variables:
|
||||||
|
* mode: C
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2019 Jolla Ltd.
|
||||||
* Contact: Slava Monich <slava.monich@jolla.com>
|
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
|
||||||
*
|
*
|
||||||
* You may use this file under the terms of BSD license as follows:
|
* You may use this file under the terms of BSD license as follows:
|
||||||
*
|
*
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
* be used to endorse or promote products derived from this software
|
* contributors may be used to endorse or promote products derived from
|
||||||
* without specific prior written permission.
|
* this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
@@ -39,6 +39,8 @@
|
|||||||
|
|
||||||
#include <gutil_intarray.h>
|
#include <gutil_intarray.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
static TestOpt test_opt;
|
static TestOpt test_opt;
|
||||||
|
|
||||||
#define BUFFER_OBJECT_SIZE_32 (24)
|
#define BUFFER_OBJECT_SIZE_32 (24)
|
||||||
@@ -74,10 +76,13 @@ test_null(
|
|||||||
gbinder_writer_append_string16(&writer, NULL);
|
gbinder_writer_append_string16(&writer, NULL);
|
||||||
gbinder_writer_append_string16_len(NULL, NULL, 0);
|
gbinder_writer_append_string16_len(NULL, NULL, 0);
|
||||||
gbinder_writer_append_string16_len(&writer, NULL, 0);
|
gbinder_writer_append_string16_len(&writer, NULL, 0);
|
||||||
|
gbinder_writer_append_string16_utf16(NULL, NULL, 0);
|
||||||
gbinder_writer_append_bool(NULL, FALSE);
|
gbinder_writer_append_bool(NULL, FALSE);
|
||||||
gbinder_writer_append_bool(&writer, FALSE);
|
gbinder_writer_append_bool(&writer, FALSE);
|
||||||
|
gbinder_writer_append_fd(NULL, 0);
|
||||||
gbinder_writer_append_bytes(NULL, NULL, 0);
|
gbinder_writer_append_bytes(NULL, NULL, 0);
|
||||||
gbinder_writer_append_bytes(&writer, NULL, 0);
|
gbinder_writer_append_bytes(&writer, NULL, 0);
|
||||||
|
gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0);
|
||||||
gbinder_writer_append_hidl_string(NULL, NULL);
|
gbinder_writer_append_hidl_string(NULL, NULL);
|
||||||
gbinder_writer_append_hidl_string(&writer, NULL);
|
gbinder_writer_append_hidl_string(&writer, NULL);
|
||||||
gbinder_writer_append_hidl_string_vec(NULL, NULL, 0);
|
gbinder_writer_append_hidl_string_vec(NULL, NULL, 0);
|
||||||
@@ -90,9 +95,53 @@ test_null(
|
|||||||
gbinder_writer_append_local_object(&writer, NULL);
|
gbinder_writer_append_local_object(&writer, NULL);
|
||||||
gbinder_writer_append_remote_object(NULL, NULL);
|
gbinder_writer_append_remote_object(NULL, NULL);
|
||||||
gbinder_writer_append_remote_object(&writer, NULL);
|
gbinder_writer_append_remote_object(&writer, NULL);
|
||||||
|
gbinder_writer_append_byte_array(NULL, NULL, 0);
|
||||||
|
gbinder_writer_append_byte_array(&writer, NULL, 0);
|
||||||
|
gbinder_writer_add_cleanup(NULL, NULL, 0);
|
||||||
|
gbinder_writer_add_cleanup(NULL, g_free, 0);
|
||||||
|
gbinder_writer_overwrite_int32(NULL, 0, 0);
|
||||||
|
|
||||||
g_assert(!gbinder_output_data_offsets(NULL));
|
g_assert(!gbinder_output_data_offsets(NULL));
|
||||||
g_assert(!gbinder_output_data_buffers_size(NULL));
|
g_assert(!gbinder_output_data_buffers_size(NULL));
|
||||||
|
g_assert(!gbinder_writer_malloc(NULL, 0));
|
||||||
|
g_assert(!gbinder_writer_malloc0(NULL, 0));
|
||||||
|
g_assert(!gbinder_writer_memdup(&writer, NULL, 0));
|
||||||
|
g_assert(!gbinder_writer_memdup(NULL, &writer, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* cleanup
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_cleanup_fn(
|
||||||
|
gpointer ptr)
|
||||||
|
{
|
||||||
|
(*((int*)ptr))++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_cleanup(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||||
|
GBinderWriter writer;
|
||||||
|
int cleanup_count = 0;
|
||||||
|
int value = 42;
|
||||||
|
int* zero;
|
||||||
|
int* copy;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
zero = gbinder_writer_new0(&writer, int);
|
||||||
|
copy = gbinder_writer_memdup(&writer, &value, sizeof(value));
|
||||||
|
g_assert(*zero == 0);
|
||||||
|
g_assert(*copy == value);
|
||||||
|
gbinder_writer_add_cleanup(&writer, test_cleanup_fn, &cleanup_count);
|
||||||
|
gbinder_writer_add_cleanup(&writer, test_cleanup_fn, &cleanup_count);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
g_assert(cleanup_count == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
@@ -116,6 +165,19 @@ test_int32(
|
|||||||
g_assert(!gbinder_output_data_buffers_size(data));
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
g_assert(data->bytes->len == sizeof(value));
|
g_assert(data->bytes->len == sizeof(value));
|
||||||
g_assert(!memcmp(data->bytes->data, &value, data->bytes->len));
|
g_assert(!memcmp(data->bytes->data, &value, data->bytes->len));
|
||||||
|
|
||||||
|
const guint32 value2 = 2345678;
|
||||||
|
gbinder_writer_overwrite_int32(&writer, 0, value2);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
g_assert(!gbinder_output_data_offsets(data));
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(data->bytes->len == sizeof(value2));
|
||||||
|
g_assert(!memcmp(data->bytes->data, &value2, data->bytes->len));
|
||||||
|
|
||||||
|
// test overlap over the end of the buffer
|
||||||
|
gbinder_writer_overwrite_int32(&writer, 2, value2);
|
||||||
|
g_assert(data->bytes->len == sizeof(value2));
|
||||||
|
|
||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,9 +263,9 @@ test_bool(
|
|||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
const char encoded[] = {
|
const char encoded[] = {
|
||||||
0x00, 0xff, 0xff, 0xff,
|
0x00, 0x00, 0x00, 0x00,
|
||||||
0x01, 0xff, 0xff, 0xff,
|
0x01, 0x00, 0x00, 0x00,
|
||||||
0x01, 0xff, 0xff, 0xff
|
0x01, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||||
GBinderOutputData* data;
|
GBinderOutputData* data;
|
||||||
@@ -339,6 +401,136 @@ test_string16(
|
|||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* utf16
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
typedef struct test_utf16_data {
|
||||||
|
const char* name;
|
||||||
|
const gunichar2* in;
|
||||||
|
gssize in_len;
|
||||||
|
const guint8* out;
|
||||||
|
gssize out_len;
|
||||||
|
} TestUtf16Data;
|
||||||
|
|
||||||
|
static const guint8 utf16_tests_data_null[] = {
|
||||||
|
TEST_INT32_BYTES(-1)
|
||||||
|
};
|
||||||
|
|
||||||
|
static const guint8 utf16_tests_data_empty[] = {
|
||||||
|
TEST_INT32_BYTES(0),
|
||||||
|
0x00, 0x00, 0xff, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
static const guint8 utf16_tests_data_x[] = {
|
||||||
|
TEST_INT32_BYTES(1),
|
||||||
|
TEST_INT16_BYTES('x'), 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
static const guint8 utf16_tests_data_xy[] = {
|
||||||
|
TEST_INT32_BYTES(2),
|
||||||
|
TEST_INT16_BYTES('x'), TEST_INT16_BYTES('y'),
|
||||||
|
0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
static const gunichar2 utf16_tests_input_empty[] = { 0 };
|
||||||
|
static const gunichar2 utf16_tests_input_x[] = { 'x', 0 };
|
||||||
|
static const gunichar2 utf16_tests_input_xy[] = { 'x', 'y', 0 };
|
||||||
|
|
||||||
|
static const TestUtf16Data test_utf16_tests[] = {
|
||||||
|
{ "null", NULL, -1,
|
||||||
|
TEST_ARRAY_AND_SIZE(utf16_tests_data_null) },
|
||||||
|
{ "empty", utf16_tests_input_empty, -1,
|
||||||
|
TEST_ARRAY_AND_SIZE(utf16_tests_data_empty) },
|
||||||
|
{ "1", utf16_tests_input_x, -1,
|
||||||
|
TEST_ARRAY_AND_SIZE(utf16_tests_data_x) },
|
||||||
|
{ "2", utf16_tests_input_xy, 1,
|
||||||
|
TEST_ARRAY_AND_SIZE(utf16_tests_data_x) },
|
||||||
|
{ "3", utf16_tests_input_xy, -1,
|
||||||
|
TEST_ARRAY_AND_SIZE(utf16_tests_data_xy) }
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_utf16(
|
||||||
|
gconstpointer test_data)
|
||||||
|
{
|
||||||
|
const TestUtf16Data* test = test_data;
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GBinderWriter writer;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_string16_utf16(&writer, test->in, test->in_len);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
g_assert(!gbinder_output_data_offsets(data));
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(data->bytes->len == test->out_len);
|
||||||
|
g_assert(!memcmp(data->bytes->data, test->out, test->out_len));
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* hidl_vec
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
typedef struct test_hidl_vec_data {
|
||||||
|
const char* name;
|
||||||
|
const GBinderIo* io;
|
||||||
|
const void* data;
|
||||||
|
const gsize count;
|
||||||
|
const gsize elemsize;
|
||||||
|
const guint* offsets;
|
||||||
|
guint offsets_count;
|
||||||
|
guint buffers_size;
|
||||||
|
} TestHidlVecData;
|
||||||
|
|
||||||
|
static guint test_hidl_vec_offsets_0[] =
|
||||||
|
{ 0 };
|
||||||
|
static guint test_hidl_vec_offsets_32[] =
|
||||||
|
{ 0, BUFFER_OBJECT_SIZE_32 };
|
||||||
|
static guint test_hidl_vec_offsets_64[] =
|
||||||
|
{ 0, BUFFER_OBJECT_SIZE_64 };
|
||||||
|
|
||||||
|
static const TestHidlVecData test_hidl_vec_tests[] = {
|
||||||
|
{ "32/null", &gbinder_io_32, NULL, 0, 0,
|
||||||
|
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(GBinderHidlVec) },
|
||||||
|
{ "32/2x1", &gbinder_io_32, "xy", 2, 1,
|
||||||
|
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_32),
|
||||||
|
sizeof(GBinderHidlVec) + 8 /* vec data aligned at 8 bytes boundary */ },
|
||||||
|
{ "64/null", &gbinder_io_64, NULL, 0, 0,
|
||||||
|
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(GBinderHidlVec) },
|
||||||
|
{ "64/2x2", &gbinder_io_64, "xxyy", 2, 2,
|
||||||
|
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_64),
|
||||||
|
sizeof(GBinderHidlVec) + 8 /* vec data aligned at 8 bytes boundary */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_hidl_vec(
|
||||||
|
gconstpointer test_data)
|
||||||
|
{
|
||||||
|
const TestHidlVecData* test = test_data;
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(test->io, NULL);
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GBinderWriter writer;
|
||||||
|
GUtilIntArray* offsets;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_hidl_vec(&writer, test->data,
|
||||||
|
test->count, test->elemsize);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
offsets = gbinder_output_data_offsets(data);
|
||||||
|
g_assert(offsets);
|
||||||
|
g_assert(offsets->count == test->offsets_count);
|
||||||
|
for (i = 0; i < offsets->count; i++) {
|
||||||
|
g_assert(offsets->data[i] == test->offsets[i]);
|
||||||
|
}
|
||||||
|
g_assert(gbinder_output_data_buffers_size(data) == test->buffers_size);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* hidl_string
|
* hidl_string
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -361,15 +553,17 @@ static guint test_hidl_string_offsets_64[] =
|
|||||||
|
|
||||||
static const TestHidlStringData test_hidl_string_tests[] = {
|
static const TestHidlStringData test_hidl_string_tests[] = {
|
||||||
{ "32/null", &gbinder_io_32, NULL,
|
{ "32/null", &gbinder_io_32, NULL,
|
||||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0), sizeof(HidlString) },
|
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0),
|
||||||
|
sizeof(GBinderHidlString) },
|
||||||
{ "32/xxx", &gbinder_io_32, "xxx",
|
{ "32/xxx", &gbinder_io_32, "xxx",
|
||||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_32),
|
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_32),
|
||||||
sizeof(HidlString) + 8 /* string data aligned at 8 bytes boundary */ },
|
sizeof(GBinderHidlString) + 8 /* string data aligned at 8 bytes */ },
|
||||||
{ "64/null", &gbinder_io_64, NULL,
|
{ "64/null", &gbinder_io_64, NULL,
|
||||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0), sizeof(HidlString) },
|
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0),
|
||||||
|
sizeof(GBinderHidlString) },
|
||||||
{ "64/xxxxxxx", &gbinder_io_64, "xxxxxxx",
|
{ "64/xxxxxxx", &gbinder_io_64, "xxxxxxx",
|
||||||
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_64),
|
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_64),
|
||||||
sizeof(HidlString) + 8 /* string data aligned at 8 bytes boundary */ }
|
sizeof(GBinderHidlString) + 8 /* string data aligned at 8 bytes */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -417,8 +611,9 @@ test_hidl_string2(
|
|||||||
g_assert(offsets->data[0] == 0);
|
g_assert(offsets->data[0] == 0);
|
||||||
g_assert(offsets->data[1] == BUFFER_OBJECT_SIZE_32);
|
g_assert(offsets->data[1] == BUFFER_OBJECT_SIZE_32);
|
||||||
g_assert(offsets->data[2] == 2*BUFFER_OBJECT_SIZE_32);
|
g_assert(offsets->data[2] == 2*BUFFER_OBJECT_SIZE_32);
|
||||||
/* 2 HidlStrings + "foo" aligned at 8 bytes boundary */
|
/* 2 GBinderHidlStrings + "foo" aligned at 8 bytes boundary */
|
||||||
g_assert(gbinder_output_data_buffers_size(data) == 2*sizeof(HidlString)+8);
|
g_assert(gbinder_output_data_buffers_size(data) ==
|
||||||
|
(2 * sizeof(GBinderHidlString) + 8));
|
||||||
|
|
||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
@@ -449,18 +644,18 @@ static guint test_hidl_string_vec_offsets_1_64[] =
|
|||||||
static const TestHidlStringVecData test_hidl_string_vec_tests[] = {
|
static const TestHidlStringVecData test_hidl_string_vec_tests[] = {
|
||||||
{ "32/null", &gbinder_io_32, NULL, -1,
|
{ "32/null", &gbinder_io_32, NULL, -1,
|
||||||
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
|
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
|
||||||
sizeof(HidlVec) },
|
sizeof(GBinderHidlVec) },
|
||||||
{ "32/1", &gbinder_io_32,
|
{ "32/1", &gbinder_io_32,
|
||||||
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
|
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
|
||||||
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_32),
|
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_32),
|
||||||
sizeof(HidlVec) + sizeof(HidlString) + 8 },
|
sizeof(GBinderHidlVec) + sizeof(GBinderHidlString) + 8 },
|
||||||
{ "64/null", &gbinder_io_64, NULL, -1,
|
{ "64/null", &gbinder_io_64, NULL, -1,
|
||||||
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
|
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
|
||||||
sizeof(HidlVec) },
|
sizeof(GBinderHidlVec) },
|
||||||
{ "64/1", &gbinder_io_64,
|
{ "64/1", &gbinder_io_64,
|
||||||
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
|
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
|
||||||
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_64),
|
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_64),
|
||||||
sizeof(HidlVec) + sizeof(HidlString) + 8 },
|
sizeof(GBinderHidlVec) + sizeof(GBinderHidlString) + 8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -569,6 +764,76 @@ test_parent(
|
|||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* fd
|
||||||
|
* fd_invalid
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd2(
|
||||||
|
int fd)
|
||||||
|
{
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GUtilIntArray* offsets;
|
||||||
|
GBinderWriter writer;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_fd(&writer, fd);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
offsets = gbinder_output_data_offsets(data);
|
||||||
|
g_assert(offsets);
|
||||||
|
g_assert(offsets->count == 1);
|
||||||
|
g_assert(offsets->data[0] == 0);
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
test_fd2(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd_invalid(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
test_fd2(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* fd_close_error
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_fd_close_error(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const GBinderIo* io = &gbinder_io_32;
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GBinderWriter writer;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_fd(&writer, STDOUT_FILENO);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
|
||||||
|
|
||||||
|
/* Fetch duplicated fd and close it. That makes the second close
|
||||||
|
* done by gbinder_writer_data_close_fd() fail. */
|
||||||
|
g_assert(io->decode_fd_object(data->bytes->data, data->bytes->len, &fd));
|
||||||
|
g_assert(close(fd) == 0);
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* local_object
|
* local_object
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
@@ -621,38 +886,128 @@ test_remote_object(
|
|||||||
gbinder_local_request_unref(req);
|
gbinder_local_request_unref(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* byte_array
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_byte_array(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
GBinderLocalRequest* req;
|
||||||
|
GBinderOutputData* data;
|
||||||
|
GBinderWriter writer;
|
||||||
|
|
||||||
|
const char in_data[] = "abcd1234";
|
||||||
|
gint32 in_len = sizeof(in_data) - 1;
|
||||||
|
gint32 null_len = -1;
|
||||||
|
|
||||||
|
/* test for NULL byte array with non-zero len */
|
||||||
|
req = gbinder_local_request_new(&gbinder_io_64, NULL);
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_byte_array(&writer, NULL, 42);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
g_assert(!gbinder_output_data_offsets(data));
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(data->bytes->len == sizeof(gint32));
|
||||||
|
g_assert(!memcmp(data->bytes->data, &null_len, data->bytes->len));
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
|
||||||
|
/* test for valid array with zero len */
|
||||||
|
req = gbinder_local_request_new(&gbinder_io_64, NULL);
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_byte_array(&writer, in_data, 0);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
g_assert(!gbinder_output_data_offsets(data));
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(data->bytes->len == sizeof(gint32));
|
||||||
|
g_assert(!memcmp(data->bytes->data, &null_len, data->bytes->len));
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
|
||||||
|
/* test for valid array with correct len */
|
||||||
|
req = gbinder_local_request_new(&gbinder_io_64, NULL);
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
gbinder_writer_append_byte_array(&writer, in_data, in_len);
|
||||||
|
data = gbinder_local_request_data(req);
|
||||||
|
g_assert(!gbinder_output_data_offsets(data));
|
||||||
|
g_assert(!gbinder_output_data_buffers_size(data));
|
||||||
|
g_assert(data->bytes->len == sizeof(in_len) + in_len);
|
||||||
|
g_assert(!memcmp(data->bytes->data, &in_len, sizeof(in_len)));
|
||||||
|
g_assert(!memcmp(data->bytes->data + sizeof(in_len), in_data, in_len));
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*==========================================================================*
|
||||||
|
* bytes_written
|
||||||
|
*==========================================================================*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
test_bytes_written(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const guint32 value = 1234567;
|
||||||
|
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
|
||||||
|
GBinderWriter writer;
|
||||||
|
|
||||||
|
gbinder_local_request_init_writer(req, &writer);
|
||||||
|
g_assert(gbinder_writer_bytes_written(&writer) == 0);
|
||||||
|
gbinder_writer_append_int32(&writer, value);
|
||||||
|
g_assert(gbinder_writer_bytes_written(&writer) == sizeof(value));
|
||||||
|
|
||||||
|
gbinder_local_request_unref(req);
|
||||||
|
}
|
||||||
/*==========================================================================*
|
/*==========================================================================*
|
||||||
* Common
|
* Common
|
||||||
*==========================================================================*/
|
*==========================================================================*/
|
||||||
|
|
||||||
#define TEST_PREFIX "/writer/"
|
#define TEST_PREFIX "/writer/"
|
||||||
|
#define TEST_(t) TEST_PREFIX t
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
g_test_add_func(TEST_PREFIX "null", test_null);
|
g_test_add_func(TEST_("null"), test_null);
|
||||||
g_test_add_func(TEST_PREFIX "int32", test_int32);
|
g_test_add_func(TEST_("cleanup"), test_cleanup);
|
||||||
g_test_add_func(TEST_PREFIX "int64", test_int64);
|
g_test_add_func(TEST_("int32"), test_int32);
|
||||||
g_test_add_func(TEST_PREFIX "float", test_float);
|
g_test_add_func(TEST_("int64"), test_int64);
|
||||||
g_test_add_func(TEST_PREFIX "double", test_double);
|
g_test_add_func(TEST_("float"), test_float);
|
||||||
g_test_add_func(TEST_PREFIX "bool", test_bool);
|
g_test_add_func(TEST_("double"), test_double);
|
||||||
g_test_add_func(TEST_PREFIX "bytes", test_bytes);
|
g_test_add_func(TEST_("bool"), test_bool);
|
||||||
g_test_add_func(TEST_PREFIX "string8", test_string8);
|
g_test_add_func(TEST_("bytes"), test_bytes);
|
||||||
|
g_test_add_func(TEST_("string8"), test_string8);
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(test_string16_tests); i++) {
|
for (i = 0; i < G_N_ELEMENTS(test_string16_tests); i++) {
|
||||||
const TestString16Data* test = test_string16_tests + i;
|
const TestString16Data* test = test_string16_tests + i;
|
||||||
char* path = g_strconcat(TEST_PREFIX "string16/", test->name, NULL);
|
char* path = g_strconcat(TEST_("string16/"), test->name, NULL);
|
||||||
|
|
||||||
g_test_add_data_func(path, test, test_string16);
|
g_test_add_data_func(path, test, test_string16);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_test_add_func(TEST_PREFIX "hidl_string/2strings", test_hidl_string2);
|
for (i = 0; i < G_N_ELEMENTS(test_utf16_tests); i++) {
|
||||||
|
const TestUtf16Data* test = test_utf16_tests + i;
|
||||||
|
char* path = g_strconcat(TEST_("utf16/"), test->name, NULL);
|
||||||
|
|
||||||
|
g_test_add_data_func(path, test, test_utf16);
|
||||||
|
g_free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS(test_hidl_vec_tests); i++) {
|
||||||
|
const TestHidlVecData* test = test_hidl_vec_tests + i;
|
||||||
|
char* path = g_strconcat(TEST_("hidl_vec/"), test->name, NULL);
|
||||||
|
|
||||||
|
g_test_add_data_func(path, test, test_hidl_vec);
|
||||||
|
g_free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_test_add_func(TEST_("hidl_string/2strings"), test_hidl_string2);
|
||||||
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_tests); i++) {
|
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_tests); i++) {
|
||||||
const TestHidlStringData* test = test_hidl_string_tests + i;
|
const TestHidlStringData* test = test_hidl_string_tests + i;
|
||||||
char* path = g_strconcat(TEST_PREFIX "hidl_string/", test->name, NULL);
|
char* path = g_strconcat(TEST_("hidl_string/"), test->name, NULL);
|
||||||
|
|
||||||
g_test_add_data_func(path, test, test_hidl_string);
|
g_test_add_data_func(path, test, test_hidl_string);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
@@ -660,17 +1015,21 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_vec_tests); i++) {
|
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_vec_tests); i++) {
|
||||||
const TestHidlStringVecData* test = test_hidl_string_vec_tests + i;
|
const TestHidlStringVecData* test = test_hidl_string_vec_tests + i;
|
||||||
char* path = g_strconcat(TEST_PREFIX "hidl_string_vec/",
|
char* path = g_strconcat(TEST_("hidl_string_vec/"), test->name, NULL);
|
||||||
test->name, NULL);
|
|
||||||
|
|
||||||
g_test_add_data_func(path, test, test_hidl_string_vec);
|
g_test_add_data_func(path, test, test_hidl_string_vec);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_test_add_func(TEST_PREFIX "buffer", test_buffer);
|
g_test_add_func(TEST_("buffer"), test_buffer);
|
||||||
g_test_add_func(TEST_PREFIX "parent", test_parent);
|
g_test_add_func(TEST_("parent"), test_parent);
|
||||||
g_test_add_func(TEST_PREFIX "local_object", test_local_object);
|
g_test_add_func(TEST_("fd"), test_fd);
|
||||||
g_test_add_func(TEST_PREFIX "remote_object", test_remote_object);
|
g_test_add_func(TEST_("fd_invalid"), test_fd_invalid);
|
||||||
|
g_test_add_func(TEST_("fd_close_error"), test_fd_close_error);
|
||||||
|
g_test_add_func(TEST_("local_object"), test_local_object);
|
||||||
|
g_test_add_func(TEST_("remote_object"), test_remote_object);
|
||||||
|
g_test_add_func(TEST_("byte_array"), test_byte_array);
|
||||||
|
g_test_add_func(TEST_("bytes_written"), test_bytes_written);
|
||||||
test_init(&test_opt, argc, argv);
|
test_init(&test_opt, argc, argv);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user