Compare commits

...

82 Commits

Author SHA1 Message Date
Slava Monich
ba2ddf4163 Version 1.0.32 2019-05-17 15:58:22 +03:00
Slava Monich
3d16384acd Merge pull request #37 from monich/dead
Refuse to perform transactions with dead objects
2019-05-17 15:54:12 +03:00
Slava Monich
0f73626025 [gbinder] Refuse to perform transactions with dead objects. JB#42956
Stale handle may be pointing to a random valid object, resulting
in a mess and unexpected behavior.
2019-05-17 15:04:19 +03:00
Slava Monich
84fb44e519 Version 1.0.31 2019-05-13 18:08:00 +03:00
Slava Monich
aafe23396a Merge pull request #36 from monich/drop_handle
Invalidate handle when remote object dies
2019-05-13 18:03:30 +03:00
Slava Monich
51f270df67 [gbinder] Hardcode servicemanager handle. JB#42956
It's always zero, keeping it configurable would complicate object
death handling for no good reason.
2019-05-13 15:09:45 +03:00
Slava Monich
e9c404de92 [gbinder] Invalidate handle when remote object dies. JB#42956
Otherwise the handle may get reused by the remote side but on
our side it would remain mapped to the old GBinderRemoteObject
(as long as there are any references to it), possibly pointing
to an entirely different object.
2019-05-13 14:40:33 +03:00
Slava Monich
141bda151b Version 1.0.30 2019-02-20 12:00:07 +02:00
Slava Monich
e952380ce6 Merge pull request #35 from monich/localobj
Make gbinder_local_object_new() public
2019-02-20 11:57:10 +02:00
Slava Monich
721f5dc469 [gbinder] Made gbinder_local_object_new() public. JB#44551
Until now, gbinder_servicemanager_new_local_object() was the only
API for creating local objects. That was slightly weird because
creating local object don't have much to do servicemanager, it's
a purely local operation. All we need to know is which binder
device (GBinderIpc) the object is going to be associated with.
That's what gbinder_remote_object_ipc() is for.
2019-02-19 23:56:29 +02:00
Slava Monich
434b17eefe Version 1.0.29 2019-02-14 18:18:50 +03:00
Slava Monich
af6a1c84ef Merge pull request #34 from monich/ifaces
Add gbinder_servicemanager_new_local_object2()
2019-02-14 18:12:24 +03:00
Slava Monich
a0ce447a1f [gbinder] Add gbinder_servicemanager_new_local_object2. Fixes JB#44766
It allows to pass a list of interfaces (top-most interface first) for
HIDL_DESCRIPTOR_CHAIN_TRANSACTION to GBinderLocalObject.
2019-02-14 12:31:54 +03:00
Slava Monich
f24145f407 Version 1.0.28 2019-01-29 02:50:13 +02:00
Slava Monich
11c173b2e4 Merge pull request #33 from mer-hybris/jb44588
Set type for local nulls to BINDER_TYPE_WEAK_BINDER
2019-01-29 02:48:09 +02:00
Andrew Branson
aff816d10c [binder] Set type for local nulls to BINDER_TYPE_WEAK_BINDER. JB#44588
Else they are not equivalent to null in Java.
2019-01-29 01:09:52 +01:00
Slava Monich
e1acaa3bdb Version 1.0.27 2019-01-24 18:56:58 +02:00
Slava Monich
c63743ac51 Merge pull request #32 from monich/oneway
Fix outgoing oneway transactions
2019-01-24 18:53:51 +02:00
Slava Monich
6832d9bf46 [unit] Added unit test for async oneway transactions 2019-01-24 18:51:26 +02:00
Slava Monich
4c3ccbc06f [gbinder] Fixed outgoing oneway transactions. JB#42956
Oneway transactions didn't have the appropriate flag set.
Also, a reply was unnecessarily allocated for those and
then just deallocated, which was a total waste.
2019-01-24 18:36:20 +02:00
Slava Monich
f82596c372 Version 1.0.26 2019-01-23 17:45:25 +02:00
Slava Monich
4921a6ab8d Merge pull request #28 from monich/interface_tx
Implement PING and INTERFACE transactions
2019-01-23 17:39:07 +02:00
Slava Monich
ef9c242a59 Merge pull request #30 from monich/servicename
Add GBinderServiceName object
2019-01-23 17:34:13 +02:00
Slava Monich
a83c9937a5 Merge pull request #29 from monich/utf16
Add gbinder_reader_read_string16_utf16()
2019-01-23 17:25:40 +02:00
Slava Monich
cfa3ad4d9e [unit] Added unit test for GBinderServiceName 2019-01-23 01:35:56 +02:00
Slava Monich
ffc9638ebb [gbinder] Added GBinderServiceName object. JB#42956
It keeps GBinderLocalObject registered, waiting for servicemanager
to appear and re-registering the object after servicemanager restarts.
2019-01-23 01:34:54 +02:00
Slava Monich
000534654d [gbinder] Added gbinder_reader_read_string16_utf16(). JB#42956
Returns const pointer to UTF-16 string in binder's buffer. The
memory pointed to by this string gets automatically deallocated
by libgbinder when transaction completes.

Also added const to gbinder_reader_read_nullable_string16_utf16()
output argument. It may cause compilation warnings, but that makes
it obvious that caller doesn't deallocate the returned pointer, in
my opinion it's worth the trouble.
2019-01-22 18:39:51 +02:00
Slava Monich
68e9358d02 [gbinder] Added tests for PING and INTERFACE transactions 2019-01-22 17:36:02 +02:00
Slava Monich
37e3859f8f [gbinder] Implement PING and INTERFACE transactions. JB#42956 2019-01-22 17:36:02 +02:00
Slava Monich
e79b940b0d Version 1.0.25 2019-01-22 16:05:32 +02:00
Slava Monich
d8dfe3f289 Merge pull request #27 from monich/sm_presence
ServiceManager presence API
2019-01-22 16:00:35 +02:00
Slava Monich
394c286ee5 [gbinder] Re-arm watches after restart of servicemanager. JB#42956 2019-01-20 18:14:15 +02:00
Slava Monich
307bd6942c [gbinder] Added servicemanager presence API. JB#42956
This function allows to wait for servicemanager synchronously,
blocking the event loop in the process (not recommended):

  gbinder_servicemanager_wait()

These two allow to follow the presence state of servicemanager
without blocking the event loop:

  gbinder_servicemanager_is_present()
  gbinder_servicemanager_add_presence_handler()

Note that services need to re-add their names to servicemanager
after it has restarted. This can be done by the presence handler.
2019-01-20 14:12:25 +02:00
Slava Monich
148b53e862 Version 1.0.24 2019-01-18 21:38:03 +02:00
Slava Monich
5c8cb0a013 Merge pull request #26 from mlehtima/jb44476
Revert "Make sure NULL objects are passed as BINDER_TYPE_WEAK_HANDLE"
2019-01-18 21:34:03 +02:00
Matti Lehtimäki
4d644e0584 [local_object] Revert "Make sure NULL objects are passed as BINDER_TYPE_WEAK_HANDLE". Fixes JB#44476
This reverts commit 3b299d3345 which broke handling of NULL objects in certain situations.
2019-01-18 21:21:06 +02:00
Slava Monich
dce9c8b3d1 Version 1.0.23 2019-01-15 15:17:47 +02:00
Slava Monich
b117ee6404 Merge pull request #25 from monich/buffer_obj
Add gbinder_reader_read_hidl_string_c()
2019-01-15 15:14:10 +02:00
Slava Monich
c3f783bf7e [gbinder] Added gbinder_reader_read_hidl_string_c(). JB#42956
It allows to fetch a pointer to the hidl string contents (which must
be NULL terminated) without duplicating the string and allocating any
memory in the process.

Added gbinder_reader_skip_hidl_string() macro.

Reduced number of memory allocations performed by functions parsing
buffer objects. Many of them don't allocate any memory at all now.
2019-01-15 14:44:25 +02:00
Slava Monich
4c65a6eded [licence] 2018 -> 2019 2019-01-15 01:48:50 +02:00
Slava Monich
c382cab922 [gbinder] Housekeeping
Fixed compilation warning:

gbinder_writer.c:223:9: warning: format ‘%d’ expects argument of type ‘int’,
but argument 4 has type ‘gsize’ [-Wformat=]

and a new other things.
2019-01-11 02:36:25 +03:00
Slava Monich
199fd4ed61 Version 1.0.22 2019-01-10 14:14:35 +03:00
Slava Monich
f86d62fbf8 Merge pull request #24 from monich/client_iface
Add gbinder_client_interface() function
2019-01-10 14:06:01 +03:00
Slava Monich
3ea82dc384 [gbinder] Added gbinder_client_interface(). JB#42956 2019-01-10 12:55:57 +03:00
Slava Monich
03ae5834ee [gbinder] Made warning message more informative. JB#42956 2019-01-10 12:46:23 +03:00
Slava Monich
e39b5c20ee [gbinder] Housekeeping 2019-01-10 12:45:23 +03:00
Slava Monich
d6e131eb6e Version 1.0.21 2018-12-18 14:11:01 +02:00
Slava Monich
1c36b5f142 Acknowledge Andrew's contribution 2018-12-18 14:09:49 +02:00
Slava Monich
827bd0b59f Merge pull request #23 from mer-hybris/overwrite
Add gbinder_writer_bytes_written and gbinder_writer_overwrite_int32
2018-12-18 14:02:07 +02:00
Andrew Branson
2dab057652 [gbinder] Add gbinder_writer_bytes_written and gbinder_writer_overwrite_int32. JB#43524
Bundles require their prefix length value to be set after the rest of the bundle has been written. This needs to remember the buffer position before a dummy value is written, which it then overwrites with the real value afterwards.
2018-12-18 13:00:30 +01:00
Slava Monich
488fbc5b63 Version 1.0.20 2018-12-17 16:07:50 +02:00
Slava Monich
17f511d7a3 Merge pull request #22 from monich/block
Add API to block incoming requests
2018-12-17 16:04:49 +02:00
Slava Monich
63e633c0ec [test] Added option to test asynchronous completion 2018-12-17 15:46:28 +02:00
Slava Monich
f46448c236 [gbinder] Added API to block incoming requests. JB#43529
GBinderRemoteRequest can be marked as blocked by calling
gbinder_remote_request_block() and later completed with
gbinder_remote_request_complete()
2018-12-17 15:46:19 +02:00
Slava Monich
43023be32d [test] Fixed typo 2018-12-17 00:36:21 +02:00
Slava Monich
4811d51c5d Version 1.0.19 2018-12-14 16:40:31 +02:00
Slava Monich
821dabca3d Merge pull request #21 from monich/cleanup
GBinderWriter allocators and cleanup
2018-12-14 16:01:31 +02:00
Slava Monich
587f4ebb50 [gbinder] GBinderWriter allocators and cleanup. JB#42956
Memory allocated by these allocators will be deallocated together
with the rest of the data.
2018-12-13 15:05:44 +02:00
Slava Monich
0c0b25fcd1 Version 1.0.18 2018-12-10 13:21:53 +02:00
Slava Monich
bdf07d04d4 Merge pull request #20 from monich/fd
Support for file descriptors
2018-12-10 12:56:48 +02:00
Slava Monich
6936675eb9 [gbinder] Added binder-dump test. JB#42956
Similar to Android's dumpsys
2018-12-08 16:35:59 +02:00
Slava Monich
c39bf4b802 [gbinder] Support for file descriptors. JB#42956
gbinder_writer_append_fd() duplicates the descriptor and appends
the duplicate to the parcel. The caller may immediately close its
descriptor.

gbinder_reader_read_fd() fetches the descriptor from the parcel
without duplicating it. The descrriptor will be closed as soon as
the library has finished processing the request. Returns -1 on error.

gbinder_reader_read_dup_fd() fetches descriptor from the parcel
and dups it. The caller is responsible for closing the returned
descriptor. Returns -1 on failure.
2018-12-08 16:27:45 +02:00
Slava Monich
5a43b1b091 [gbinder] Allow GBinderClient without RPC header. JB#42956
Binder transactions don't necessarily have RPC header, for example
GBINDER_DUMP_TRANSACTION and such.
2018-12-08 13:40:44 +02:00
Slava Monich
3e039e033c [gbinder] Close descriptors associated with transactions. Fixes JB#44099
Those are coming as objects of type BINDER_TYPE_FD and the
receiving side has to close them.
2018-12-08 03:12:22 +02:00
Slava Monich
6a2af83ea3 [gbinder] Removed unused GBinderLocalRequest field 2018-12-07 17:09:37 +02:00
Slava Monich
5a12df240b [test] Fail unexpected binder-service transactions 2018-12-07 17:09:04 +02:00
Slava Monich
2ea7d91fc7 [build] Make libgbinder.pc depend on Makefile
It's Makefile which contains the version number which has to match
the one in libgbinder.pc
2018-12-07 16:45:56 +02:00
Slava Monich
d9903e7398 Version 1.0.17 2018-12-07 02:54:57 +02:00
Slava Monich
39b69f27ee Merge pull request #19 from monich/utf16
Reading and writing UTF-16 strings without any conversion
2018-12-07 02:52:12 +02:00
Slava Monich
31a1d19b4e [gbinder] Added gbinder_reader_read_nullable_string16_utf16(). JB#43524
This function allows to read UTF-16 strings from Java parcel as UTF-16,
without any conversion.

As a side effect, it also allows parsing strings containing embedded
NULL characters.
2018-12-06 21:50:08 +02:00
Slava Monich
f4a923c3dc [gbinder] Added gbinder_writer_append_string16_utf16(). JB#43524
This function allows to write UTF-16 strings to Java parcel
without converting UTF-16 to UTF-8 and then back to UTF-16.
As a side effect, it also allows writing strings containing
embedded NULL characters.

This function can be used for adding QString contents to the
request more efficiently.
2018-12-06 21:27:51 +02:00
Slava Monich
171ff7d1e4 Version 1.0.16 2018-12-06 19:06:18 +02:00
Slava Monich
5cfbf22b81 Merge pull request #18 from monich/reader_copy
Added gbinder_reader_copy()
2018-12-06 18:38:36 +02:00
Slava Monich
5a35ed5ea1 [gbinder] Added gbinder_reader_copy(). JB#42956
Even though it's just a straight memcpy at the moment.
Also, constified GBinderReader pointer where appropriate.

This allows passing const GBinderReader pointer as a parameter and
a) allow the callee to parse the payload and b) make sure that the
caller's reader doesn't get damaged (well, or at least warn the callee
that it's doing the wrong thing).
2018-12-06 16:35:30 +02:00
Slava Monich
1978359f15 Merge pull request #17 from monich/hidl_types
Added GBinderHidlVec and GBinderHidlString types
2018-12-06 14:55:36 +02:00
Slava Monich
fef6543f1a [gbinder] Added GBinderHidlVec and GBinderHidlString types. JB#42956
These basic HIDL types are often used as a part of a larger structure.
2018-12-05 20:10:36 +02:00
Slava Monich
b1a9200803 Version 1.0.15 2018-12-05 12:14:45 +02:00
Slava Monich
fada30868a Merge pull request #16 from monich/poll
Implement service polling for old servicemanager
2018-12-05 11:57:29 +02:00
Slava Monich
8414e9485f [unit] Added servicepoll test 2018-12-04 23:48:25 +02:00
Slava Monich
f6d8d485bc [gbinder] Implemented service polling. JB#43524
Old servicemanager protocol didn't implement registration
notifications. Those have to be implemented with polling.
Note that polling will be active as long as at least one
listener is registered, i.e. it's important to unregister
the listener when you don't need it.

The polling interval is 2 seconds.

It doesn't affect hwservicemanager implementation which relies
on notifications, no polling there.
2018-12-04 23:43:49 +02:00
Slava Monich
6ea0d6c631 [unit] Added test for HIDL_PING_TRANSACTION 2018-12-04 15:07:27 +02:00
Slava Monich
31c6c05c1e [unit] Added unit_servicemanager test 2018-12-04 13:31:18 +02:00
82 changed files with 8089 additions and 1061 deletions

View File

@@ -2,3 +2,4 @@ Slava Monich <slava.monich@jolla.com>
Matti Lehtimäki <matti.lehtimaki@gmail.com>
Franz-Josef Haider <franz.haider@jolla.com>
Juho Hämäläinen <juho.hamalainen@jolla.com>
Andrew Branson <andrew.branson@jolla.com>

10
LICENSE
View File

@@ -1,5 +1,5 @@
Copyright (C) 2018 Jolla Ltd.
Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
Copyright (C) 2018-2019 Jolla Ltd.
Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:
@@ -12,9 +12,9 @@ are met:
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Jolla Ltd nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
3. Neither the names of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

View File

@@ -2,7 +2,7 @@
.PHONY: clean all debug release test
.PHONY: print_debug_so print_release_so
.PHONY: print_debug_lib print_release_lib
.PHONY: print_debug_lib print_release_lib print_coverage_lib
.PHONY: print_debug_link print_release_link
.PHONY: print_debug_path print_release_path
@@ -24,7 +24,7 @@ all: debug release pkgconfig
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_RELEASE = 14
VERSION_RELEASE = 32
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
@@ -62,6 +62,8 @@ SRC = \
gbinder_remote_reply.c \
gbinder_remote_request.c \
gbinder_rpc_protocol.c \
gbinder_servicename.c \
gbinder_servicepoll.c \
gbinder_writer.c
SRC += \
@@ -247,7 +249,7 @@ $(COVERAGE_LIB): $(COVERAGE_OBJS)
$(AR) rc $@ $?
ranlib $@
$(PKGCONFIG): $(LIB_NAME).pc.in
$(PKGCONFIG): $(LIB_NAME).pc.in Makefile
sed -e 's/\[version\]/'$(PCVERSION)/g $< > $@
#

120
debian/changelog vendored
View File

@@ -1,3 +1,123 @@
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

4
debian/control vendored
View File

@@ -2,13 +2,13 @@ Source: libgbinder
Section: libs
Priority: optional
Maintainer: Slava Monich <slava.monich@jolla.com>
Build-Depends: debhelper (>= 7), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.34)
Build-Depends: debhelper (>= 7), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.35)
Standards-Version: 3.8.4
Package: libgbinder
Section: libs
Architecture: any
Depends: libglibutil (>= 1.0.34), ${shlibs:Depends}, ${misc:Depends}
Depends: libglibutil (>= 1.0.35), ${shlibs:Depends}, ${misc:Depends}
Description: Binder client library
Package: libgbinder-dev

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -44,6 +44,7 @@
#include "gbinder_remote_object.h"
#include "gbinder_remote_reply.h"
#include "gbinder_remote_request.h"
#include "gbinder_servicename.h"
#include "gbinder_servicemanager.h"
#include "gbinder_writer.h"

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -58,6 +58,10 @@ void
gbinder_client_unref(
GBinderClient* client);
const char*
gbinder_client_interface(
GBinderClient* client); /* since 1.0.22 */
GBinderLocalRequest*
gbinder_client_new_request(
GBinderClient* client);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -37,6 +37,14 @@
G_BEGIN_DECLS
GBinderLocalObject*
gbinder_local_object_new(
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc handler,
void* user_data) /* Since 1.0.30 */
G_GNUC_WARN_UNUSED_RESULT;
GBinderLocalObject*
gbinder_local_object_ref(
GBinderLocalObject* obj);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -53,7 +53,7 @@ struct gbinder_reader {
gboolean
gbinder_reader_at_end(
GBinderReader* reader);
const GBinderReader* reader);
gboolean
gbinder_reader_read_byte(
@@ -95,6 +95,15 @@ gbinder_reader_read_double(
GBinderReader* reader,
gdouble* value);
int
gbinder_reader_read_fd(
GBinderReader* reader); /* Since 1.0.18 */
int
gbinder_reader_read_dup_fd(
GBinderReader* reader) /* Since 1.0.18 */
G_GNUC_WARN_UNUSED_RESULT;
gboolean
gbinder_reader_read_nullable_object(
GBinderReader* reader,
@@ -116,7 +125,7 @@ gbinder_reader_read_buffer(
const void*
gbinder_reader_read_hidl_struct1(
GBinderReader* reader,
gsize size); /* since 1.0.9 */
gsize size); /* Since 1.0.9 */
#define gbinder_reader_read_hidl_struct(reader,type) \
((const type*)gbinder_reader_read_hidl_struct1(reader, sizeof(type)))
@@ -131,7 +140,7 @@ const void*
gbinder_reader_read_hidl_vec1(
GBinderReader* reader,
gsize* count,
guint expected_elemsize); /* since 1.0.9 */
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)))
@@ -143,6 +152,13 @@ gbinder_reader_read_hidl_string(
GBinderReader* reader)
G_GNUC_WARN_UNUSED_RESULT;
const char*
gbinder_reader_read_hidl_string_c(
GBinderReader* reader); /* Since 1.0.23 */
#define gbinder_reader_skip_hidl_string(reader) \
(gbinder_reader_read_hidl_string_c(reader) != NULL)
char**
gbinder_reader_read_hidl_string_vec(
GBinderReader* reader);
@@ -165,6 +181,17 @@ gbinder_reader_read_nullable_string16(
GBinderReader* reader,
char** out);
gboolean
gbinder_reader_read_nullable_string16_utf16(
GBinderReader* reader,
const gunichar2** out,
gsize* len); /* Since 1.0.17 */
const gunichar2*
gbinder_reader_read_string16_utf16(
GBinderReader* reader,
gsize* len); /* Since 1.0.26 */
gboolean
gbinder_reader_skip_string16(
GBinderReader* reader);
@@ -172,15 +199,20 @@ gbinder_reader_skip_string16(
const void*
gbinder_reader_read_byte_array(
GBinderReader* reader,
gsize* len); /* since 1.0.12 */
gsize* len); /* Since 1.0.12 */
gsize
gbinder_reader_bytes_read(
GBinderReader* reader);
const GBinderReader* reader);
gsize
gbinder_reader_bytes_remaining(
GBinderReader* reader);
const GBinderReader* reader);
void
gbinder_reader_copy(
GBinderReader* dest,
const GBinderReader* src); /* Since 1.0.16 */
G_END_DECLS

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -51,6 +51,10 @@ void
gbinder_remote_object_unref(
GBinderRemoteObject* obj);
GBinderIpc*
gbinder_remote_object_ipc(
GBinderRemoteObject* obj); /* Since 1.0.30 */
gboolean
gbinder_remote_object_is_dead(
GBinderRemoteObject* obj);

View File

@@ -67,6 +67,16 @@ gbinder_remote_request_copy_to_local(
GBinderRemoteRequest* req) /* since 1.0.6 */
G_GNUC_WARN_UNUSED_RESULT;
void
gbinder_remote_request_block(
GBinderRemoteRequest* req); /* Since 1.0.20 */
void
gbinder_remote_request_complete(
GBinderRemoteRequest* req,
GBinderLocalReply* reply,
int status); /* Since 1.0.20 */
/* Convenience function to decode requests with just one data item */
gboolean

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -37,6 +37,12 @@
G_BEGIN_DECLS
typedef
void
(*GBinderServiceManagerFunc)(
GBinderServiceManager* sm,
void* user_data);
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
* list, otherwise the caller will deallocate it. */
typedef
@@ -87,6 +93,13 @@ gbinder_servicemanager_new_local_object(
GBinderLocalTransactFunc handler,
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*
gbinder_servicemanager_ref(
GBinderServiceManager* sm);
@@ -95,6 +108,15 @@ void
gbinder_servicemanager_unref(
GBinderServiceManager* sm);
gboolean
gbinder_servicemanager_is_present(
GBinderServiceManager* sm); /* Since 1.0.25 */
gboolean
gbinder_servicemanager_wait(
GBinderServiceManager* sm,
long max_wait_ms); /* Since 1.0.25 */
gulong
gbinder_servicemanager_list(
GBinderServiceManager* sm,
@@ -137,6 +159,12 @@ gbinder_servicemanager_cancel(
GBinderServiceManager* sm,
gulong id);
gulong
gbinder_servicemanager_add_presence_handler(
GBinderServiceManager* sm,
GBinderServiceManagerFunc func,
void* user_data); /* Since 1.0.25 */
gulong
gbinder_servicemanager_add_registration_handler(
GBinderServiceManager* sm,
@@ -149,6 +177,15 @@ gbinder_servicemanager_remove_handler(
GBinderServiceManager* sm,
gulong id); /* Since 1.0.13 */
void
gbinder_servicemanager_remove_handlers(
GBinderServiceManager* sm,
gulong* ids,
guint count); /* Since 1.0.25 */
#define gbinder_servicemanager_remove_all_handlers(r,ids) \
gbinder_servicemanager_remove_handlers(sm, ids, G_N_ELEMENTS(ids))
G_END_DECLS
#endif /* GBINDER_SERVICEMANAGER_H */

View 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:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -61,6 +61,7 @@ G_BEGIN_DECLS
typedef struct gbinder_buffer GBinderBuffer;
typedef struct gbinder_client GBinderClient;
typedef struct gbinder_ipc GBinderIpc;
typedef struct gbinder_local_object GBinderLocalObject;
typedef struct gbinder_local_reply GBinderLocalReply;
typedef struct gbinder_local_request GBinderLocalRequest;
@@ -68,10 +69,35 @@ typedef struct gbinder_reader GBinderReader;
typedef struct gbinder_remote_object GBinderRemoteObject;
typedef struct gbinder_remote_reply GBinderRemoteReply;
typedef struct gbinder_remote_request GBinderRemoteRequest;
typedef struct gbinder_servicename GBinderServiceName;
typedef struct gbinder_servicemanager GBinderServiceManager;
typedef struct gbinder_writer GBinderWriter;
typedef struct gbinder_parent GBinderParent;
/* Basic HIDL types */
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
* by gbinder_remote_request_interface() the transaction code.

View File

@@ -86,6 +86,12 @@ gbinder_writer_append_string16_len(
const char* utf8,
gssize num_bytes);
void
gbinder_writer_append_string16_utf16(
GBinderWriter* writer,
const gunichar2* utf16,
gssize length); /* Since 1.0.17 */
void
gbinder_writer_append_string8(
GBinderWriter* writer,
@@ -108,6 +114,21 @@ gbinder_writer_append_bytes(
const void* data,
gsize size);
void
gbinder_writer_append_fd(
GBinderWriter* writer,
int fd); /* Since 1.0.18 */
gsize
gbinder_writer_bytes_written(
GBinderWriter* writer); /* since 1.0.21 */
void
gbinder_writer_overwrite_int32(
GBinderWriter* writer,
gsize offset,
gint32 value); /* since 1.0.21 */
guint
gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* writer,
@@ -151,10 +172,38 @@ gbinder_writer_append_remote_object(
void
gbinder_writer_append_byte_array(
GBinderWriter* self,
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
#endif /* GBINDER_WRITER_H */

View File

@@ -1,14 +1,14 @@
Name: libgbinder
Version: 1.0.14
Version: 1.0.32
Release: 0
Summary: Binder client library
Group: Development/Libraries
License: BSD
URL: https://github.com/mer-hybris/libgbinder
Source: %{name}-%{version}.tar.bz2
Requires: libglibutil >= 1.0.34
Requires: libglibutil >= 1.0.35
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libglibutil) >= 1.0.34
BuildRequires: pkgconfig(libglibutil) >= 1.0.35
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig

View File

@@ -36,54 +36,62 @@
#include <gutil_macros.h>
struct gbinder_buffer_memory {
struct gbinder_buffer_contents {
gint refcount;
void* buffer;
gsize size;
void** objects;
GBinderDriver* driver;
};
typedef struct gbinder_buffer_priv {
GBinderBuffer pub;
GBinderBufferMemory* memory;
GBinderBufferContents* contents;
} GBinderBufferPriv;
static inline GBinderBufferPriv* gbinder_buffer_cast(GBinderBuffer* buf)
{ return G_CAST(buf, GBinderBufferPriv, pub); }
/*==========================================================================*
* GBinderBufferMemory
* GBinderBufferContents
*==========================================================================*/
static
GBinderBufferMemory*
gbinder_buffer_memory_new(
GBinderBufferContents*
gbinder_buffer_contents_new(
GBinderDriver* driver,
void* buffer,
gsize size)
gsize size,
void** objects)
{
GBinderBufferMemory* self = g_slice_new0(GBinderBufferMemory);
GBinderBufferContents* self = g_slice_new0(GBinderBufferContents);
g_atomic_int_set(&self->refcount, 1);
self->buffer = buffer;
self->size = size;
self->objects = objects;
self->driver = gbinder_driver_ref(driver);
return self;
}
static
void
gbinder_buffer_memory_free(
GBinderBufferMemory* self)
gbinder_buffer_contents_free(
GBinderBufferContents* self)
{
if (self->objects) {
gbinder_driver_close_fds(self->driver, self->objects,
((guint8*)self->buffer) + self->size);
g_free(self->objects);
}
gbinder_driver_free_buffer(self->driver, self->buffer);
gbinder_driver_unref(self->driver);
g_slice_free(GBinderBufferMemory, self);
g_slice_free(GBinderBufferContents, self);
}
GBinderBufferMemory*
gbinder_buffer_memory_ref(
GBinderBufferMemory* self)
GBinderBufferContents*
gbinder_buffer_contents_ref(
GBinderBufferContents* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
@@ -93,13 +101,13 @@ gbinder_buffer_memory_ref(
}
void
gbinder_buffer_memory_unref(
GBinderBufferMemory* self)
gbinder_buffer_contents_unref(
GBinderBufferContents* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_buffer_memory_free(self);
gbinder_buffer_contents_free(self);
}
}
}
@@ -111,14 +119,14 @@ gbinder_buffer_memory_unref(
static
GBinderBuffer*
gbinder_buffer_alloc(
GBinderBufferMemory* memory,
GBinderBufferContents* contents,
void* data,
gsize size)
{
GBinderBufferPriv* priv = g_slice_new0(GBinderBufferPriv);
GBinderBuffer* self = &priv->pub;
priv->memory = memory;
priv->contents = contents;
self->data = data;
self->size = size;
return self;
@@ -131,7 +139,7 @@ gbinder_buffer_free(
if (G_LIKELY(self)) {
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
gbinder_buffer_memory_unref(priv->memory);
gbinder_buffer_contents_unref(priv->contents);
g_slice_free(GBinderBufferPriv, priv);
}
}
@@ -140,10 +148,12 @@ GBinderBuffer*
gbinder_buffer_new(
GBinderDriver* driver,
void* data,
gsize size)
gsize size,
void** objects)
{
return gbinder_buffer_alloc((driver && data) ?
gbinder_buffer_memory_new(driver, data, size) : NULL, data, size);
gbinder_buffer_contents_new(driver, data, size, objects) : NULL,
data, size);
}
GBinderBuffer*
@@ -153,7 +163,7 @@ gbinder_buffer_new_with_parent(
gsize size)
{
return gbinder_buffer_alloc(parent ?
gbinder_buffer_memory_ref(gbinder_buffer_memory(parent)) : NULL,
gbinder_buffer_contents_ref(gbinder_buffer_contents(parent)) : NULL,
data, size);
}
@@ -162,13 +172,13 @@ gbinder_buffer_data(
GBinderBuffer* self,
gsize* size)
{
GBinderBufferMemory* memory = gbinder_buffer_memory(self);
GBinderBufferContents* contents = gbinder_buffer_contents(self);
if (G_LIKELY(memory)) {
if (G_LIKELY(contents)) {
if (size) {
*size = memory->size;
*size = contents->size;
}
return memory->buffer;
return contents->buffer;
} else {
if (size) {
*size = 0;
@@ -184,8 +194,8 @@ gbinder_buffer_driver(
if (G_LIKELY(self)) {
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
if (priv->memory) {
return priv->memory->driver;
if (priv->contents) {
return priv->contents->driver;
}
}
return NULL;
@@ -200,11 +210,25 @@ gbinder_buffer_io(
return driver ? gbinder_driver_io(driver) : NULL;
}
GBinderBufferMemory*
gbinder_buffer_memory(
void**
gbinder_buffer_objects(
GBinderBuffer* self)
{
return G_LIKELY(self) ? gbinder_buffer_cast(self)->memory : NULL;
if (G_LIKELY(self)) {
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
if (priv->contents) {
return priv->contents->objects;
}
}
return NULL;
}
GBinderBufferContents*
gbinder_buffer_contents(
GBinderBuffer* self)
{
return G_LIKELY(self) ? gbinder_buffer_cast(self)->contents : NULL;
}
/*

View File

@@ -41,7 +41,8 @@ GBinderBuffer*
gbinder_buffer_new(
GBinderDriver* driver,
void* data,
gsize size);
gsize size,
void** objects);
GBinderBuffer*
gbinder_buffer_new_with_parent(
@@ -53,8 +54,8 @@ GBinderDriver*
gbinder_buffer_driver(
GBinderBuffer* buf);
GBinderBufferMemory*
gbinder_buffer_memory(
GBinderBufferContents*
gbinder_buffer_contents(
GBinderBuffer* buf);
gconstpointer
@@ -66,13 +67,17 @@ const GBinderIo*
gbinder_buffer_io(
GBinderBuffer* buf);
GBinderBufferMemory*
gbinder_buffer_memory_ref(
GBinderBufferMemory* mem);
void**
gbinder_buffer_objects(
GBinderBuffer* buffer);
GBinderBufferContents*
gbinder_buffer_contents_ref(
GBinderBufferContents* contents);
void
gbinder_buffer_memory_unref(
GBinderBufferMemory* mem);
gbinder_buffer_contents_unref(
GBinderBufferContents* contents);
#endif /* GBINDER_BUFFER_PRIVATE_H */

View File

@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -48,11 +48,33 @@ struct gbinder_cleanup {
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
static
void
gbinder_cleanup_destroy_func(
gpointer data)
{
GBinderCleanupItem* item = data;
item->destroy(item->pointer);
}
static
GBinderCleanup*
gbinder_cleanup_new()
{
return (GBinderCleanup*)g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
GArray* array = g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
g_array_set_clear_func(array, gbinder_cleanup_destroy_func);
return (GBinderCleanup*)array;
}
void
gbinder_cleanup_reset(
GBinderCleanup* self)
{
if (G_LIKELY(self)) {
g_array_set_size((GArray*)self, 0);
}
}
void
@@ -60,11 +82,6 @@ gbinder_cleanup_free(
GBinderCleanup* self)
{
if (G_LIKELY(self)) {
guint i;
for (i = 0; i < self->count; i++) {
self->items[i].destroy(self->items[i].pointer);
}
g_array_free((GArray*)self, TRUE);
}
}

View File

@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -39,6 +39,10 @@ void
gbinder_cleanup_free(
GBinderCleanup* cleanup);
void
gbinder_cleanup_reset(
GBinderCleanup* cleanup);
GBinderCleanup*
gbinder_cleanup_add(
GBinderCleanup* cleanup,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -75,7 +75,9 @@ gbinder_client_free(
gbinder_remote_object_unref(self->remote);
gbinder_local_request_unref(priv->basic_req);
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);
}
@@ -117,13 +119,13 @@ gbinder_client_new(
GBinderRemoteObject* remote,
const char* iface)
{
if (G_LIKELY(remote) && G_LIKELY(iface)) {
if (G_LIKELY(remote)) {
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
GBinderClient* self = &priv->pub;
GBinderIpc* ipc = remote->ipc;
GBinderOutputData* hdr;
GBinderDriver* driver = remote->ipc->driver;
g_atomic_int_set(&priv->refcount, 1);
self->remote = gbinder_remote_object_ref(remote);
/*
* Generate basic request (without additional parameters) and pull
@@ -131,12 +133,17 @@ gbinder_client_new(
* transactions which has no additional parameters. The header data
* are needed for building non-trivial requests.
*/
priv->basic_req = gbinder_driver_local_request_new(ipc->driver, iface);
hdr = gbinder_local_request_data(priv->basic_req);
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
if (iface) {
GBinderOutputData* hdr;
self->remote = gbinder_remote_object_ref(remote);
self->iface = priv->iface = g_strdup(iface);
priv->basic_req = gbinder_driver_local_request_new(driver, iface);
hdr = gbinder_local_request_data(priv->basic_req);
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
self->iface = priv->iface = g_strdup(iface);
} else {
priv->basic_req = gbinder_local_request_new
(gbinder_driver_io(driver), NULL);
}
return self;
}
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*
gbinder_client_new_request(
GBinderClient* self)
@@ -191,12 +205,15 @@ gbinder_client_transact_sync_reply(
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
if (G_LIKELY(!obj->dead)) {
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
}
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
code, req, status);
}
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
code, req, status);
GDEBUG("Refusing to perform transaction with a dead object");
}
return NULL;
}
@@ -210,15 +227,18 @@ gbinder_client_transact_sync_oneway(
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
if (G_LIKELY(!obj->dead)) {
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
}
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
code, req);
}
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
code, req);
} else {
return (-EINVAL);
GDEBUG("Refusing to perform transaction with a dead object");
return (-ESTALE);
}
return (-EINVAL);
}
gulong
@@ -233,23 +253,27 @@ gbinder_client_transact(
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
tx->client = gbinder_client_ref(self);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
if (G_LIKELY(!obj->dead)) {
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
tx->client = gbinder_client_ref(self);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
}
return gbinder_ipc_transact(obj->ipc, obj->handle, code,
flags, req, gbinder_client_transact_reply,
gbinder_client_transact_destroy, tx);
}
return gbinder_ipc_transact(obj->ipc, obj->handle, code, flags, req,
gbinder_client_transact_reply, gbinder_client_transact_destroy, tx);
} else {
return 0;
GDEBUG("Refusing to perform transaction with a dead object");
}
return 0;
}
void

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -32,6 +32,7 @@
#include "gbinder_servicemanager_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_servicepoll.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
@@ -43,13 +44,31 @@
#include <errno.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 struct gbinder_defaultservicemanager {
GBinderServiceManager manager;
GBinderServicePoll* poll;
GHashTable* watch_table;
} GBinderDefaultServiceManager;
G_DEFINE_TYPE(GBinderDefaultServiceManager,
gbinder_defaultservicemanager,
GBINDER_TYPE_SERVICEMANAGER)
#define PARENT_CLASS gbinder_defaultservicemanager_parent_class
#define GBINDER_TYPE_DEFAULTSERVICEMANAGER \
gbinder_defaultservicemanager_get_type()
#define GBINDER_DEFAULTSERVICEMANAGER(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_DEFAULTSERVICEMANAGER, \
GBinderDefaultServiceManager)
enum gbinder_defaultservicemanager_calls {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
@@ -57,8 +76,6 @@ enum gbinder_defaultservicemanager_calls {
LIST_SERVICES_TRANSACTION
};
/* As a special case, ServiceManager's handle is zero */
#define DEFAULTSERVICEMANAGER_HANDLE (0)
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager"
GBinderServiceManager*
@@ -66,7 +83,76 @@ gbinder_defaultservicemanager_new(
const char* dev)
{
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
@@ -157,9 +243,35 @@ gbinder_defaultservicemanager_check_name(
GBinderServiceManager* self,
const char* name)
{
/* Old servicemanager doesn't support notifications, those would
* have to be emulated with polling. Is it necessary though? */
return GBINDER_SERVICEMANAGER_NAME_INVALID;
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
@@ -167,6 +279,19 @@ void
gbinder_defaultservicemanager_init(
GBinderDefaultServiceManager* self)
{
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, gbinder_defaultservicemanager_watch_free);
}
static
void
gbinder_defaultservicemanager_finalize(
GObject* object)
{
GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(object);
g_hash_table_destroy(self->watch_table);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
@@ -174,7 +299,6 @@ void
gbinder_defaultservicemanager_class_init(
GBinderDefaultServiceManagerClass* klass)
{
klass->handle = DEFAULTSERVICEMANAGER_HANDLE;
klass->iface = DEFAULTSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;
@@ -183,7 +307,10 @@ gbinder_defaultservicemanager_class_init(
klass->get_service = gbinder_defaultservicemanager_get_service;
klass->add_service = gbinder_defaultservicemanager_add_service;
klass->check_name = gbinder_defaultservicemanager_check_name;
/* No need for other watch callbacks */
/* normalize_name is not needed */
klass->watch = gbinder_defaultservicemanager_watch;
klass->unwatch = gbinder_defaultservicemanager_unwatch;
G_OBJECT_CLASS(klass)->finalize = gbinder_defaultservicemanager_finalize;
}
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -288,19 +288,15 @@ gbinder_driver_death_notification(
guint32 cmd,
GBinderRemoteObject* obj)
{
if (G_LIKELY(obj)) {
GBinderIoBuf write;
guint8 buf[4 + GBINDER_MAX_DEATH_NOTIFICATION_SIZE];
guint32* data = (guint32*)buf;
GBinderIoBuf write;
guint8 buf[4 + GBINDER_MAX_DEATH_NOTIFICATION_SIZE];
guint32* data = (guint32*)buf;
data[0] = cmd;
memset(&write, 0, sizeof(write));
write.ptr = (uintptr_t)buf;
write.size = 4 + self->io->encode_death_notification(data + 1, obj);
return gbinder_driver_write(self, &write) >= 0;
}
return FALSE;
data[0] = cmd;
memset(&write, 0, sizeof(write));
write.ptr = (uintptr_t)buf;
write.size = 4 + self->io->encode_death_notification(data + 1, obj);
return gbinder_driver_write(self, &write) >= 0;
}
static
@@ -439,11 +435,10 @@ gbinder_driver_handle_transaction(
/* Transfer data ownership to the request */
if (tx.data && tx.size) {
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
gbinder_remote_request_set_data(req,
gbinder_buffer_new(self, tx.data, tx.size),
tx.objects);
gbinder_remote_request_set_data(req, tx.code,
gbinder_buffer_new(self, tx.data, tx.size, tx.objects));
} else {
g_free(tx.objects);
GASSERT(!tx.objects);
gbinder_driver_free_buffer(self, tx.data);
}
@@ -459,7 +454,7 @@ gbinder_driver_handle_transaction(
&status);
break;
default:
GWARN("Unhandled transaction 0x%08x", tx.code);
GWARN("Unhandled transaction %s 0x%08x", iface, tx.code);
break;
}
@@ -536,6 +531,7 @@ gbinder_driver_handle_command(
} else if (cmd == io->br.transaction) {
gbinder_driver_handle_transaction(self, reg, handler, data);
} else if (cmd == io->br.dead_binder) {
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
guint64 handle = 0;
GBinderRemoteObject* obj;
@@ -546,6 +542,8 @@ gbinder_driver_handle_command(
gbinder_remote_object_handle_death_notification(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) {
GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE");
} else {
@@ -637,10 +635,9 @@ gbinder_driver_txstatus(
if (tx.data && tx.size) {
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
gbinder_remote_reply_set_data(reply,
gbinder_buffer_new(self, tx.data, tx.size),
tx.objects);
gbinder_buffer_new(self, tx.data, tx.size, tx.objects));
} else {
g_free(tx.objects);
GASSERT(!tx.objects);
gbinder_driver_free_buffer(self, tx.data);
}
@@ -814,8 +811,13 @@ gbinder_driver_request_death_notification(
GBinderDriver* self,
GBinderRemoteObject* obj)
{
return gbinder_driver_death_notification
(self, self->io->bc.request_death_notification, obj);
if (G_LIKELY(obj)) {
GVERBOSE("< BC_REQUEST_DEATH_NOTIFICATION 0x%08x", obj->handle);
return gbinder_driver_death_notification(self,
self->io->bc.request_death_notification, obj);
} else {
return FALSE;
}
}
gboolean
@@ -823,8 +825,13 @@ gbinder_driver_clear_death_notification(
GBinderDriver* self,
GBinderRemoteObject* obj)
{
return gbinder_driver_death_notification
(self, self->io->bc.clear_death_notification, obj);
if (G_LIKELY(obj)) {
GVERBOSE("< BC_CLEAR_DEATH_NOTIFICATION 0x%08x", obj->handle);
return gbinder_driver_death_notification(self,
self->io->bc.clear_death_notification, obj);
} else {
return FALSE;
}
}
gboolean
@@ -863,6 +870,32 @@ gbinder_driver_release(
return gbinder_driver_cmd_int32(self, self->io->bc.release, handle);
}
void
gbinder_driver_close_fds(
GBinderDriver* self,
void** objects,
const void* end)
{
const GBinderIo* io = self->io;
void** ptr;
/* Caller checks objects for NULL */
for (ptr = objects; *ptr; ptr++) {
void* obj = *ptr;
GASSERT(obj < end);
if (obj < end) {
int fd;
if (io->decode_fd_object(obj, (guint8*)end - (guint8*)obj, &fd)) {
if (close(fd) < 0) {
GWARN("Error closing fd %d: %s", fd, strerror(errno));
}
}
}
}
}
void
gbinder_driver_free_buffer(
GBinderDriver* self,
@@ -1014,6 +1047,28 @@ gbinder_driver_transact(
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*
gbinder_driver_local_request_new(
GBinderDriver* self,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -97,6 +97,12 @@ gbinder_driver_release(
GBinderDriver* driver,
guint32 handle);
void
gbinder_driver_close_fds(
GBinderDriver* self,
void** objects,
const void* end);
void
gbinder_driver_free_buffer(
GBinderDriver* driver,
@@ -125,6 +131,12 @@ gbinder_driver_transact(
GBinderLocalRequest* request,
GBinderRemoteReply* reply);
int
gbinder_driver_ping(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
guint32 handle);
GBinderLocalRequest*
gbinder_driver_local_request_new(
GBinderDriver* self,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -80,8 +80,6 @@ enum gbinder_hwservicemanager_notifications {
ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION
};
/* As a special case, ServiceManager's handle is zero */
#define HWSERVICEMANAGER_HANDLE (0)
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
#define HWSERVICEMANAGER_NOTIFICATION_IFACE \
"android.hidl.manager@1.0::IServiceNotification"
@@ -378,7 +376,6 @@ void
gbinder_hwservicemanager_class_init(
GBinderHwServiceManagerClass* klass)
{
klass->handle = HWSERVICEMANAGER_HANDLE;
klass->iface = HWSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -128,9 +128,13 @@ GBINDER_IO_FN(encode_local_object)(
struct flat_binder_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = obj ? BINDER_TYPE_BINDER : BINDER_TYPE_WEAK_HANDLE;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
if (obj) {
dest->hdr.type = BINDER_TYPE_BINDER;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
} else {
dest->hdr.type = BINDER_TYPE_WEAK_BINDER;
}
return sizeof(*dest);
}
@@ -153,6 +157,21 @@ GBINDER_IO_FN(encode_remote_object)(
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 */
static
guint
@@ -394,7 +413,7 @@ guint
GBINDER_IO_FN(decode_buffer_object)(
GBinderBuffer* buf,
gsize offset,
GBinderBuffer** out)
GBinderIoBufferObject* out)
{
const void* data = (guint8*)buf->data + offset;
const gsize size = (offset < buf->size) ? (buf->size - offset) : 0;
@@ -402,12 +421,36 @@ GBINDER_IO_FN(decode_buffer_object)(
if (size >= sizeof(*flat) && flat->hdr.type == BINDER_TYPE_PTR) {
if (out) {
*out = gbinder_buffer_new_with_parent(buf,
(void*)(uintptr_t)flat->buffer, flat->length);
out->data = (void*)(uintptr_t)flat->buffer;
out->size = (gsize)flat->length;
out->parent_offset = (gsize)flat->parent_offset;
out->has_parent = (flat->flags & BINDER_BUFFER_FLAG_HAS_PARENT) ?
TRUE : FALSE;
}
return sizeof(*flat);
}
if (out) *out = NULL;
return 0;
}
static
guint
GBINDER_IO_FN(decode_fd_object)(
const void* data,
gsize size,
int* fd)
{
const struct flat_binder_object* obj = data;
if (size >= sizeof(*obj)) {
switch (obj->hdr.type) {
case BINDER_TYPE_FD:
if (fd) *fd = obj->handle;
return sizeof(*obj);
default:
break;
}
}
if (fd) *fd = -1;
return 0;
}
@@ -466,6 +509,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
.encode_pointer = GBINDER_IO_FN(encode_pointer),
.encode_local_object = GBINDER_IO_FN(encode_local_object),
.encode_remote_object = GBINDER_IO_FN(encode_remote_object),
.encode_fd_object = GBINDER_IO_FN(encode_fd_object),
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
.encode_transaction = GBINDER_IO_FN(encode_transaction),
@@ -478,6 +522,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
.decode_binder_ptr_cookie = GBINDER_IO_FN(decode_binder_ptr_cookie),
.decode_binder_object = GBINDER_IO_FN(decode_binder_object),
.decode_buffer_object = GBINDER_IO_FN(decode_buffer_object),
.decode_fd_object = GBINDER_IO_FN(decode_fd_object),
/* ioctl wrappers */
.write_read = GBINDER_IO_FN(write_read)

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -43,6 +43,13 @@ typedef struct gbinder_io_buf {
gsize consumed;
} GBinderIoBuf;
typedef struct gbinder_io_buffer_object {
void* data;
gsize size;
gsize parent_offset;
gboolean has_parent;
} GBinderIoBufferObject;
typedef struct gbinder_io_tx_data {
int status;
guint32 code;
@@ -131,6 +138,7 @@ struct gbinder_io {
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
guint (*encode_fd_object)(void* out, int fd);
/* Encode binder_buffer_object */
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
@@ -164,9 +172,10 @@ struct gbinder_io {
void* (*decode_binder_ptr_cookie)(const void* data);
guint (*decode_cookie)(const void* data, guint64* cookie);
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,
GBinderBuffer** out);
GBinderIoBufferObject* out);
guint (*decode_fd_object)(const void* data, gsize size, int* fd);
/* ioctl wrappers */
int (*write_read)(int fd, GBinderIoBuf* write, GBinderIoBuf* read);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -68,9 +68,9 @@ struct gbinder_ipc_priv {
GMutex local_objects_mutex;
GHashTable* local_objects;
/* We may need more loopers... But let's start with just one */
GMutex looper_mutex;
GBinderIpcLooper* looper;
GBinderIpcLooper* primary_loopers;
GBinderIpcLooper* blocked_loopers;
};
typedef GObjectClass GBinderIpcClass;
@@ -100,7 +100,7 @@ static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
* When the main thread receives GBinderIpcLooperTx:
*
* 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
*
* When tx pipe wakes up the looper:
@@ -111,11 +111,26 @@ static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
* Note that GBinderIpcLooperTx can be deallocated on either looper or
* main thread, depending on whether looper gives up on the transaction
* 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_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 */
gint refcount;
/* These are filled by the looper: */
@@ -125,19 +140,23 @@ typedef struct gbinder_ipc_looper_tx {
GBinderLocalObject* obj;
GBinderRemoteRequest* req;
/* And these by the main thread processing the transaction: */
GBINDER_IPC_LOOPER_TX_STATE state;
GBinderLocalReply* reply;
int status;
} GBinderIpcLooperTx;
} /* GBinderIpcLooperTx */;
struct gbinder_ipc_looper {
gint refcount;
GBinderIpcLooper* next;
char* name;
GBinderHandler handler;
GBinderDriver* driver;
GBinderIpc* ipc; /* Not a reference! */
GThread* thread;
GMutex mutex;
GCond start_cond;
gboolean started;
gint exit;
gint started;
int pipefd[2];
int txfd[2];
};
@@ -178,6 +197,11 @@ typedef struct gbinder_ipc_tx_custom {
GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self)
{ return gbinder_driver_dev(self->driver); }
static
GBinderIpcLooper*
gbinder_ipc_looper_new(
GBinderIpc* ipc);
/*==========================================================================*
* GBinderIpcLooperTx
*==========================================================================*/
@@ -245,6 +269,91 @@ gbinder_ipc_looper_tx_unref(
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
*==========================================================================*/
@@ -255,11 +364,70 @@ gbinder_ipc_looper_tx_handle(
gpointer 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 */
tx->reply = gbinder_local_object_handle_transaction(tx->obj, tx->req,
tx->code, tx->flags, &tx->status);
reply = gbinder_local_object_handle_transaction(tx->obj, req,
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 */
(void)write(tx->pipefd[1], &done, sizeof(done));
@@ -274,6 +442,52 @@ gbinder_ipc_looper_tx_done(
gbinder_ipc_looper_tx_unref(data, FALSE);
}
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
GBinderLocalReply*
gbinder_ipc_looper_transact(
@@ -318,11 +532,65 @@ gbinder_ipc_looper_transact(
if ((fds[1].revents & POLLIN) &&
read(fds[1].fd, &done, sizeof(done)) == 1) {
/* Normal completion */
if (done == TX_BLOCKED) {
/*
* We are going to block this looper for potentially
* significant period of time. Start new looper to
* accept normal incoming requests and terminate this
* one when we are done with this transaction.
*
* For the duration of the transaction, this looper is
* moved to the blocked_loopers list.
*/
GBinderIpcPriv* priv = looper->ipc->priv;
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (gbinder_ipc_looper_remove_primary(looper)) {
GBinderIpcLooper* new_looper;
GDEBUG("Primary looper %s is blocked", looper->name);
looper->next = priv->blocked_loopers;
priv->blocked_loopers = looper;
/* Looper will exit once transaction completes */
g_atomic_int_set(&looper->exit, 1);
/* Create new primary looper to replace this one */
new_looper = gbinder_ipc_looper_new(ipc);
if (new_looper) {
new_looper->next = priv->primary_loopers;
priv->primary_loopers = new_looper;
}
}
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
/* 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) {
GASSERT(done == TX_DONE);
}
}
}
if (done) {
GASSERT(done == TX_DONE);
reply = gbinder_local_reply_ref(tx->reply);
status = tx->status;
if (!gbinder_ipc_looper_tx_unref(tx, TRUE)) {
/* 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;
}
} else {
@@ -348,6 +616,7 @@ gbinder_ipc_looper_free(
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);
@@ -384,11 +653,11 @@ gbinder_ipc_looper_thread(
if (gbinder_driver_enter_looper(driver)) {
struct pollfd pipefd;
int result;
int res;
GDEBUG("Looper %s running", gbinder_driver_dev(driver));
GDEBUG("Looper %s running", looper->name);
g_mutex_lock(&looper->mutex);
looper->started = TRUE;
g_atomic_int_set(&looper->started, TRUE);
g_cond_broadcast(&looper->start_cond);
g_mutex_unlock(&looper->mutex);
@@ -396,31 +665,33 @@ gbinder_ipc_looper_thread(
pipefd.fd = looper->pipefd[0]; /* read end of the pipe */
pipefd.events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
result = gbinder_driver_poll(driver, &pipefd);
while (looper->ipc && ((result & POLLIN) || !result)) {
if (result & POLLIN) {
/* No need to synchronize access to looper->ipc because
res = gbinder_driver_poll(driver, &pipefd);
while (!g_atomic_int_get(&looper->exit) && ((res & POLLIN) || !res)) {
if (res & POLLIN) {
/*
* No need to synchronize access to looper->ipc because
* 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);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
/* But that gbinder_driver_read() may unref GBinderIpc */
int ret = gbinder_driver_read(driver, reg, &looper->handler);
/* And this gbinder_ipc_unref() may release the last ref: */
gbinder_ipc_unref(ipc);
/* And at this point looper->ipc may be NULL */
if (ret < 0) {
GDEBUG("Looper %s failed", gbinder_driver_dev(driver));
GDEBUG("Looper %s failed", looper->name);
break;
}
}
if (pipefd.revents) {
/* Any event from this pipe terminates the loop */
GDEBUG("Looper %s is asked to exit",
gbinder_driver_dev(driver));
/* Any event from this pipe terminates the loop */
if (pipefd.revents || g_atomic_int_get(&looper->exit)) {
GDEBUG("Looper %s is requested to exit", looper->name);
break;
}
result = gbinder_driver_poll(driver, &pipefd);
res = gbinder_driver_poll(driver, &pipefd);
}
gbinder_driver_exit_looper(driver);
@@ -432,24 +703,26 @@ gbinder_ipc_looper_thread(
*/
if (looper->ipc) {
GBinderIpcPriv* priv = looper->ipc->priv;
/* Lock */
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 */
priv->looper = NULL;
GDEBUG("Looper %s exits", gbinder_driver_dev(driver));
GDEBUG("Looper %s exits", looper->name);
gbinder_ipc_looper_unref(looper);
} else {
/* 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);
/* Unlock */
} else {
GDEBUG("Looper %s is abandoned", gbinder_driver_dev(driver));
GDEBUG("Looper %s is abandoned", looper->name);
}
} else {
g_mutex_lock(&looper->mutex);
looper->started = TRUE;
g_atomic_int_set(&looper->started, TRUE);
g_cond_broadcast(&looper->start_cond);
g_mutex_unlock(&looper->mutex);
}
@@ -472,20 +745,24 @@ gbinder_ipc_looper_new(
};
GError* error = NULL;
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));
looper->txfd[0] = looper->txfd[1] = -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->ipc = ipc;
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);
if (looper->thread) {
/* gbinder_ipc_looper_thread() will release this reference: */
gbinder_ipc_looper_ref(looper);
GDEBUG("Starting looper %s", looper->name);
return looper;
} else {
GERR("Failed to create looper thread: %s", GERRMSG(error));
@@ -505,29 +782,29 @@ gbinder_ipc_looper_check(
if (G_LIKELY(self)) {
GBinderIpcPriv* priv = self->priv;
if (!priv->looper) {
if (!priv->primary_loopers) {
GBinderIpcLooper* looper;
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (!priv->looper) {
GDEBUG("Starting looper %s", gbinder_ipc_name(self));
priv->looper = gbinder_ipc_looper_new(self);
looper = priv->primary_loopers;
if (!looper) {
looper = priv->primary_loopers = gbinder_ipc_looper_new(self);
}
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
/* We are not ready to accept incoming transactions until
* looper has started. We may need to wait a bit. */
looper = priv->looper;
if (!looper->started) {
if (looper && !g_atomic_int_get(&looper->started)) {
/* Lock */
g_mutex_lock(&looper->mutex);
if (!looper->started) {
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(looper->started);
GASSERT(g_atomic_int_get(&looper->started));
}
g_mutex_unlock(&looper->mutex);
/* Unlock */
@@ -536,12 +813,91 @@ gbinder_ipc_looper_check(
}
}
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
*==========================================================================*/
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.
*
* Note the following scenario (where object may be either local or remote):
@@ -589,31 +945,19 @@ gbinder_ipc_remote_object_disposed(
/* Lock */
g_mutex_lock(&priv->remote_objects_mutex);
if (obj->object.ref_count == 1 && priv->remote_objects) {
void* key = GINT_TO_POINTER(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;
}
if (obj->object.ref_count == 1) {
gbinder_ipc_invalidate_remote_handle_locked(priv, obj->handle);
}
g_mutex_unlock(&priv->remote_objects_mutex);
/* Unlock */
}
GBinderLocalObject*
gbinder_ipc_new_local_object(
void
gbinder_ipc_register_local_object(
GBinderIpc* self,
const char* iface,
GBinderLocalTransactFunc txproc,
void* data)
GBinderLocalObject* obj)
{
GBinderIpcPriv* priv = self->priv;
GBinderLocalObject* obj = gbinder_local_object_new
(self, iface, txproc, data);
/* Lock */
g_mutex_lock(&priv->local_objects_mutex);
@@ -626,7 +970,6 @@ gbinder_ipc_new_local_object(
GVERBOSE_("%p", obj);
gbinder_ipc_looper_check(self);
return obj;
}
static
@@ -661,7 +1004,8 @@ static
GBinderRemoteObject*
gbinder_ipc_priv_get_remote_object(
GBinderIpcPriv* priv,
guint32 handle)
guint32 handle,
gboolean maybe_dead)
{
GBinderRemoteObject* obj = NULL;
void* key = GINT_TO_POINTER(handle);
@@ -674,7 +1018,11 @@ gbinder_ipc_priv_get_remote_object(
if (obj) {
gbinder_remote_object_ref(obj);
} 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) {
priv->remote_objects = g_hash_table_new
(g_direct_hash, g_direct_equal);
@@ -690,10 +1038,11 @@ gbinder_ipc_priv_get_remote_object(
GBinderRemoteObject*
gbinder_ipc_get_remote_object(
GBinderIpc* self,
guint32 handle)
guint32 handle,
gboolean maybe_dead)
{
/* 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
@@ -745,7 +1094,7 @@ gbinder_ipc_object_registry_get_remote(
guint32 handle)
{
return gbinder_ipc_priv_get_remote_object
(gbinder_ipc_priv_from_object_registry(reg), handle);
(gbinder_ipc_priv_from_object_registry(reg), handle, FALSE);
}
/*==========================================================================*
@@ -839,14 +1188,19 @@ gbinder_ipc_tx_internal_exec(
GBinderObjectRegistry* reg = &self->priv->object_registry;
/* Perform synchronous transaction */
tx->reply = gbinder_remote_reply_new(&self->priv->object_registry);
tx->status = gbinder_driver_transact(self->driver, reg,
tx->handle, tx->code, tx->req, tx->reply);
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;
if (tx->flags & GBINDER_TX_FLAG_ONEWAY) {
tx->status = gbinder_driver_transact(self->driver, reg, tx->handle,
tx->code, tx->req, NULL);
} else {
tx->reply = gbinder_remote_reply_new(&self->priv->object_registry);
tx->status = gbinder_driver_transact(self->driver, reg, tx->handle,
tx->code, tx->req, tx->reply);
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;
}
}
}
@@ -1232,7 +1586,7 @@ gbinder_ipc_dispose(
{
GBinderIpc* self = GBINDER_IPC(object);
GBinderIpcPriv* priv = self->priv;
GBinderIpcLooper* looper;
GBinderIpcLooper* loopers = NULL;
GVERBOSE_("%s", self->dev);
/* Lock */
@@ -1253,22 +1607,19 @@ gbinder_ipc_dispose(
/* Lock */
g_mutex_lock(&priv->looper_mutex);
looper = priv->looper;
priv->looper = NULL;
loopers = gbinder_ipc_looper_stop_all(loopers, priv->primary_loopers);
loopers = gbinder_ipc_looper_stop_all(loopers, priv->blocked_loopers);
priv->blocked_loopers = NULL;
priv->primary_loopers = NULL;
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
if (looper) {
if (looper->thread && looper->thread != g_thread_self()) {
guint8 done = TX_DONE;
while (loopers) {
GBinderIpcLooper* looper = loopers;
GDEBUG("Stopping looper %s", gbinder_ipc_name(looper->ipc));
if (write(looper->pipefd[1], &done, sizeof(done)) > 0) {
g_thread_join(looper->thread);
looper->thread = NULL;
}
}
looper->ipc = NULL;
loopers = looper->next;
looper->next = NULL;
gbinder_ipc_looper_join(looper);
gbinder_ipc_looper_unref(looper);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -89,15 +89,19 @@ GBinderObjectRegistry*
gbinder_ipc_object_registry(
GBinderIpc* ipc);
GBinderLocalObject*
gbinder_ipc_new_local_object(
void
gbinder_ipc_register_local_object(
GBinderIpc* ipc,
const char* iface,
GBinderLocalTransactFunc txproc,
void* data);
GBinderLocalObject* obj);
GBinderRemoteObject*
gbinder_ipc_get_remote_object(
GBinderIpc* ipc,
guint32 handle,
gboolean maybe_dead);
void
gbinder_ipc_invalidate_remote_handle(
GBinderIpc* ipc,
guint32 handle);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -38,11 +38,13 @@
#include "gbinder_writer.h"
#include "gbinder_log.h"
#include <gutil_strv.h>
#include <errno.h>
struct gbinder_local_object_priv {
GMainContext* context;
char* iface;
char** ifaces;
GBinderLocalTransactFunc txproc;
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, \
GBinderLocalObjectClass)
typedef
GBinderLocalReply*
(*GBinderLocalObjectTxHandler)(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
int* status);
enum gbinder_local_object_signal {
SIGNAL_WEAK_REFS_CHANGED,
SIGNAL_STRONG_REFS_CHANGED,
@@ -78,6 +87,9 @@ gbinder_local_object_default_can_handle_transaction(
guint code)
{
switch (code) {
case GBINDER_PING_TRANSACTION:
case GBINDER_INTERFACE_TRANSACTION:
return GBINDER_LOCAL_TRANSACTION_LOOPER;
case HIDL_PING_TRANSACTION:
case HIDL_GET_DESCRIPTOR_TRANSACTION:
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
@@ -110,6 +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
GBinderLocalReply*
gbinder_local_object_hidl_ping_transaction(
@@ -120,12 +165,10 @@ gbinder_local_object_hidl_ping_transaction(
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
GVERBOSE(" HIDL_PING_TRANSACTION \"%s\"",
gbinder_remote_request_interface(req));
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -139,6 +182,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
{
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalObjectPriv* priv = self->priv;
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
@@ -146,8 +190,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
gbinder_remote_request_interface(req));
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_hidl_string(&writer, self->iface ? self->iface :
hidl_base_interface);
gbinder_writer_append_hidl_string(&writer, priv->ifaces[0]);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -163,17 +206,14 @@ gbinder_local_object_hidl_descriptor_chain_transaction(
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
const char* chain[2];
int n = 0;
GVERBOSE(" HIDL_DESCRIPTOR_CHAIN_TRANSACTION \"%s\"",
gbinder_remote_request_interface(req));
if (self->iface) chain[n++] = self->iface;
chain[n++] = hidl_base_interface;
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_hidl_string_vec(&writer, chain, n);
gbinder_writer_append_hidl_string_vec(&writer, (const char**)
self->ifaces, -1);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -187,23 +227,31 @@ gbinder_local_object_default_handle_looper_transaction(
guint flags,
int* status)
{
GBinderLocalObjectTxHandler handler = NULL;
switch (code) {
case GBINDER_PING_TRANSACTION:
handler = gbinder_local_object_ping_transaction;
break;
case GBINDER_INTERFACE_TRANSACTION:
handler = gbinder_local_object_interface_transaction;
break;
case HIDL_PING_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_ping_transaction
(self, req, status);
handler = gbinder_local_object_hidl_ping_transaction;
break;
case HIDL_GET_DESCRIPTOR_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_get_descriptor_transaction
(self, req, status);
handler = gbinder_local_object_hidl_get_descriptor_transaction;
break;
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_descriptor_chain_transaction
(self, req, status);
handler = gbinder_local_object_hidl_descriptor_chain_transaction;
break;
default:
if (status) *status = (-EBADMSG);
return NULL;
}
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return handler(self, req, status);
}
static
@@ -282,20 +330,40 @@ gbinder_local_object_handle_release_proc(
GBinderLocalObject*
gbinder_local_object_new(
GBinderIpc* ipc,
const char* iface,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
void* user_data) /* Since 1.0.30 */
{
/* Should only be called from gbinder_ipc_new_local_local_object() */
if (G_LIKELY(ipc)) {
GBinderLocalObject* self = g_object_new
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
GBinderLocalObjectPriv* priv = self->priv;
guint i = 0, n = gutil_strv_length((char**)ifaces);
gboolean append_base_interface;
if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
append_base_interface = TRUE;
n++;
} else {
append_base_interface = FALSE;
}
priv->ifaces = g_new(char*, n + 1);
if (ifaces) {
while (*ifaces) {
priv->ifaces[i++] = g_strdup(*ifaces++);
}
}
if (append_base_interface) {
priv->ifaces[i++] = g_strdup(hidl_base_interface);
}
priv->ifaces[i] = NULL;
self->ipc = gbinder_ipc_ref(ipc);
self->iface = priv->iface = g_strdup(iface);
self->ifaces = (const char**)priv->ifaces;
priv->txproc = txproc;
priv->user_data = user_data;
gbinder_ipc_register_local_object(ipc, self);
return self;
}
return NULL;
@@ -491,7 +559,7 @@ gbinder_local_object_finalize(
GASSERT(!self->strong_refs);
gbinder_ipc_unref(self->ipc);
g_free(priv->iface);
g_strfreev(priv->ifaces);
G_OBJECT_CLASS(gbinder_local_object_parent_class)->finalize(local);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -55,7 +55,7 @@ struct gbinder_local_object {
GObject object;
GBinderLocalObjectPriv* priv;
GBinderIpc* ipc;
const char* iface;
const char* const* ifaces;
gint weak_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_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
gbinder_local_object_add_weak_refs_changed_handler(
GBinderLocalObject* obj,

View File

@@ -95,14 +95,13 @@ gbinder_local_reply_new(
GBinderLocalReply*
gbinder_local_reply_new_from_data(
GBinderBuffer* buffer,
void** objects)
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, objects);
gbinder_writer_data_set_contents(&self->data, buffer);
}
return self;
}

View File

@@ -47,8 +47,7 @@ gbinder_local_reply_data(
GBinderLocalReply*
gbinder_local_reply_new_from_data(
GBinderBuffer* buffer,
void** objects);
GBinderBuffer* buffer);
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */

View File

@@ -44,7 +44,6 @@ struct gbinder_local_request {
gint refcount;
GBinderWriterData data;
GBinderOutputData out;
GBinderBufferMemory* memory;
};
GBINDER_INLINE_FUNC
@@ -106,14 +105,13 @@ gbinder_local_request_new(
GBinderLocalRequest*
gbinder_local_request_new_from_data(
GBinderBuffer* buffer,
void** objects)
GBinderBuffer* buffer)
{
GBinderLocalRequest* self = gbinder_local_request_new
(gbinder_buffer_io(buffer), NULL);
if (self) {
gbinder_writer_data_set_contents(&self->data, buffer, objects);
gbinder_writer_data_set_contents(&self->data, buffer);
}
return self;
}
@@ -128,7 +126,6 @@ gbinder_local_request_free(
g_byte_array_free(data->bytes, TRUE);
gutil_int_array_free(data->offsets, TRUE);
gbinder_cleanup_free(data->cleanup);
gbinder_buffer_memory_unref(self->memory);
g_slice_free(GBinderLocalRequest, self);
}

View File

@@ -48,8 +48,7 @@ gbinder_local_request_data(
GBinderLocalRequest*
gbinder_local_request_new_from_data(
GBinderBuffer* buffer,
void** objects);
GBinderBuffer* buffer);
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-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:
*
@@ -38,6 +38,9 @@
#include <gutil_macros.h>
#include <errno.h>
#include <fcntl.h>
typedef struct gbinder_reader_priv {
const guint8* start;
const guint8* end;
@@ -50,6 +53,8 @@ G_STATIC_ASSERT(sizeof(GBinderReader) >= sizeof(GBinderReaderPriv));
static inline GBinderReaderPriv* gbinder_reader_cast(GBinderReader* reader)
{ return (GBinderReaderPriv*)reader; }
static inline const GBinderReaderPriv* gbinder_reader_cast_c
(const GBinderReader* reader) { return (GBinderReaderPriv*)reader; }
void
gbinder_reader_init(
@@ -81,9 +86,9 @@ gbinder_reader_init(
gboolean
gbinder_reader_at_end(
GBinderReader* reader)
const GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
return p->ptr >= p->end;
}
@@ -229,16 +234,67 @@ gbinder_reader_read_double(
}
}
static
inline
gboolean
gbinder_reader_can_read_object(
GBinderReaderPriv* p)
{
const GBinderReaderData* data = p->data;
return data && data->reg &&
p->objects && p->objects[0] &&
p->ptr == p->objects[0];
}
int
gbinder_reader_read_fd(
GBinderReader* reader) /* Since 1.0.18 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
if (gbinder_reader_can_read_object(p)) {
int fd;
const guint eaten = p->data->reg->io->decode_fd_object(p->ptr,
gbinder_reader_bytes_remaining(reader), &fd);
if (eaten) {
GASSERT(fd >= 0);
p->ptr += eaten;
p->objects++;
return fd;
}
}
return -1;
}
int
gbinder_reader_read_dup_fd(
GBinderReader* reader) /* Since 1.0.18 */
{
const int fd = gbinder_reader_read_fd(reader);
if (fd >= 0) {
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
if (dupfd >= 0) {
return dupfd;
} else {
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
}
}
return -1;
}
gboolean
gbinder_reader_read_nullable_object(
GBinderReader* reader,
GBinderRemoteObject** out)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderData* data = p->data;
if (data && data->reg && p->objects && p->objects[0] &&
p->ptr == p->objects[0]) {
if (gbinder_reader_can_read_object(p)) {
const GBinderReaderData* data = p->data;
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
gbinder_reader_bytes_remaining(reader), data->reg, out);
@@ -264,15 +320,14 @@ gbinder_reader_read_object(
static
gboolean
gbinder_reader_read_buffer_impl(
gbinder_reader_read_buffer_object(
GBinderReader* reader,
GBinderBuffer** out)
GBinderIoBufferObject* out)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderData* data = p->data;
if (data && data->reg && p->objects && p->objects[0] &&
p->ptr == p->objects[0]) {
if (gbinder_reader_can_read_object(p)) {
const GBinderReaderData* data = p->data;
GBinderBuffer* buf = data->buffer;
const GBinderIo* io = data->reg->io;
const gsize offset = p->ptr - (guint8*)buf->data;
@@ -284,7 +339,6 @@ gbinder_reader_read_buffer_impl(
return TRUE;
}
}
if (out) *out = NULL;
return FALSE;
}
@@ -292,34 +346,36 @@ GBinderBuffer*
gbinder_reader_read_buffer(
GBinderReader* reader)
{
GBinderBuffer* buf = NULL;
GBinderIoBufferObject obj;
gbinder_reader_read_buffer_impl(reader, &buf);
return buf;
if (gbinder_reader_read_buffer_object(reader, &obj)) {
const GBinderReaderData* data = gbinder_reader_cast(reader)->data;
GBinderBuffer* buf = data->buffer;
return gbinder_buffer_new_with_parent(buf, obj.data, obj.size);
}
return NULL;
}
gboolean
gbinder_reader_skip_buffer(
GBinderReader* reader)
{
return gbinder_reader_read_buffer_impl(reader, NULL);
return gbinder_reader_read_buffer_object(reader, NULL);
}
/* Helper for gbinder_reader_read_hidl_struct() macro */
const void*
gbinder_reader_read_hidl_struct1(
GBinderReader* reader,
gsize size) /* since 1.0.9 */
gsize size) /* Since 1.0.9 */
{
const void* result = NULL;
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
GBinderIoBufferObject obj;
/* Check the size */
if (buf && buf->size == size) {
result = buf->data;
if (gbinder_reader_read_buffer_object(reader, &obj) && obj.size == size) {
return obj.data;
}
gbinder_buffer_free(buf);
return result;
return NULL;
}
/* Doesn't copy the data */
@@ -329,30 +385,28 @@ gbinder_reader_read_hidl_vec(
gsize* count,
gsize* elemsize)
{
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
gsize out_count = 0, out_elemsize = 0;
GBinderIoBufferObject obj;
const void* out = NULL;
gsize out_count = 0, out_elemsize = 0;
if (buf && buf->size == sizeof(HidlVec)) {
const HidlVec* vec = buf->data;
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) {
GBinderBuffer* vbuf = gbinder_reader_read_buffer(reader);
if (vbuf && vbuf->data == next && ((!vec->count && !vbuf->size) ||
(vec->count && vbuf->size && !(vbuf->size % vec->count)))) {
out_elemsize = vec->count ? (vbuf->size / vec->count) : 0;
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 = vbuf->data;
out = obj.data;
}
gbinder_buffer_free(vbuf);
} else if (!vec->count) {
/* Any non-NULL pointer just to indicate success */
/* Any non-NULL pointer just to indicate success? */
out = vec;
}
}
gbinder_buffer_free(buf);
if (elemsize) {
*elemsize = out_elemsize;
}
@@ -367,7 +421,7 @@ const void*
gbinder_reader_read_hidl_vec1(
GBinderReader* reader,
gsize* count,
guint expected_elem_size) /* since 1.0.9 */
guint expected_elem_size) /* Since 1.0.9 */
{
gsize actual;
const void* data = gbinder_reader_read_hidl_vec(reader, count, &actual);
@@ -376,88 +430,94 @@ gbinder_reader_read_hidl_vec1(
return (data && (actual == expected_elem_size || !actual)) ? data : NULL;
}
const char*
gbinder_reader_read_hidl_string_c(
GBinderReader* reader) /* Since 1.0.23 */
{
GBinderIoBufferObject obj;
if (gbinder_reader_read_buffer_object(reader, &obj) &&
obj.data && obj.size == sizeof(GBinderHidlString)) {
const GBinderHidlString* str = obj.data;
if (gbinder_reader_read_buffer_object(reader, &obj) &&
obj.has_parent &&
obj.parent_offset == GBINDER_HIDL_STRING_BUFFER_OFFSET &&
obj.data == str->data.str &&
obj.size == str->len + 1 &&
str->data.str[str->len] == 0) {
return str->data.str;
}
}
return NULL;
}
char*
gbinder_reader_read_hidl_string(
GBinderReader* reader)
{
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
char* str = NULL;
if (buf && buf->size == sizeof(HidlString)) {
const HidlString* s = buf->data;
GBinderBuffer* sbuf = gbinder_reader_read_buffer(reader);
if (sbuf && sbuf->size == s->len + 1 &&
sbuf->data == s->data.str &&
s->data.str[s->len] == 0) {
str = g_strdup(s->data.str);
}
gbinder_buffer_free(sbuf);
}
gbinder_buffer_free(buf);
return str;
/* This function should've been called gbinder_reader_dup_hidl_string */
return g_strdup(gbinder_reader_read_hidl_string_c(reader));
}
char**
gbinder_reader_read_hidl_string_vec(
GBinderReader* reader)
{
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
GBinderIoBufferObject obj;
/* First buffer contains hidl_vector */
if (buf && buf->size == sizeof(HidlVec)) {
HidlVec* vec = buf->data;
if (gbinder_reader_read_buffer_object(reader, &obj) &&
obj.data && obj.size == sizeof(GBinderHidlVec)) {
GBinderHidlVec* vec = obj.data;
const guint n = vec->count;
const void* next = vec->data.ptr;
gbinder_buffer_free(buf);
if (!next && !n) {
char** out = g_new(char*, 1);
/* 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;
return out;
} else {
/* The second buffer (if any) contains n hidl_string's */
buf = gbinder_reader_read_buffer(reader);
if (buf && buf->data == next && buf->size == sizeof(HidlString)*n) {
const HidlString* strings = buf->data;
GBinderBuffer* sbuf;
GPtrArray* list = g_ptr_array_new();
guint i;
/* Now we expect n buffers containing the actual data */
for (i = 0; i < n &&
gbinder_reader_read_buffer_object(reader, &obj); i++) {
const GBinderHidlString* s = strings + i;
const gsize expected_offset = (i * sizeof(*s)) +
GBINDER_HIDL_STRING_BUFFER_OFFSET;
if (obj.has_parent &&
obj.parent_offset == expected_offset &&
obj.data == s->data.str &&
obj.size == s->len + 1 &&
s->data.str[s->len] == 0) {
char* name = g_strdup(s->data.str);
/* Now we expect n buffers containing the actual data */
for (i=0; i<n &&
(sbuf = gbinder_reader_read_buffer(reader)); i++) {
const HidlString* s = strings + i;
if (sbuf->size == s->len + 1 &&
sbuf->data == s->data.str &&
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;
}
g_ptr_array_add(list, name);
GVERBOSE_("%u. %s", i + 1, name);
} else {
GWARN("Unexpected hidl_string buffer %p/%u vs %p/%u",
obj.data, (guint)obj.size, s->data.str, s->len);
break;
}
if (i == n) {
gbinder_buffer_free(buf);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
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>");
gbinder_buffer_free(buf);
return NULL;
}
@@ -489,6 +549,24 @@ gboolean
gbinder_reader_read_nullable_string16(
GBinderReader* reader,
char** out)
{
const gunichar2* str;
gsize len;
if (gbinder_reader_read_nullable_string16_utf16(reader, &str, &len)) {
if (out) {
*out = str ? g_utf16_to_utf8(str, len, NULL, NULL, NULL) : NULL;
}
return TRUE;
}
return FALSE;
}
gboolean
gbinder_reader_read_nullable_string16_utf16(
GBinderReader* reader,
const gunichar2** out,
gsize* out_len) /* Since 1.0.17 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
@@ -502,15 +580,21 @@ gbinder_reader_read_nullable_string16(
if (out) {
*out = NULL;
}
if (out_len) {
*out_len = 0;
}
return TRUE;
} else if (len >= 0) {
const guint32 padded_len = G_ALIGN4((len+1)*2);
const gunichar2* utf16 = (const gunichar2*)(p->ptr + 4);
const guint32 padded_len = G_ALIGN4((len + 1)*2);
const gunichar2* utf16 = (gunichar2*)(p->ptr + 4);
if ((p->ptr + padded_len + 4) <= p->end) {
p->ptr += padded_len + 4;
if (out) {
*out = g_utf16_to_utf8(utf16, len, NULL, NULL, NULL);
*out = utf16;
}
if (out_len) {
*out_len = len;
}
return TRUE;
}
@@ -519,6 +603,21 @@ gbinder_reader_read_nullable_string16(
return FALSE;
}
const gunichar2*
gbinder_reader_read_string16_utf16(
GBinderReader* reader,
gsize* len) /* Since 1.0.26 */
{
const gunichar2* str;
/*
* Use gbinder_reader_read_nullable_string16_utf16 to distinguish
* NULL string from a parsing failure.
*/
return gbinder_reader_read_nullable_string16_utf16(reader, &str, len) ?
str : NULL;
}
char*
gbinder_reader_read_string16(
GBinderReader* reader)
@@ -558,7 +657,7 @@ gbinder_reader_skip_string16(
const void*
gbinder_reader_read_byte_array(
GBinderReader* reader,
gsize* len) /* since 1.0.12 */
gsize* len) /* Since 1.0.12 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const void* data = NULL;
@@ -583,22 +682,31 @@ gbinder_reader_read_byte_array(
gsize
gbinder_reader_bytes_read(
GBinderReader* reader)
const GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
return p->ptr - p->start;
}
gsize
gbinder_reader_bytes_remaining(
GBinderReader* reader)
const GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
return p->end - p->ptr;
}
void
gbinder_reader_copy(
GBinderReader* dest,
const GBinderReader* src)
{
/* It's actually quite simple :) */
memcpy(dest, src, sizeof(*dest));
}
/*
* Local Variables:
* mode: C

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -33,6 +33,7 @@
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_servicemanager_p.h"
#include "gbinder_log.h"
struct gbinder_remote_object_priv {
@@ -65,9 +66,20 @@ void
gbinder_remote_object_died_on_main_thread(
GBinderRemoteObject* self)
{
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
GASSERT(!self->dead);
self->dead = TRUE;
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
if (!self->dead) {
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
@@ -79,6 +91,47 @@ gbinder_remote_object_died_handle(
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
*==========================================================================*/
@@ -86,15 +139,19 @@ gbinder_remote_object_died_handle(
GBinderRemoteObject*
gbinder_remote_object_new(
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
(GBINDER_TYPE_REMOTE_OBJECT, NULL);
self->ipc = gbinder_ipc_ref(ipc);
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 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
gbinder_remote_object_is_dead(
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
*==========================================================================*/
@@ -200,8 +252,10 @@ gbinder_remote_object_finalize(
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
gbinder_driver_clear_death_notification(driver, self);
gbinder_driver_release(driver, self->handle);
if (!self->dead) {
gbinder_driver_clear_death_notification(driver, self);
gbinder_driver_release(driver, self->handle);
}
gbinder_ipc_unref(ipc);
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->finalize(remote);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -54,7 +54,12 @@ struct gbinder_remote_object {
GBinderRemoteObject*
gbinder_remote_object_new(
GBinderIpc* ipc,
guint32 handle);
guint32 handle,
gboolean maybe_dead);
gboolean
gbinder_remote_object_reanimate(
GBinderRemoteObject* obj);
void
gbinder_remote_object_handle_death_notification(

View File

@@ -34,7 +34,7 @@
#include "gbinder_local_reply_p.h"
#include "gbinder_reader_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_buffer.h"
#include "gbinder_buffer_p.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
@@ -65,26 +65,22 @@ gbinder_remote_reply_free(
gbinder_object_registry_unref(data->reg);
gbinder_buffer_free(data->buffer);
g_free(data->objects);
g_slice_free(GBinderRemoteReply, self);
}
void
gbinder_remote_reply_set_data(
GBinderRemoteReply* self,
GBinderBuffer* buffer,
void** objects)
GBinderBuffer* buffer)
{
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
g_free(data->objects);
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = objects;
data->objects = gbinder_buffer_objects(buffer);
} else {
gbinder_buffer_free(buffer);
g_free(objects);
}
}
@@ -125,7 +121,7 @@ gbinder_remote_reply_copy_to_local(
if (G_LIKELY(self)) {
GBinderReaderData* d = &self->data;
return gbinder_local_reply_new_from_data(d->buffer, d->objects);
return gbinder_local_reply_new_from_data(d->buffer);
}
return NULL;
}

View File

@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -44,8 +44,7 @@ gbinder_remote_reply_new(
void
gbinder_remote_reply_set_data(
GBinderRemoteReply* reply,
GBinderBuffer* buffer,
void** objects);
GBinderBuffer* buffer);
gboolean
gbinder_remote_reply_is_empty(

View File

@@ -35,12 +35,15 @@
#include "gbinder_rpc_protocol.h"
#include "gbinder_local_request_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_buffer.h"
#include "gbinder_buffer_p.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
struct gbinder_remote_request {
#include <errno.h>
typedef struct gbinder_remote_request_priv {
GBinderRemoteRequest pub;
gint refcount;
pid_t pid;
uid_t euid;
@@ -49,7 +52,11 @@ struct gbinder_remote_request {
char* iface2;
gsize header_size;
GBinderReaderData data;
};
} GBinderRemoteRequestPriv;
GBINDER_INLINE_FUNC GBinderRemoteRequestPriv*
gbinder_remote_request_cast(GBinderRemoteRequest* pub)
{ return G_LIKELY(pub) ? G_CAST(pub,GBinderRemoteRequestPriv,pub) : NULL; }
GBinderRemoteRequest*
gbinder_remote_request_new(
@@ -58,7 +65,7 @@ gbinder_remote_request_new(
pid_t pid,
uid_t euid)
{
GBinderRemoteRequest* self = g_slice_new0(GBinderRemoteRequest);
GBinderRemoteRequestPriv* self = g_slice_new0(GBinderRemoteRequestPriv);
GBinderReaderData* data = &self->data;
g_atomic_int_set(&self->refcount, 1);
@@ -66,17 +73,19 @@ gbinder_remote_request_new(
self->euid = euid;
self->protocol = protocol;
data->reg = gbinder_object_registry_ref(reg);
return self;
return &self->pub;
}
GBinderLocalRequest*
gbinder_remote_request_copy_to_local(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReaderData* d = &self->data;
return gbinder_local_request_new_from_data(d->buffer, d->objects);
return gbinder_local_request_new_from_data(d->buffer);
}
return NULL;
}
@@ -84,22 +93,27 @@ gbinder_remote_request_copy_to_local(
static
void
gbinder_remote_request_free(
GBinderRemoteRequest* self)
GBinderRemoteRequestPriv* self)
{
GBinderReaderData* data = &self->data;
GBinderRemoteRequest* req = &self->pub;
GASSERT(!req->tx);
if (req->tx) {
GWARN("Request is dropped without completing the transaction");
gbinder_remote_request_complete(req, NULL, -ECANCELED);
}
gbinder_object_registry_unref(data->reg);
gbinder_buffer_free(data->buffer);
g_free(data->objects);
g_free(self->iface2);
g_slice_free(GBinderRemoteRequest, self);
g_slice_free(GBinderRemoteRequestPriv, self);
}
static
inline
void
gbinder_remote_request_init_reader2(
GBinderRemoteRequest* self,
GBinderRemoteRequestPriv* self,
GBinderReader* p)
{
/* The caller has already checked the request for NULL */
@@ -116,53 +130,64 @@ gbinder_remote_request_init_reader2(
void
gbinder_remote_request_set_data(
GBinderRemoteRequest* self,
GBinderBuffer* buffer,
void** objects)
GBinderRemoteRequest* req,
guint32 txcode,
GBinderBuffer* buffer)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
GBinderReader reader;
g_free(self->iface2);
g_free(data->objects);
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = objects;
data->objects = gbinder_buffer_objects(buffer);
/* Parse RPC header */
self->header_size = 0;
gbinder_remote_request_init_reader2(self, &reader);
self->iface = self->protocol->read_rpc_header(&reader, &self->iface2);
self->header_size = gbinder_reader_bytes_read(&reader);
self->iface = self->protocol->read_rpc_header(&reader, txcode,
&self->iface2);
if (self->iface) {
self->header_size = gbinder_reader_bytes_read(&reader);
} else {
/* No RPC header */
self->header_size = 0;
}
} else {
gbinder_buffer_free(buffer);
g_free(objects);
}
}
const char*
gbinder_remote_request_interface(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
return G_LIKELY(self) ? self->iface : NULL;
}
GBinderRemoteRequest*
gbinder_remote_request_ref(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return self;
return req;
}
void
gbinder_remote_request_unref(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
@@ -173,9 +198,11 @@ gbinder_remote_request_unref(
void
gbinder_remote_request_init_reader(
GBinderRemoteRequest* self,
GBinderRemoteRequest* req,
GBinderReader* reader)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
gbinder_remote_request_init_reader2(self, reader);
} else {
@@ -185,15 +212,19 @@ gbinder_remote_request_init_reader(
pid_t
gbinder_remote_request_sender_pid(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
return G_LIKELY(self) ? self->pid : (uid_t)(-1);
}
uid_t
gbinder_remote_request_sender_euid(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
return G_LIKELY(self) ? self->euid : (uid_t)(-1);
}
@@ -207,9 +238,11 @@ gbinder_remote_request_read_int32(
gboolean
gbinder_remote_request_read_uint32(
GBinderRemoteRequest* self,
GBinderRemoteRequest* req,
guint32* value)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;
@@ -229,9 +262,11 @@ gbinder_remote_request_read_int64(
gboolean
gbinder_remote_request_read_uint64(
GBinderRemoteRequest* self,
GBinderRemoteRequest* req,
guint64* value)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;
@@ -243,8 +278,10 @@ gbinder_remote_request_read_uint64(
const char*
gbinder_remote_request_read_string8(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;
@@ -256,8 +293,10 @@ gbinder_remote_request_read_string8(
char*
gbinder_remote_request_read_string16(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;
@@ -269,8 +308,10 @@ gbinder_remote_request_read_string16(
GBinderRemoteObject*
gbinder_remote_request_read_object(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;

View File

@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -37,6 +37,10 @@
#include "gbinder_types_p.h"
struct gbinder_remote_request {
GBinderIpcLooperTx* tx;
};
GBinderRemoteRequest*
gbinder_remote_request_new(
GBinderObjectRegistry* reg,
@@ -47,8 +51,8 @@ gbinder_remote_request_new(
void
gbinder_remote_request_set_data(
GBinderRemoteRequest* request,
GBinderBuffer* buffer,
void** objects);
guint txcode,
GBinderBuffer* buffer);
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-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:
*
@@ -50,6 +50,14 @@
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
static
void
gbinder_rpc_protocol_binder_write_ping(
GBinderWriter* writer)
{
/* No payload */
}
static
void
gbinder_rpc_protocol_binder_write_rpc_header(
@@ -69,9 +77,13 @@ static
const char*
gbinder_rpc_protocol_binder_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
{
if (gbinder_reader_read_int32(reader, NULL)) {
if (txcode > GBINDER_TRANSACTION(0,0,0)) {
/* Internal transaction e.g. GBINDER_DUMP_TRANSACTION etc. */
*iface = NULL;
} else if (gbinder_reader_read_int32(reader, NULL)) {
*iface = gbinder_reader_read_string16(reader);
} else {
*iface = NULL;
@@ -95,10 +107,20 @@ gbinder_rpc_protocol_hwbinder_write_rpc_header(
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
const char*
gbinder_rpc_protocol_hwbinder_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
{
*iface = NULL;
@@ -110,13 +132,17 @@ gbinder_rpc_protocol_hwbinder_read_rpc_header(
*==========================================================================*/
const GBinderRpcProtocol gbinder_rpc_protocol_binder = {
.read_rpc_header = gbinder_rpc_protocol_binder_read_rpc_header,
.write_rpc_header = gbinder_rpc_protocol_binder_write_rpc_header
.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 = {
.read_rpc_header = gbinder_rpc_protocol_hwbinder_read_rpc_header,
.write_rpc_header = gbinder_rpc_protocol_hwbinder_write_rpc_header
.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*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -42,8 +42,11 @@
*/
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);
const char* (*read_rpc_header)(GBinderReader* reader, guint32 txcode,
char** iface);
};
extern const GBinderRpcProtocol gbinder_rpc_protocol_binder;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -41,9 +41,14 @@
#include <gbinder_client.h>
#include <gutil_idlepool.h>
#include <gutil_misc.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;
@@ -53,6 +58,10 @@ typedef struct gbinder_servicemanager_watch {
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,
@@ -72,10 +81,12 @@ G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_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
@@ -253,6 +264,129 @@ gbinder_servicemanager_add_service_tx_free(
g_slice_free(GBinderServiceManagerAddServiceTxData, data);
}
static
void
gbinder_servicemanager_reanimated(
GBinderServiceManager* self)
{
GBinderServiceManagerPriv* priv = self->priv;
if (priv->presence_check_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
*==========================================================================*/
@@ -271,21 +405,25 @@ gbinder_servicemanager_new_with_type(
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, klass->handle);
(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 */
GVERBOSE_("%s", dev);
first_ref = TRUE;
self = g_object_new(type, NULL);
self->client = gbinder_client_new(object, klass->iface);
self->dev = gbinder_remote_object_dev(object);
@@ -297,6 +435,20 @@ gbinder_servicemanager_new_with_type(
}
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);
@@ -357,10 +509,25 @@ gbinder_servicemanager_new_local_object(
const char* iface,
GBinderLocalTransactFunc txproc,
void* user_data)
{
const char* ifaces[2];
ifaces[0] = iface;
ifaces[1] = NULL;
return gbinder_servicemanager_new_local_object2
(self, ifaces, txproc, user_data);
}
GBinderLocalObject*
gbinder_servicemanager_new_local_object2(
GBinderServiceManager* self,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
{
if (G_LIKELY(self)) {
return gbinder_ipc_new_local_object(gbinder_client_ipc(self->client),
iface, txproc, user_data);
return gbinder_local_object_new(gbinder_client_ipc(self->client),
ifaces, txproc, user_data);
}
return NULL;
}
@@ -384,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
gbinder_servicemanager_list(
GBinderServiceManager* self,
@@ -513,6 +732,16 @@ 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,
@@ -546,8 +775,8 @@ gbinder_servicemanager_add_registration_handler(
watch = gbinder_servicemanager_watch_new(name);
g_hash_table_insert(priv->watch_table, watch->name, watch);
}
if (!watch->watched) {
watch->watched = klass->watch(self, name);
if (!watch->watched && !self->client->remote->dead) {
watch->watched = klass->watch(self, watch->name);
if (watch->watched) {
GDEBUG("Watching %s", watch->name);
} else {
@@ -570,26 +799,46 @@ gbinder_servicemanager_remove_handler(
GBinderServiceManager* self,
gulong id) /* Since 1.0.13 */
{
if (G_LIKELY(self) && G_LIKELY(id)) {
GBinderServiceManagerClass* klass =
GBINDER_SERVICEMANAGER_GET_CLASS(self);
GBinderServiceManagerPriv* priv = self->priv;
GHashTableIter it;
gpointer value;
gbinder_servicemanager_remove_handlers(self, &id, 1);
}
g_signal_handler_disconnect(self, id);
g_hash_table_iter_init(&it, priv->watch_table);
while (g_hash_table_iter_next(&it, NULL, &value)) {
GBinderServiceManagerWatch* watch = value;
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;
if (watch->watched && !g_signal_has_handler_pending(self,
gbinder_servicemanager_signals[SIGNAL_REGISTRATION],
watch->quark, TRUE)) {
/* This must be the one we have just removed */
GDEBUG("Unwatching %s", watch->name);
watch->watched = FALSE;
klass->unwatch(self, watch->name);
break;
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--;
}
}
}
}
@@ -662,6 +911,10 @@ gbinder_servicemanager_finalize(
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
GBinderServiceManagerPriv* priv = self->priv;
if (priv->presence_check_id) {
g_source_remove(priv->presence_check_id);
}
gbinder_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);
@@ -674,13 +927,18 @@ gbinder_servicemanager_class_init(
GBinderServiceManagerClass* klass)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
GType type = G_OBJECT_CLASS_TYPE(klass);
g_mutex_init(&klass->mutex);
g_type_class_add_private(klass, sizeof(GBinderServiceManagerPriv));
object_class->dispose = gbinder_servicemanager_dispose;
object_class->finalize = gbinder_servicemanager_finalize;
gbinder_servicemanager_signals[SIGNAL_PRESENCE] =
g_signal_new(SIGNAL_PRESENCE_NAME, type,
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
gbinder_servicemanager_signals[SIGNAL_REGISTRATION] =
g_signal_new(SIGNAL_REGISTRATION_NAME, G_OBJECT_CLASS_TYPE(klass),
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);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -39,6 +39,9 @@
#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 {
@@ -60,7 +63,6 @@ typedef struct gbinder_servicemanager_class {
GMutex mutex;
GHashTable* table;
guint32 handle;
const char* iface;
const char* default_device;
const GBinderRpcProtocol* rpc_protocol;

173
src/gbinder_servicename.c Normal file
View 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
View 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
View 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:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -35,37 +35,16 @@
#include <gbinder_types.h>
typedef struct gbinder_buffer_memory GBinderBufferMemory;
typedef struct gbinder_buffer_contents GBinderBufferContents;
typedef struct gbinder_cleanup GBinderCleanup;
typedef struct gbinder_driver GBinderDriver;
typedef struct gbinder_handler GBinderHandler;
typedef struct gbinder_io GBinderIo;
typedef struct gbinder_ipc GBinderIpc;
typedef struct gbinder_object_registry GBinderObjectRegistry;
typedef struct gbinder_output_data GBinderOutputData;
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;
typedef struct hidl_vec {
union {
guint64 value;
const void* ptr;
} data;
guint32 count;
guint32 owns_buffer;
} HidlVec;
#define HIDL_VEC_BUFFER_OFFSET (0)
typedef struct hidl_string {
union {
guint64 value;
const char* str;
} data;
guint32 len;
guint32 owns_buffer;
} HidlString;
#define HIDL_STRING_BUFFER_OFFSET (0)
typedef struct gbinder_servicepoll GBinderServicePoll;
typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
#define GBINDER_INLINE_FUNC static inline

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -39,7 +39,10 @@
#include <gutil_macros.h>
#include <gutil_strv.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
typedef struct gbinder_writer_priv {
GBinderWriterData* data;
@@ -54,47 +57,49 @@ GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub)
static
void
gbinder_writer_data_memory_cleanup(
gpointer memory)
gbinder_writer_data_buffer_cleanup(
gpointer data)
{
gbinder_buffer_memory_unref(memory);
gbinder_buffer_contents_unref((GBinderBufferContents*)data);
}
void
gbinder_writer_data_set_contents(
GBinderWriterData* data,
GBinderBuffer* buffer,
void** objects)
GBinderBuffer* buffer)
{
gsize bufsize;
const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize);
const GBinderIo* io = gbinder_buffer_io(buffer);
GBinderBufferMemory* mem = gbinder_buffer_memory(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 (mem) {
data->cleanup = gbinder_cleanup_add(data->cleanup,
gbinder_writer_data_memory_cleanup,
gbinder_buffer_memory_ref(mem));
}
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);
if (contents) {
void** objects = gbinder_buffer_objects(buffer);
GASSERT(offset > 0 && offset < bufsize);
gutil_int_array_append(data->offsets, (int)offset);
/* Size of each buffer has to be 8-byte aligned */
data->buffers_size += G_ALIGN8(objsize);
data->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);
}
}
}
}
@@ -144,6 +149,14 @@ gbinder_writer_init(
gbinder_writer_cast(self)->data = data;
}
gsize
gbinder_writer_bytes_written(
GBinderWriter* self) /* since 1.0.21 */
{
GBinderWriterData* data = gbinder_writer_data(self);
return data->bytes->len;
}
void
gbinder_writer_append_bool(
GBinderWriter* self,
@@ -194,6 +207,26 @@ gbinder_writer_data_append_int32(
*ptr = value;
}
void
gbinder_writer_overwrite_int32(
GBinderWriter* self,
gsize offset,
gint32 value) /* since 1.0.21 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
GByteArray* buf = data->bytes;
if (buf->len >= offset + sizeof(gint32)) {
*((gint32*)(buf->data + offset)) = value;
} else {
GWARN("Can't overwrite at %lu as buffer is only %u bytes long",
(gulong)offset, buf->len);
}
}
}
void
gbinder_writer_append_int64(
GBinderWriter* self,
@@ -351,15 +384,36 @@ gbinder_writer_data_append_string16(
gbinder_writer_data_append_string16_len(data, utf8, utf8? strlen(utf8) : 0);
}
static
void
gbinder_writer_data_append_string16_null(
GBinderWriterData* data)
{
/* NULL string */
gbinder_writer_data_append_int32(data, -1);
}
static
void
gbinder_writer_data_append_string16_empty(
GBinderWriterData* data)
{
GByteArray* buf = data->bytes;
const gsize old_size = buf->len;
guint16* ptr16;
/* Empty string */
g_byte_array_set_size(buf, old_size + 8);
ptr16 = (guint16*)(buf->data + old_size);
ptr16[0] = ptr16[1] = ptr16[2] = 0; ptr16[3] = 0xffff;
}
void
gbinder_writer_data_append_string16_len(
GBinderWriterData* data,
const char* utf8,
gssize num_bytes)
{
GByteArray* buf = data->bytes;
const gsize old_size = buf->len;
if (utf8) {
const char* end = utf8;
@@ -370,6 +424,8 @@ gbinder_writer_data_append_string16_len(
}
if (num_bytes > 0) {
GByteArray* buf = data->bytes;
const gsize old_size = buf->len;
glong len = g_utf8_strlen(utf8, num_bytes);
gsize padded_len = G_ALIGN4((len+1)*2);
guint32* len_ptr;
@@ -407,14 +463,69 @@ gbinder_writer_data_append_string16_len(
g_byte_array_set_size(buf, old_size + padded_len + 4);
} else if (utf8) {
/* Empty string */
guint16* ptr16;
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;
gbinder_writer_data_append_string16_empty(data);
} else {
/* NULL string */
gbinder_writer_data_append_int32(data, -1);
gbinder_writer_data_append_string16_null(data);
}
}
static
void
gbinder_writer_data_append_string16_utf16(
GBinderWriterData* data,
const gunichar2* utf16,
gssize length)
{
if (length < 0) {
length = 0;
if (utf16) {
const guint16* ptr;
/* Assume NULL terminated string */
for (ptr = utf16; *ptr; ptr++);
length = ptr - utf16;
}
}
if (length > 0) {
GByteArray* buf = data->bytes;
const gsize old_size = buf->len;
const gsize padded_size = G_ALIGN4((length + 1) * 2);
guint32* len_ptr;
gunichar2* utf16_ptr;
/* Preallocate space */
g_byte_array_set_size(buf, old_size + padded_size + 4);
len_ptr = (guint32*)(buf->data + old_size);
utf16_ptr = (gunichar2*)(len_ptr + 1);
/* Actual length */
*len_ptr = length;
/* Characters */
memcpy(utf16_ptr, utf16, 2 * length);
/* Zero padding */
memset(utf16_ptr + length, 0, padded_size - 2 * length);
} else if (utf16) {
/* Empty string */
gbinder_writer_data_append_string16_empty(data);
} else {
/* NULL string */
gbinder_writer_data_append_string16_null(data);
}
}
void
gbinder_writer_append_string16_utf16(
GBinderWriter* self,
const gunichar2* utf16,
gssize length) /* Since 1.0.17 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_string16_utf16(data, utf16, length);
}
}
@@ -442,6 +553,60 @@ gbinder_writer_data_prepare(
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
gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* self,
@@ -504,13 +669,13 @@ gbinder_writer_data_append_hidl_vec(
guint elemsize)
{
GBinderParent vec_parent;
HidlVec* vec = g_new0(HidlVec, 1);
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 = HIDL_VEC_BUFFER_OFFSET;
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
/* Fill in the vector descriptor */
if (buf) {
@@ -550,12 +715,12 @@ gbinder_writer_data_append_hidl_string(
const char* str)
{
GBinderParent str_parent;
HidlString* hidl_string = g_new0(HidlString, 1);
GBinderHidlString* hidl_string = g_new0(GBinderHidlString, 1);
const gsize len = str ? strlen(str) : 0;
/* Prepare parent descriptor for the string data */
str_parent.index = gbinder_writer_data_prepare(data);
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
/* Fill in the string descriptor and store it */
hidl_string->data.str = str;
@@ -597,8 +762,8 @@ gbinder_writer_data_append_hidl_string_vec(
gssize count)
{
GBinderParent vec_parent;
HidlVec* vec = g_new0(HidlVec, 1);
HidlString* strings = NULL;
GBinderHidlVec* vec = g_new0(GBinderHidlVec, 1);
GBinderHidlString* strings = NULL;
int i;
if (count < 0) {
@@ -608,11 +773,11 @@ gbinder_writer_data_append_hidl_string_vec(
/* Prepare parent descriptor for the vector 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 */
if (count > 0) {
strings = g_new0(HidlString, count);
strings = g_new0(GBinderHidlString, count);
vec->data.ptr = strings;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, strings);
}
@@ -623,7 +788,7 @@ gbinder_writer_data_append_hidl_string_vec(
/* Fill in string descriptors */
for (i = 0; i < count; i++) {
const char* str = strv[i];
HidlString* hidl_str = strings + i;
GBinderHidlString* hidl_str = strings + i;
if ((hidl_str->data.str = str) != NULL) {
hidl_str->len = strlen(str);
@@ -638,7 +803,7 @@ gbinder_writer_data_append_hidl_string_vec(
/* Prepare parent descriptor for the string data */
str_parent.index = data->offsets->count;
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
/* Write the vector data (it's parent for the string data) */
gbinder_writer_data_write_buffer_object(data, strings,
@@ -646,7 +811,7 @@ gbinder_writer_data_append_hidl_string_vec(
/* Write the string data */
for (i = 0; i < count; i++) {
HidlString* hidl_str = strings + i;
GBinderHidlString* hidl_str = strings + i;
if (hidl_str->data.str) {
gbinder_writer_data_write_buffer_object(data,
@@ -655,7 +820,7 @@ gbinder_writer_data_append_hidl_string_vec(
(guint)hidl_str->len, (guint)str_parent.index,
(guint)data->buffers_size);
}
str_parent.offset += sizeof(HidlString);
str_parent.offset += sizeof(GBinderHidlString);
}
}
}
@@ -752,6 +917,73 @@ gbinder_writer_data_append_remote_object(
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:
* mode: C

View File

@@ -53,8 +53,7 @@ gbinder_writer_init(
void
gbinder_writer_data_set_contents(
GBinderWriterData* data,
GBinderBuffer* buffer,
void** objects);
GBinderBuffer* buffer);
void
gbinder_writer_data_append_bool(

View File

@@ -3,6 +3,7 @@
all:
%:
@$(MAKE) -C binder-client $*
@$(MAKE) -C binder-dump $*
@$(MAKE) -C binder-list $*
@$(MAKE) -C binder-service $*
@$(MAKE) -C rild-card-status $*

140
test/binder-dump/Makefile Normal file
View 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)

View 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:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -194,7 +194,7 @@ app_init(
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_quiet, "Be quiet", NULL },
{ "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,
"Binder device [" DEV_DEFAULT "]", "DEVICE" },
{ NULL }
@@ -245,7 +245,7 @@ int main(int argc, char* argv[])
app.opt = &opt;
if (app_init(&opt, argc, argv)) {
app.sm = gbinder_servicemanager_new(opt.dev);
if (app.sm) {
if (gbinder_servicemanager_wait(app.sm, -1)) {
if (opt.async) {
app_async(&app);
} else {

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -36,6 +36,9 @@
#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_NOTFOUND (1)
#define RET_INVARG (2)
@@ -49,6 +52,7 @@ typedef struct app_options {
char* dev;
char* iface;
const char* name;
gboolean async;
} AppOptions;
typedef struct app {
@@ -59,6 +63,11 @@ typedef struct app {
int ret;
} App;
typedef struct response {
GBinderRemoteRequest* req;
GBinderLocalReply* reply;
} Response;
static const char pname[] = "binder-service";
static
@@ -73,6 +82,29 @@ app_signal(
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
GBinderLocalReply*
app_reply(
@@ -83,15 +115,52 @@ app_reply(
int* status,
void* user_data)
{
char* str = gbinder_remote_request_read_string16(req);
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
App* app = user_data;
GBinderReader reader;
GVERBOSE("\"%s\" %u", gbinder_remote_request_interface(req), code);
GDEBUG("\"%s\"", str);
gbinder_local_reply_append_string16(reply, str);
g_free(str);
*status = 0;
return reply;
gbinder_remote_request_init_reader(req, &reader);
if (code == GBINDER_FIRST_CALL_TRANSACTION) {
const AppOptions* opt = app->opt;
const char* iface = gbinder_remote_request_interface(req);
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
@@ -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
void
app_run(
@@ -120,6 +206,8 @@ app_run(
const char* name = app->opt->name;
guint sigtrm = g_unix_signal_add(SIGTERM, 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);
@@ -130,6 +218,7 @@ app_run(
if (sigtrm) g_source_remove(sigtrm);
if (sigint) g_source_remove(sigint);
gbinder_servicemanager_remove_handler(app->sm, presence_id);
g_main_loop_unref(app->loop);
app->loop = NULL;
}
@@ -175,6 +264,8 @@ app_init(
"Binder device [" DEFAULT_DEVICE "]", "DEVICE" },
{ "interface", 'i', 0, G_OPTION_ARG_STRING, &opt->iface,
"Local interface [" DEFAULT_IFACE "]", "IFACE" },
{ "async", 'a', 0, G_OPTION_ARG_NONE, &opt->async,
"Handle calls asynchronously", NULL },
{ NULL }
};
@@ -226,7 +317,7 @@ int main(int argc, char* argv[])
app.opt = &opt;
if (app_init(&opt, argc, argv)) {
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.sm, opt.iface, app_reply, &app);
app_run(&app);

View File

@@ -3,6 +3,7 @@
all:
%:
@$(MAKE) -C unit_buffer $*
@$(MAKE) -C unit_cleanup $*
@$(MAKE) -C unit_client $*
@$(MAKE) -C unit_driver $*
@$(MAKE) -C unit_ipc $*
@@ -14,6 +15,9 @@ all:
@$(MAKE) -C unit_remote_object $*
@$(MAKE) -C unit_remote_reply $*
@$(MAKE) -C unit_remote_request $*
@$(MAKE) -C unit_servicemanager $*
@$(MAKE) -C unit_servicename $*
@$(MAKE) -C unit_servicepoll $*
@$(MAKE) -C unit_writer $*
clean: unitclean

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -45,6 +45,7 @@ GLOG_MODULE_DEFINE2("test_binder", gutil_log_default);
static GHashTable* test_fd_map = NULL;
static GHashTable* test_node_map = NULL;
static GPrivate test_looper;
#define public_fd fd[0]
#define private_fd fd[1]
@@ -58,6 +59,22 @@ static GHashTable* test_node_map = NULL;
#define TF_ACCEPT_FDS 0x10
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 {
char* path;
@@ -68,6 +85,8 @@ typedef struct test_binder_node {
typedef struct test_binder {
TestBinderNode* node;
TestBinderSubmitThread* submit_thread;
gboolean looper_enabled;
int fd[2];
} TestBinder;
@@ -104,6 +123,11 @@ typedef struct binder_pre_cookie_64 {
guint64 cookie;
} BinderPtrCookie64;
typedef struct binder_handle_cookie_64 {
guint32 handle;
guint64 cookie;
} __attribute__((packed)) BinderHandleCookie64;
#define BC_TRANSACTION_64 _IOW('c', 0, BinderTransactionData64)
#define BC_REPLY_64 _IOW('c', 1, BinderTransactionData64)
#define BC_FREE_BUFFER_64 _IOW('c', 3, guint64)
@@ -113,6 +137,8 @@ typedef struct binder_pre_cookie_64 {
#define BC_DECREFS _IOW('c', 7, guint32)
#define BC_ENTER_LOOPER _IO('c', 12)
#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_REPLY_64 _IOR('r', 3, BinderTransactionData64)
@@ -126,6 +152,110 @@ typedef struct binder_pre_cookie_64 {
#define BR_DEAD_BINDER_64 _IOR('r', 15, guint64)
#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(
@@ -151,11 +281,11 @@ test_io_handle_write_read_64(
TestBinder* binder,
void* data)
{
int err, bytes_available = 0;
BinderWriteRead64* wr = data;
gssize bytes_left = wr->write_size - wr->write_consumed;
const guint8* write_ptr = (void*)(gsize)
(wr->write_buffer + wr->write_consumed);
gboolean is_looper;
while (bytes_left >= sizeof(guint32)) {
const guint cmd = *(guint32*)write_ptr;
@@ -176,12 +306,18 @@ test_io_handle_write_read_64(
test_io_free_buffer(binder,
GSIZE_TO_POINTER(*(guint64*)write_ptr));
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_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS:
case BC_ENTER_LOOPER:
case BC_EXIT_LOOPER:
break;
default:
#pragma message("TODO: implement more BINDER_WRITE_READ commands")
@@ -198,24 +334,45 @@ test_io_handle_write_read_64(
}
}
/* Now read the data from the socket */
err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
if (err >= 0) {
int bytes_read = 0;
if (bytes_available > 0) {
bytes_read = read(binder->public_fd,
(void*)(gsize)(wr->read_buffer + wr->read_consumed),
wr->read_size - wr->read_consumed);
}
is_looper = g_private_get(&test_looper) ? TRUE : FALSE;
if (binder->looper_enabled || !is_looper) {
/* Now read the data from the socket */
int bytes_available = 0;
int err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
if (bytes_read >= 0) {
wr->read_consumed += bytes_read;
return 0;
} else {
err = bytes_read;
if (err >= 0) {
int bytes_read = 0;
if (bytes_available >= 4) {
bytes_read = read(binder->public_fd,
(void*)(gsize)(wr->read_buffer + wr->read_consumed),
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 = {
@@ -274,6 +431,17 @@ test_io_destroy_none(
GDEBUG("Not freeing %p", data);
}
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,
@@ -291,43 +459,35 @@ test_binder_set_destroy(
}
static
gboolean
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);
if (binder) {
const guint32* cmd = data;
const int len = sizeof(*cmd) + _IOC_SIZE(*cmd);
return write(binder->private_fd, data, len) == len;
g_assert(binder);
if (!binder->submit_thread) {
binder->submit_thread = test_binder_submit_thread_new(binder);
}
return FALSE;
test_binder_submit_later(binder->submit_thread, data);
}
static
void
test_binder_fill_transaction_data(
BinderTransactionData64* tr,
guint64 handle,
guint32 code,
const GByteArray* bytes)
{
g_assert(bytes);
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
test_binder_push_ptr_cookie(
int fd,
guint32 cmd,
@@ -339,60 +499,69 @@ test_binder_push_ptr_cookie(
memcpy(buf, &cmd, sizeof(cmd));
memset(data, 0, sizeof(*data));
data->ptr = (gsize)ptr;
return test_binder_push_data(fd, buf);
test_binder_push_data(fd, buf);
}
gboolean
void
test_binder_br_noop(
int fd)
{
guint32 cmd = BR_NOOP;
return test_binder_push_data(fd, &cmd);
test_binder_push_data(fd, &cmd);
}
gboolean
void
test_binder_br_increfs(
int fd,
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(
int fd,
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(
int fd,
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(
int fd,
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(
int fd)
{
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(
int fd,
guint handle)
@@ -403,28 +572,47 @@ test_binder_br_dead_binder(
buf[0] = BR_DEAD_BINDER_64;
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(
int fd)
{
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(
int fd)
{
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(
int fd,
void* target,
@@ -438,15 +626,17 @@ test_binder_br_transaction(
test_binder_fill_transaction_data((void*)(buf + sizeof(cmd)),
(gsize)target, code, bytes);
return test_binder_push_data(fd, buf);
test_binder_push_data(fd, buf);
}
gboolean
test_binder_br_reply(
static
void
test_binder_br_reply1(
int fd,
guint32 handle,
guint32 code,
const GByteArray* bytes)
const GByteArray* bytes,
TestBinderPushDataFunc push)
{
guint32 cmd = BR_REPLY_64;
guint8 buf[sizeof(guint32) + sizeof(BinderTransactionData64)];
@@ -455,13 +645,34 @@ test_binder_br_reply(
test_binder_fill_transaction_data((void*)(buf + sizeof(cmd)),
handle, code, bytes);
return test_binder_push_data(fd, buf);
push(fd, buf);
}
gboolean
test_binder_br_reply_status(
void
test_binder_br_reply(
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)];
guint32* cmd = (void*)buf;
@@ -473,7 +684,24 @@ test_binder_br_reply_status(
tr->data_size = sizeof(status);
/* This memory should eventually get deallocated with BC_FREE_BUFFER_64 */
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
@@ -532,6 +760,7 @@ gbinder_system_close(
g_hash_table_unref(test_fd_map);
test_fd_map = NULL;
}
test_binder_submit_thread_free(binder->submit_thread);
test_binder_node_unref(binder->node);
close(binder->public_fd);
close(binder->private_fd);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -35,66 +35,87 @@
#include "test_common.h"
gboolean
void
test_binder_br_noop(
int fd);
gboolean
void
test_binder_br_increfs(
int fd,
void* ptr);
gboolean
void
test_binder_br_acquire(
int fd,
void* ptr);
gboolean
void
test_binder_br_release(
int fd,
void* ptr);
gboolean
void
test_binder_br_decrefs(
int fd,
void* ptr);
gboolean
void
test_binder_br_transaction_complete(
int fd);
gboolean
void
test_binder_br_transaction_complete_later(
int fd);
void
test_binder_br_dead_binder(
int fd,
guint handle);
gboolean
void
test_binder_br_dead_reply(
int fd);
gboolean
void
test_binder_br_failed_reply(
int fd);
gboolean
void
test_binder_br_transaction(
int fd,
void* target,
guint32 code,
const GByteArray* bytes);
gboolean
void
test_binder_br_reply(
int fd,
guint32 handle,
guint32 code,
const GByteArray* bytes);
gboolean
void
test_binder_br_reply_status(
int fd,
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,

View File

@@ -5,6 +5,7 @@
TESTS="\
unit_buffer \
unit_cleanup \
unit_client \
unit_driver \
unit_ipc \
@@ -16,6 +17,9 @@ unit_reader \
unit_remote_object \
unit_remote_reply \
unit_remote_request \
unit_servicemanager \
unit_servicename \
unit_servicepoll \
unit_writer"
function err() {

View File

@@ -47,19 +47,21 @@ test_null(
void)
{
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;
gsize size = 1;
gbinder_buffer_free(buf);
/* 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));
gbinder_buffer_free(buf);
buf = gbinder_buffer_new_with_parent(NULL, 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(buf2));
gbinder_buffer_free(buf);
@@ -67,6 +69,7 @@ test_null(
gbinder_buffer_free(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));
@@ -87,14 +90,14 @@ test_parent(
void* ptr = g_memdup(data, sizeof(data));
gsize size = 0;
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderBuffer* parent = gbinder_buffer_new(driver, ptr, sizeof(data));
GBinderBuffer* parent = gbinder_buffer_new(driver, ptr, sizeof(data), NULL);
GBinderBuffer* buf = gbinder_buffer_new_with_parent
(parent, ptr, sizeof(data));
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_memory(buf));
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));

View File

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

View 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:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -74,16 +74,15 @@ void
test_null(
void)
{
GBinderClient* null = NULL;
g_assert(!gbinder_client_new(NULL, NULL));
g_assert(!gbinder_client_ref(null));
gbinder_client_unref(null);
g_assert(!gbinder_client_ref(NULL));
g_assert(!gbinder_client_interface(NULL));
gbinder_client_unref(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_oneway(null, 0, NULL) == (-EINVAL));
g_assert(!gbinder_client_transact(null, 0, 0, NULL, NULL, NULL, NULL));
gbinder_client_cancel(null, 0);
g_assert(!gbinder_client_transact_sync_reply(NULL, 0, NULL, NULL));
g_assert(gbinder_client_transact_sync_oneway(NULL, 0, NULL) == (-EINVAL));
g_assert(!gbinder_client_transact(NULL, 0, 0, NULL, NULL, NULL, NULL));
gbinder_client_cancel(NULL, 0);
}
/*==========================================================================*
@@ -98,11 +97,12 @@ test_basic(
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
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(gbinder_client_ref(client) == client);
g_assert(!g_strcmp0(gbinder_client_interface(client), iface));
gbinder_client_unref(client);
gbinder_client_cancel(client, 0); /* does nothing */
@@ -111,6 +111,63 @@ test_basic(
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);
}
/*==========================================================================*
* sync_oneway
*==========================================================================*/
@@ -164,10 +221,10 @@ test_sync_reply_tx(
data = gbinder_local_reply_data(reply);
g_assert(data);
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply(fd, handle, code, data->bytes);
tx_reply = gbinder_client_transact_sync_reply(client, 0, req, &status);
g_assert(tx_reply);
@@ -265,10 +322,10 @@ test_reply_tx(
data = gbinder_local_reply_data(reply);
g_assert(data);
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply(fd, handle, code, data->bytes);
id = gbinder_client_transact(client, 0, 0, req, done, destroy, loop);
g_assert(id);
@@ -326,17 +383,20 @@ test_reply_ok3(
*==========================================================================*/
#define TEST_PREFIX "/client/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, 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 "sync_oneway", test_sync_oneway);
g_test_add_func(TEST_PREFIX "sync_reply", test_sync_reply);
g_test_add_func(TEST_PREFIX "reply/ok1", test_reply_ok1);
g_test_add_func(TEST_PREFIX "reply/ok2", test_reply_ok2);
g_test_add_func(TEST_PREFIX "reply/ok3", test_reply_ok3);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("dead"), test_dead);
g_test_add_func(TEST_("no_header"), test_no_header);
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);
g_test_add_func(TEST_("sync_reply"), test_sync_reply);
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);
return g_test_run();
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -91,7 +91,7 @@ test_noop(
g_assert(driver);
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_read(driver, NULL, NULL) == 0);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -52,6 +52,24 @@
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
*==========================================================================*/
@@ -111,6 +129,46 @@ test_basic(
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);
}
/*==========================================================================*
* sync_oneway
*==========================================================================*/
@@ -125,7 +183,7 @@ test_sync_oneway(
const int fd = gbinder_driver_fd(ipc->driver);
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) ==
GBINDER_STATUS_OK);
gbinder_local_request_unref(req);
@@ -157,10 +215,10 @@ test_sync_reply_ok_status(
data = gbinder_local_reply_data(reply);
g_assert(data);
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply(fd, handle, code, data->bytes);
tx_reply = gbinder_ipc_transact_sync_reply(ipc, handle, code, req, status);
g_assert(tx_reply);
@@ -205,10 +263,10 @@ test_sync_reply_error(
const gint expected_status = GBINDER_STATUS_FAILED;
int status = INT_MAX;
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply_status(fd, expected_status));
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply_status(fd, expected_status);
g_assert(!gbinder_ipc_transact_sync_reply(ipc, handle, code, req, &status));
g_assert(status == expected_status);
@@ -268,10 +326,10 @@ test_transact_ok(
data = gbinder_local_reply_data(reply);
g_assert(data);
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply(fd, handle, code, data->bytes);
id = gbinder_ipc_transact(ipc, handle, code, 0, req,
test_transact_ok_done, test_transact_ok_destroy, loop);
@@ -317,8 +375,8 @@ test_transact_dead(
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_dead_reply(fd));
test_binder_br_noop(fd);
test_binder_br_dead_reply(fd);
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_dead_done,
NULL, loop);
@@ -363,8 +421,8 @@ test_transact_failed(
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_failed_reply(fd));
test_binder_br_noop(fd);
test_binder_br_failed_reply(fd);
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_failed_done,
NULL, loop);
@@ -411,8 +469,8 @@ test_transact_status(
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply_status(fd, EXPECTED_STATUS));
test_binder_br_noop(fd);
test_binder_br_reply_status(fd, EXPECTED_STATUS);
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_status_done,
NULL, loop);
@@ -606,24 +664,6 @@ test_transact_incoming_proc(
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
void
test_transact_incoming(
@@ -634,9 +674,10 @@ test_transact_incoming(
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_ipc_new_local_object
(ipc, "test", test_transact_incoming_proc, loop);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_incoming_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
@@ -647,21 +688,22 @@ test_transact_incoming(
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_transact_done, loop);
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_transact_unref_ipc, ipc);
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_incoming_status
* transact_status_reply
*==========================================================================*/
static
@@ -695,9 +737,10 @@ test_transact_status_reply(
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_ipc_new_local_object
(ipc, "test", test_transact_status_reply_proc, loop);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_status_reply_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
@@ -708,14 +751,193 @@ test_transact_status_reply(
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_transact_done, loop);
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_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);
g_main_loop_unref(loop);
@@ -726,26 +948,29 @@ test_transact_status_reply(
*==========================================================================*/
#define TEST_PREFIX "/ipc/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, 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 "sync_oneway", test_sync_oneway);
g_test_add_func(TEST_PREFIX "sync_reply_ok", test_sync_reply_ok);
g_test_add_func(TEST_PREFIX "sync_reply_error", test_sync_reply_error);
g_test_add_func(TEST_PREFIX "transact_ok", test_transact_ok);
g_test_add_func(TEST_PREFIX "transact_dead", test_transact_dead);
g_test_add_func(TEST_PREFIX "transact_failed", test_transact_failed);
g_test_add_func(TEST_PREFIX "transact_status", test_transact_status);
g_test_add_func(TEST_PREFIX "transact_custom", test_transact_custom);
g_test_add_func(TEST_PREFIX "transact_custom2", test_transact_custom2);
g_test_add_func(TEST_PREFIX "transact_cancel", test_transact_cancel);
g_test_add_func(TEST_PREFIX "transact_cancel2", test_transact_cancel2);
g_test_add_func(TEST_PREFIX "transact_incoming", test_transact_incoming);
g_test_add_func(TEST_PREFIX "transact_status_reply",
test_transact_status_reply);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("async_oneway"), test_async_oneway);
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);
g_test_add_func(TEST_("sync_reply_ok"), test_sync_reply_ok);
g_test_add_func(TEST_("sync_reply_error"), test_sync_reply_error);
g_test_add_func(TEST_("transact_ok"), test_transact_ok);
g_test_add_func(TEST_("transact_dead"), test_transact_dead);
g_test_add_func(TEST_("transact_failed"), test_transact_failed);
g_test_add_func(TEST_("transact_status"), test_transact_status);
g_test_add_func(TEST_("transact_custom"), test_transact_custom);
g_test_add_func(TEST_("transact_custom2"), test_transact_custom2);
g_test_add_func(TEST_("transact_cancel"), test_transact_cancel);
g_test_add_func(TEST_("transact_cancel2"), test_transact_cancel2);
g_test_add_func(TEST_("transact_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);
return g_test_run();
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -73,7 +73,8 @@ test_reader_data_init_for_reply(
GUtilIntArray* offsets = gbinder_output_data_offsets(out);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
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));
data->buffer = buf;
@@ -149,6 +150,8 @@ void
test_basic(
void)
{
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);
GBinderLocalObject* foo;
@@ -158,8 +161,8 @@ test_basic(
g_assert(!gbinder_object_registry_get_local(reg, ipc));
/* Create a new local objects */
foo = gbinder_ipc_new_local_object(ipc, "foo", NULL, NULL);
bar = gbinder_ipc_new_local_object(ipc, "bar", NULL, NULL);
foo = gbinder_local_object_new(ipc, ifaces_foo, NULL, NULL);
bar = gbinder_local_object_new(ipc, ifaces_bar, NULL, NULL);
/* But ipc is still not a local object! */
g_assert(!gbinder_object_registry_get_local(reg, ipc));
@@ -186,6 +189,150 @@ test_basic(
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
*==========================================================================*/
@@ -195,21 +342,19 @@ void
test_get_descriptor(
void)
{
static const guint8 req_data [] = {
TEST_BASE_INTERFACE_HEADER_BYTES
};
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_ipc_new_local_object(ipc, NULL, NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
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_GET_DESCRIPTOR_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
@@ -255,16 +400,18 @@ test_descriptor_chain(
};
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* reply_data;
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
gbinder_remote_request_set_data(req, HIDL_DESCRIPTOR_CHAIN_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_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
@@ -279,6 +426,11 @@ test_descriptor_chain(
g_assert(reply);
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_local_object_unref(obj);
gbinder_local_reply_unref(reply);
@@ -320,13 +472,14 @@ test_custom_iface(
void)
{
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
const char* const ifaces[] = { custom_iface, NULL };
int count = 0, status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
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);
GBinderLocalReply* reply;
GBinderReaderData reader_data;
@@ -334,8 +487,9 @@ test_custom_iface(
char** strv;
char* str;
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
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(gbinder_local_object_can_handle_transaction(obj, base_interface,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
g_assert(gbinder_local_object_can_handle_transaction(obj, custom_iface,
@@ -425,17 +579,19 @@ test_reply_status(
void)
{
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
const char* const ifaces[] = { custom_iface, NULL };
int count = 0, status = 0;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
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);
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
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));
/* Execute the custom transaction */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
@@ -469,7 +625,7 @@ test_increfs(
void)
{
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);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
@@ -479,7 +635,7 @@ test_increfs(
/* ipc is not an object, will be ignored */
test_binder_br_increfs(fd, ipc);
test_binder_br_increfs(fd, obj);
test_binder_set_looper_enabled(fd, TRUE);
test_run(&test_opt, loop);
g_assert(obj->weak_refs == 1);
@@ -511,7 +667,7 @@ test_decrefs(
void)
{
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);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
@@ -522,7 +678,7 @@ test_decrefs(
test_binder_br_decrefs(fd, ipc);
test_binder_br_increfs(fd, obj);
test_binder_br_decrefs(fd, obj);
test_binder_set_looper_enabled(fd, TRUE);
test_run(&test_opt, loop);
g_assert(obj->weak_refs == 0);
@@ -553,7 +709,7 @@ test_acquire(
void)
{
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);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
@@ -563,7 +719,7 @@ test_acquire(
/* ipc is not an object, will be ignored */
test_binder_br_acquire(fd, ipc);
test_binder_br_acquire(fd, obj);
test_binder_set_looper_enabled(fd, TRUE);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 1);
@@ -595,8 +751,7 @@ test_release(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(ipc, NULL, NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
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_acquire(fd, obj);
test_binder_br_release(fd, obj);
test_binder_set_looper_enabled(fd, TRUE);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 0);
@@ -627,6 +782,9 @@ int main(int argc, char* argv[])
g_test_init(&argc, &argv, 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 "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 "descriptor_chain", test_descriptor_chain);
g_test_add_func(TEST_PREFIX "custom_iface", test_custom_iface);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -67,7 +67,7 @@ test_buffer_from_bytes(
{
/* Prevent double free */
test_binder_set_destroy(gbinder_driver_fd(driver), bytes->data, NULL);
return gbinder_buffer_new(driver, bytes->data, bytes->len);
return gbinder_buffer_new(driver, bytes->data, bytes->len, NULL);
}
/*==========================================================================*
@@ -88,7 +88,7 @@ test_null(
gbinder_local_reply_init_writer(NULL, NULL);
gbinder_local_reply_init_writer(NULL, &writer);
g_assert(!gbinder_local_reply_data(NULL));
g_assert(!gbinder_local_reply_new_from_data(NULL, NULL));
g_assert(!gbinder_local_reply_new_from_data(NULL));
gbinder_local_reply_cleanup(NULL, NULL, &count);
gbinder_local_reply_cleanup(NULL, test_int_inc, &count);
@@ -359,7 +359,7 @@ test_hidl_string(
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
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);
gbinder_local_reply_unref(reply);
}
@@ -382,7 +382,7 @@ test_hidl_string_vec(
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
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);
gbinder_local_reply_unref(reply);
}
@@ -400,8 +400,8 @@ test_local_object(
GBinderOutputData* data;
GUtilIntArray* offsets;
GBinderIpc* ipc = gbinder_ipc_new(NULL, NULL);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, "foo", NULL, NULL);
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", 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) */
reply = gbinder_local_object_new_reply(obj);
@@ -479,7 +479,7 @@ test_remote_reply(
/* Copy flat structures (no binder objects) */
buffer = test_buffer_from_bytes(driver, bytes);
req2 = gbinder_local_reply_new_from_data(buffer, NULL);
req2 = gbinder_local_reply_new_from_data(buffer);
gbinder_buffer_free(buffer);
data2 = gbinder_local_reply_data(req2);

View File

@@ -65,7 +65,19 @@ test_buffer_from_bytes(
{
/* Prevent double free */
test_binder_set_destroy(gbinder_driver_fd(driver), bytes->data, NULL);
return gbinder_buffer_new(driver, bytes->data, bytes->len);
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);
}
/*==========================================================================*
@@ -82,7 +94,7 @@ test_null(
g_assert(!gbinder_local_request_new(NULL, NULL));
g_assert(!gbinder_local_request_ref(NULL));
g_assert(!gbinder_local_request_new_from_data(NULL, NULL));
g_assert(!gbinder_local_request_new_from_data(NULL));
gbinder_local_request_unref(NULL);
gbinder_local_request_init_writer(NULL, NULL);
gbinder_local_request_init_writer(NULL, &writer);
@@ -375,7 +387,7 @@ test_hidl_string(
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
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);
gbinder_local_request_unref(req);
}
@@ -398,7 +410,7 @@ test_hidl_string_vec(
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
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);
gbinder_local_request_unref(req);
}
@@ -471,14 +483,14 @@ test_remote_request(
const GByteArray* bytes;
const GByteArray* bytes2;
GBinderBuffer* buffer;
void* no_obj = NULL;
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, NULL);
req2 = gbinder_local_request_new_from_data(buffer);
gbinder_buffer_free(buffer);
data2 = gbinder_local_request_data(req2);
@@ -490,8 +502,8 @@ test_remote_request(
gbinder_local_request_unref(req2);
/* Same thing but with non-NULL (albeit empty) array of objects */
buffer = test_buffer_from_bytes(driver, bytes);
req2 = gbinder_local_request_new_from_data(buffer, &no_obj);
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);
@@ -525,8 +537,9 @@ test_remote_request_obj_validate_data(
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);
/* HidlString + the contents (2 bytes) aligned at 8-byte boundary */
g_assert(gbinder_output_data_buffers_size(data) == (sizeof(HidlString)+8));
/* GBinderHidlString + the contents (2 bytes) aligned at 8-byte boundary */
g_assert(gbinder_output_data_buffers_size(data) ==
(sizeof(GBinderHidlString) + 8));
}
static
@@ -558,15 +571,15 @@ test_remote_request_obj(
objects[i] = bytes->data + offsets->data[i];
}
buffer = test_buffer_from_bytes(driver, data->bytes);
req2 = gbinder_local_request_new_from_data(buffer, objects);
buffer = test_buffer_from_bytes_and_objects(driver, data->bytes, objects);
req2 = gbinder_local_request_new_from_data(buffer);
gbinder_buffer_free(buffer);
g_free(objects);
test_remote_request_obj_validate_data(gbinder_local_request_data(req2));
gbinder_local_request_unref(req);
/* req2 has to be freed first because req owns data */
gbinder_local_request_unref(req2);
gbinder_local_request_unref(req);
gbinder_driver_unref(driver);
}

View File

@@ -91,22 +91,44 @@ test_device(
}
/*==========================================================================*
* no_header
* no_header1
*==========================================================================*/
static
void
test_no_header(
test_no_header1(
void)
{
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
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));
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
*==========================================================================*/
@@ -144,38 +166,39 @@ test_read_header(
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
gbinder_rpc_protocol_for_device(test->dev), 0, 0);
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
g_memdup(test->header, test->header_size), test->header_size), NULL);
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
gbinder_buffer_new(driver, g_memdup(test->header, test->header_size),
test->header_size, NULL));
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), test->iface));
gbinder_remote_request_unref(req);
gbinder_driver_unref(driver);
}
/*==========================================================================*
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/protocol/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
guint i;
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "device", test_device);
g_test_add_func(TEST_PREFIX "no_header", test_no_header);
g_test_add_func(TEST_("device"), test_device);
g_test_add_func(TEST_("no_header1"), test_no_header1);
g_test_add_func(TEST_("no_header2"), test_no_header2);
for (i = 0; i < G_N_ELEMENTS(test_header_tests); i++) {
const TestHeaderData* test = test_header_tests + i;
char* path = g_strconcat(TEST_PREFIX, "/", test->name,
"/read_header", NULL);
char* path;
path = g_strconcat(TEST_PREFIX, test->name, "/read_header", NULL);
g_test_add_data_func(path, test, test_read_header);
g_free(path);
path = g_strconcat(TEST_PREFIX, "/", test->name,
"/write_header", NULL);
path = g_strconcat(TEST_PREFIX, test->name, "/write_header", NULL);
g_test_add_data_func(path, test, test_write_header);
g_free(path);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -50,8 +50,9 @@ void
test_null(
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_ipc(NULL));
gbinder_remote_object_unref(NULL);
g_assert(gbinder_remote_object_is_dead(NULL));
g_assert(!gbinder_remote_object_add_death_handler(NULL, NULL, NULL));
@@ -76,11 +77,14 @@ test_basic(
g_assert(obj2);
g_assert(obj1->handle == 1u);
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_reanimate(obj1));
g_assert(gbinder_remote_object_ref(obj1) == obj1);
gbinder_remote_object_unref(obj1); /* Compensate the above reference */
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);
gbinder_remote_object_unref(obj2);
@@ -109,11 +113,14 @@ test_dead(
const guint handle = 1;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
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
(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);
g_assert(gbinder_remote_object_is_dead(obj));

View File

@@ -59,7 +59,7 @@ test_null(
g_assert(!gbinder_remote_reply_ref(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);
g_assert(gbinder_reader_at_end(&reader));
g_assert(gbinder_remote_reply_is_empty(NULL));
@@ -85,8 +85,8 @@ test_empty(
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
gbinder_remote_reply_set_data
(reply, gbinder_buffer_new(driver, NULL, 0), NULL);
gbinder_remote_reply_set_data(reply,
gbinder_buffer_new(driver, NULL, 0, NULL));
g_assert(gbinder_remote_reply_is_empty(reply));
gbinder_remote_reply_unref(reply);
@@ -132,8 +132,7 @@ test_int32(
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
NULL);
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
g_assert(!gbinder_remote_reply_is_empty(reply));
g_assert(gbinder_remote_reply_read_uint32(reply, &out1));
@@ -163,8 +162,7 @@ test_int64(
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
NULL);
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
g_assert(!gbinder_remote_reply_is_empty(reply));
g_assert(gbinder_remote_reply_read_uint64(reply, &out1));
@@ -192,8 +190,7 @@ test_string8(
GBinderRemoteReply* reply = gbinder_remote_reply_new(NULL);
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
NULL);
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
g_assert(!gbinder_remote_reply_is_empty(reply));
g_assert(!g_strcmp0(gbinder_remote_reply_read_string8(reply), "bar"));
@@ -221,8 +218,7 @@ test_string16(
char* str;
gbinder_remote_reply_set_data(reply, gbinder_buffer_new(driver,
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data)),
NULL);
g_memdup(reply_data, sizeof(reply_data)), sizeof(reply_data), NULL));
g_assert(!gbinder_remote_reply_is_empty(reply));
str = gbinder_remote_reply_read_string16(reply);
@@ -264,7 +260,7 @@ test_to_local(
/* 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);
sizeof(reply_data), objects));
/* Convert to GBinderLocalReply */
req2 = gbinder_remote_reply_copy_to_local(req);

View File

@@ -71,8 +71,10 @@ test_null(
g_assert(!gbinder_remote_request_ref(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_block(NULL);
gbinder_remote_request_complete(NULL, NULL, 0);
g_assert(gbinder_reader_at_end(&reader));
g_assert(!gbinder_remote_request_interface(NULL));
g_assert(!gbinder_remote_request_copy_to_local(NULL));
@@ -100,6 +102,10 @@ test_basic(
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
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);
g_assert(gbinder_reader_at_end(&reader));
g_assert(!gbinder_remote_request_interface(req));
@@ -118,7 +124,7 @@ void
test_int32(
void)
{
static const guint8 request_data [] = {
static const guint8 req_data [] = {
TEST_RPC_HEADER,
TEST_INT32_BYTES(42)
};
@@ -129,9 +135,9 @@ test_int32(
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
gbinder_rpc_protocol_for_device(dev), 0, 0);
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
NULL);
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
sizeof(req_data), NULL));
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
g_assert(gbinder_remote_request_read_uint32(req, &out1));
@@ -152,7 +158,7 @@ void
test_int64(
void)
{
static const guint8 request_data [] = {
static const guint8 req_data [] = {
TEST_RPC_HEADER,
TEST_INT64_BYTES(42)
};
@@ -163,9 +169,9 @@ test_int64(
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
gbinder_rpc_protocol_for_device(dev), 0, 0);
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
NULL);
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
sizeof(req_data), NULL));
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
g_assert(gbinder_remote_request_read_uint64(req, &out1));
@@ -186,7 +192,7 @@ void
test_string8(
void)
{
static const guint8 request_data [] = {
static const guint8 req_data [] = {
TEST_RPC_HEADER,
'b', 'a', 'r', 0x00
};
@@ -195,9 +201,9 @@ test_string8(
GBinderRemoteRequest* req = gbinder_remote_request_new(NULL,
gbinder_rpc_protocol_for_device(dev), 0, 0);
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
NULL);
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
sizeof(req_data), NULL));
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "bar"));
@@ -215,7 +221,7 @@ void
test_string16(
void)
{
static const guint8 request_data [] = {
static const guint8 req_data [] = {
TEST_RPC_HEADER,
TEST_INT32_BYTES(3),
TEST_INT16_BYTES('b'), TEST_INT16_BYTES('a'),
@@ -227,9 +233,9 @@ test_string16(
gbinder_rpc_protocol_for_device(dev), 0, 0);
char* str;
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver,
g_memdup(request_data, sizeof(request_data)), sizeof(request_data)),
NULL);
gbinder_remote_request_set_data(req, GBINDER_FIRST_CALL_TRANSACTION,
gbinder_buffer_new(driver, g_memdup(req_data, sizeof(req_data)),
sizeof(req_data), NULL));
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), TEST_RPC_IFACE));
str = gbinder_remote_request_read_string16(req);
@@ -272,8 +278,8 @@ test_to_local(
/* Skip the 32-bit integer */
objects[0] = req_data + 4;
gbinder_remote_request_set_data(req, gbinder_buffer_new(driver, req_data,
sizeof(request_data)), objects);
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));

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View 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:
*/

View File

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

View 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:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -39,6 +39,8 @@
#include <gutil_intarray.h>
#include <unistd.h>
static TestOpt test_opt;
#define BUFFER_OBJECT_SIZE_32 (24)
@@ -74,8 +76,10 @@ test_null(
gbinder_writer_append_string16(&writer, NULL);
gbinder_writer_append_string16_len(NULL, 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(&writer, FALSE);
gbinder_writer_append_fd(NULL, 0);
gbinder_writer_append_bytes(NULL, NULL, 0);
gbinder_writer_append_bytes(&writer, NULL, 0);
gbinder_writer_append_hidl_vec(NULL, NULL, 0, 0);
@@ -93,9 +97,51 @@ test_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_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);
}
/*==========================================================================*
@@ -119,6 +165,19 @@ test_int32(
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == sizeof(value));
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);
}
@@ -342,6 +401,75 @@ test_string16(
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
*==========================================================================*/
@@ -366,15 +494,15 @@ static guint test_hidl_vec_offsets_64[] =
static const TestHidlVecData test_hidl_vec_tests[] = {
{ "32/null", &gbinder_io_32, NULL, 0, 0,
TEST_ARRAY_AND_COUNT(test_hidl_vec_offsets_0), sizeof(HidlVec) },
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(HidlVec) + 8 /* vec data aligned at 8 bytes boundary */ },
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(HidlVec) },
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(HidlVec) + 8 /* vec data aligned at 8 bytes boundary */ }
sizeof(GBinderHidlVec) + 8 /* vec data aligned at 8 bytes boundary */ }
};
static
@@ -425,15 +553,17 @@ static guint test_hidl_string_offsets_64[] =
static const TestHidlStringData test_hidl_string_tests[] = {
{ "32/null", &gbinder_io_32, NULL,
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0), sizeof(HidlString) },
TEST_ARRAY_AND_COUNT(test_hidl_string_offsets_0),
sizeof(GBinderHidlString) },
{ "32/xxx", &gbinder_io_32, "xxx",
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,
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",
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
@@ -481,8 +611,9 @@ test_hidl_string2(
g_assert(offsets->data[0] == 0);
g_assert(offsets->data[1] == BUFFER_OBJECT_SIZE_32);
g_assert(offsets->data[2] == 2*BUFFER_OBJECT_SIZE_32);
/* 2 HidlStrings + "foo" aligned at 8 bytes boundary */
g_assert(gbinder_output_data_buffers_size(data) == 2*sizeof(HidlString)+8);
/* 2 GBinderHidlStrings + "foo" aligned at 8 bytes boundary */
g_assert(gbinder_output_data_buffers_size(data) ==
(2 * sizeof(GBinderHidlString) + 8));
gbinder_local_request_unref(req);
}
@@ -513,18 +644,18 @@ static guint test_hidl_string_vec_offsets_1_64[] =
static const TestHidlStringVecData test_hidl_string_vec_tests[] = {
{ "32/null", &gbinder_io_32, NULL, -1,
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
sizeof(HidlVec) },
sizeof(GBinderHidlVec) },
{ "32/1", &gbinder_io_32,
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_32),
sizeof(HidlVec) + sizeof(HidlString) + 8 },
sizeof(GBinderHidlVec) + sizeof(GBinderHidlString) + 8 },
{ "64/null", &gbinder_io_64, NULL, -1,
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_empty),
sizeof(HidlVec) },
sizeof(GBinderHidlVec) },
{ "64/1", &gbinder_io_64,
(const char**)TEST_ARRAY_AND_COUNT(test_hidl_string_vec_data_1),
TEST_ARRAY_AND_COUNT(test_hidl_string_vec_offsets_1_64),
sizeof(HidlVec) + sizeof(HidlString) + 8 },
sizeof(GBinderHidlVec) + sizeof(GBinderHidlString) + 8 },
};
static
@@ -633,6 +764,76 @@ test_parent(
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
*==========================================================================*/
@@ -737,46 +938,76 @@ test_byte_array(
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
*==========================================================================*/
#define TEST_PREFIX "/writer/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
guint i;
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "null", test_null);
g_test_add_func(TEST_PREFIX "int32", test_int32);
g_test_add_func(TEST_PREFIX "int64", test_int64);
g_test_add_func(TEST_PREFIX "float", test_float);
g_test_add_func(TEST_PREFIX "double", test_double);
g_test_add_func(TEST_PREFIX "bool", test_bool);
g_test_add_func(TEST_PREFIX "bytes", test_bytes);
g_test_add_func(TEST_PREFIX "string8", test_string8);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("cleanup"), test_cleanup);
g_test_add_func(TEST_("int32"), test_int32);
g_test_add_func(TEST_("int64"), test_int64);
g_test_add_func(TEST_("float"), test_float);
g_test_add_func(TEST_("double"), test_double);
g_test_add_func(TEST_("bool"), test_bool);
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++) {
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_free(path);
}
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_PREFIX "hidl_vec/", test->name, NULL);
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_PREFIX "hidl_string/2strings", test_hidl_string2);
g_test_add_func(TEST_("hidl_string/2strings"), test_hidl_string2);
for (i = 0; i < G_N_ELEMENTS(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_free(path);
@@ -784,18 +1015,21 @@ int main(int argc, char* argv[])
for (i = 0; i < G_N_ELEMENTS(test_hidl_string_vec_tests); i++) {
const TestHidlStringVecData* test = test_hidl_string_vec_tests + i;
char* path = g_strconcat(TEST_PREFIX "hidl_string_vec/",
test->name, NULL);
char* path = g_strconcat(TEST_("hidl_string_vec/"), test->name, NULL);
g_test_add_data_func(path, test, test_hidl_string_vec);
g_free(path);
}
g_test_add_func(TEST_PREFIX "buffer", test_buffer);
g_test_add_func(TEST_PREFIX "parent", test_parent);
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 "byte_array", test_byte_array);
g_test_add_func(TEST_("buffer"), test_buffer);
g_test_add_func(TEST_("parent"), test_parent);
g_test_add_func(TEST_("fd"), test_fd);
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);
return g_test_run();
}