Compare commits

...

121 Commits

Author SHA1 Message Date
Slava Monich
885d27c12c Version 1.1.31 2023-01-04 19:14:49 +02:00
Slava Monich
38f156a8ba Merge pull request #110 from monich/binder-test
Refactor binder simulation used by unit tests
2023-01-04 19:02:48 +02:00
Slava Monich
d7eacd455f [unit] Refactored binder simulation. JB#42956
The old one was way too hackish and prone to race conditions.
This one is more accurate and hopefully more reliable.
2023-01-04 14:42:19 +02:00
Slava Monich
b1a3dc5c64 [gbinder] Improved handling of multiple gbinder_ipc_exit() calls
Needed primarily for unit testing.
2023-01-03 12:49:04 +02:00
Slava Monich
98ad09e803 Merge pull request #112 from monich/big-endian
Fix serialization issues on big-endian systems
2023-01-03 12:42:44 +02:00
Slava Monich
c94ccbd8bf [gbinder] Fixed serialization issues on big-endian. JB#42956
Note that libhwbinder and libbinder encode TRUE value differently
on big-endian machines (0x01 becomes either first or last of 4 bytes)
but reading uint32 and comparing it with zero works in either case.
2023-01-03 01:56:18 +02:00
Slava Monich
5874c88559 Version 1.1.30 2022-12-04 19:51:04 +02:00
Slava Monich
b0c3b6017f Merge pull request #109 from monich/ptr_cookie
Fix return value from binder_ptr_cookie encoder
2022-12-04 19:46:23 +02:00
Slava Monich
4f82e82081 [gbinder] Fix return value from binder_ptr_cookie encoder. JB#42956
It was resulting in broken BC_ACQUIRE_DONE commands being sent to
the driver. That's not nice.
2022-12-04 19:41:24 +02:00
Slava Monich
51eefbf566 Version 1.1.29 2022-11-25 00:03:04 +02:00
Slava Monich
ec76cb3930 Merge pull request #106 from monich/vec
gbinder_writer_append_struct_vec
2022-11-24 23:41:11 +02:00
Slava Monich
9a0d0a7894 [gbinder] Added gbinder_writer_append_struct_vec(). JB#42956
Appends top-level vec<type>. Allocates GBinderHidlVec for that,
but unlike gbinder_writer_append_hidl_vec(), doesn't copy the
contents of the vector.
2022-11-24 19:48:24 +02:00
Slava Monich
32b3d4455a Version 1.1.28 2022-11-22 18:22:37 +02:00
Slava Monich
09e9a9d5c1 Merge pull request #103 from monich/minus
Allow to pass negative number as a parameter
2022-11-22 18:12:34 +02:00
Slava Monich
83b04757c6 Merge pull request #105 from monich/pie
Compile executables with -fPIE
2022-11-22 18:12:09 +02:00
Slava Monich
c636814500 [test] Compile executables with -fPIE. JB#42956 2022-11-20 18:02:58 +02:00
Slava Monich
2592ea60ce Merge pull request #104 from monich/spec
Tweak the spec file
2022-11-20 05:18:12 +02:00
Slava Monich
f04e21b462 [packaging] Tweak the spec file. JB#42956
1. Some packaging guides suggest not to do rm -rf %{buildroot}
2. Own the directory containing the header files, not just the files
2022-11-20 01:17:19 +02:00
Slava Monich
d739912faa [binder-call] Allow to pass negative number as a parameter. JB#59412
Note that the user would have to use  "--" flag to stop GOptionContext
from parsing negative numbers as command line options.
2022-11-19 21:48:54 +02:00
Slava Monich
c2263874ec [binder-call] Removed unused app_options field 2022-11-19 21:43:32 +02:00
Slava Monich
aa23e44677 Version 1.1.27 2022-11-17 03:26:48 +02:00
Slava Monich
ca38c15d3c Merge pull request #102 from monich/append-struct
Convenience API for writing nested structures
2022-11-17 03:20:33 +02:00
Slava Monich
6f9220aedb [gbinder] Added gbinder_writer_append_struct(). JB#42956
It simplifies writing buffers for nested structures.
2022-11-17 03:19:33 +02:00
Slava Monich
eafec68ff8 Verision 1.1.26 2022-10-14 16:49:58 +03:00
Slava Monich
0dc84b0748 Merge pull request #100 from monich/stability
All binder objects need stability field in Android 11
2022-10-14 16:39:53 +03:00
Slava Monich
f227ae4291 [gbinder] All binder objects need stability field in Android 11. JB#58951
According to Parcel::finishFlattenBinder() in native/libs/binder/Parcel.cpp
2022-10-14 16:16:19 +03:00
Slava Monich
b14b68717f Merge pull request #99 from monich/null
Use BINDER_TYPE_HANDLE for NULL binders
2022-10-11 18:44:37 +03:00
Slava Monich
8bf0d63960 [gbinder] Use BINDER_TYPE_HANDLE for NULL binders
That's what Parcel.cpp seems to be doing on the Android side
2022-10-11 17:14:10 +03:00
Slava Monich
c22eafe49e Version 1.1.25 2022-07-19 02:04:30 +03:00
Slava Monich
66122a2ce6 [unit] Added unit test for device + protocol combo. JB#42254 2022-07-19 02:01:26 +03:00
Slava Monich
c1ff25f6ae [gbinder] Housekeeping. JB#42254 2022-07-19 01:57:13 +03:00
Slava Monich
af3c23a18f Merge pull request #98 from aleasto/master
Handle changing the rpc protocol during execution
2022-07-19 01:49:19 +03:00
Alessandro Astone
5a14796c4c [gbinder] Handle changing the rpc protocol during execution
When calling gbinder_ipc_new with a different protocol for the same
device node, we would end up getting the old cached GBinderIpc object
referencing the old protocol.

Make the hash table key uniquely identify a (dev,protocol) pair.
2022-07-19 00:47:51 +02:00
Slava Monich
3bb8a38f5f Version 1.1.24 2022-07-14 01:35:45 +03:00
Slava Monich
f29f0b5a1b [debian] Bumped debhelper compat level to 7. JB#42956 2022-07-14 01:34:45 +03:00
Slava Monich
2da1c7b5ca Version 1.1.23 2022-06-23 20:12:08 +03:00
Slava Monich
8348bc76bd Merge pull request #96 from monich/build-deps
Fix debian build dependencies
2022-06-23 20:06:28 +03:00
Slava Monich
a97a153c94 [debian] Fix build dependencies. JB#42956 2022-06-23 04:09:12 +03:00
Slava Monich
94ddc9f0e5 Version 1.1.22 2022-06-22 17:05:07 +03:00
Slava Monich
370d2dedb3 [unit] Improved gbinder_config.c coverage. JB#42956 2022-06-22 16:57:15 +03:00
Slava Monich
58c9a7fe93 Merge pull request #83 from adglkh/api_31_support
[gbinder] Support for Android 12 (API level 31). JB#42254
2022-06-22 16:29:38 +03:00
gary-wzl77
3742e2ca8e [test] make the binder device configurable for binder-dump test 2022-06-22 18:36:52 +08:00
gary-wzl77
ede15da9e2 [gbinder] Add preset gbinder config to support Android API version 31 2022-06-22 18:36:52 +08:00
gary-wzl77
771444a8ac [gbinder] Add "aidl4" variant of service manager
Introduce "aidl4" variant of service manager to adapt the change
to service related protocol for Android 12.

From Android 12, when reading nullable strong binder, the format of
the `stability` field passed on the wire was changed and evolved to
`struct Category`, which consists of the following members with 4 bytes long.
```
struct Category {
  uint8_t version;
  uint8_t reserved[2];
  Level level;        <- bitmask of Stability::Level
}
```
Please check the following link for details:

  https://cs.android.com/android/platform/superproject/+/android-12.0.0_r3:frameworks/native/libs/binder/include/binder/Stability.h;l=140

To honor the change on AOSP side for Android 12, we need to adapt
the protocol change in Service Manager.
2022-06-22 18:36:51 +08:00
Slava Monich
956fa90cbf Version 1.1.21 2022-06-20 18:54:33 +03:00
Slava Monich
17ff87510c [gbinder] Housekeeping. JB#42956 2022-06-20 13:28:20 +03:00
Slava Monich
552fc4f172 [gbinder] Don't finalize GObject twice. JB#42956 2022-06-20 13:26:11 +03:00
Slava Monich
4b179477ad [gbinder] Properly finalize GBinderServicePoll. JB#42956 2022-06-20 13:01:34 +03:00
Slava Monich
8419a53f23 Version 1.1.20 2022-06-11 02:50:08 +03:00
Slava Monich
865a29d1dd [unit] Tests should ignore system config 2022-06-11 02:49:02 +03:00
Slava Monich
93fbb5b238 [gbinder] Housekeeping. JB#42254 2022-06-11 02:08:05 +03:00
Slava Monich
1a9408f65c Acknowledge Alessandro's contribution 2022-06-11 02:05:29 +03:00
Slava Monich
14399b112f [gbinder] Make RPC protocol selectable at runtime. JB#42254
Merge pull request #93 from aleasto/master
2022-06-11 02:03:02 +03:00
Alessandro Astone
754fa5bcda Make protocol selectable at runtime 2022-06-10 13:50:01 +02:00
Slava Monich
0b43f88700 Version 1.1.19 2022-02-20 03:29:13 +02:00
Slava Monich
5822a40c39 [unit] Added tests for invalid parcelables. JB#54354 2022-02-20 03:22:09 +02:00
Slava Monich
ca5f3ad0be [gbinder] Better handle invalid parcelables. JB#54354 2022-02-20 03:21:34 +02:00
Slava Monich
3398afd701 [unit] Fixed a memory leak in unit_reader. JB#54354
==642984== HEAP SUMMARY:
==642984==     in use at exit: 1,097,253 bytes in 557 blocks
==642984==   total heap usage: 4,780 allocs, 4,223 frees, 78,991,940 bytes allocated
==642984==
==642984== 1,040,520 (24 direct, 1,040,496 indirect) bytes in 1 blocks are definitely lost in loss record 475 of 475
==642984==    at 0x483B7F3: malloc
==642984==    by 0x4923E98: g_malloc
==642984==    by 0x493C485: g_slice_alloc
==642984==    by 0x493CAAD: g_slice_alloc0
==642984==    by 0x11CA1E: gbinder_buffer_alloc (gbinder_buffer.c:167)
==642984==    by 0x11CAFD: gbinder_buffer_new (gbinder_buffer.c:195)
==642984==    by 0x1192C9: test_parcelable (unit_reader.c:1728)
==642984==    by 0x494658D: ???
==642984==    by 0x4946A79: g_test_run_suite
==642984==    by 0x4946A94: g_test_run
==642984==    by 0x11C719: main (unit_reader.c:2448)
==642984==
2022-02-20 02:40:19 +02:00
Slava Monich
3c828b453a [gbinder] Housekeeping. JB#54354 2022-02-20 02:31:56 +02:00
Slava Monich
9d95a622f4 Acknowledge Eugenio's contribution 2022-02-20 01:54:03 +02:00
Slava Monich
78dd0563e6 Merge pull request #92 from g7/for-upstream/mer-hybris/parcelables
[gbinder] Reader and writer for aidl parcelables. JB#54354
2022-02-20 01:51:04 +02:00
Eugenio Paolantonio (g7)
5fd5b423c1 [gbinder] Added reader for parcelables
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2022-02-19 19:06:12 +01:00
Eugenio Paolantonio (g7)
2acec3f7ce [gbinder] Added writer for parcelables
Parcelables allow to serialize arbitrary objects inside
an AIDL parcel.

The structure is pretty simple, and is as follows:

* (int32) Control integer that signals whether there is content (1),
or not (0)

* (int32) Integer holding the payload size, including itself

* The actual payload

Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2022-02-19 19:06:12 +01:00
Slava Monich
59dee397f0 [gbinder] Fixed gbinder_servicemanager_remove_all_handlers macro. JB#42956 2022-02-11 20:12:52 +02:00
Slava Monich
e196c66264 Version 1.1.18 2022-01-08 15:39:43 +02:00
Slava Monich
8f62f4d65c Merge pull request #89 from monich/nodrop
Disassociate auto-created proxies
2022-01-08 15:28:20 +02:00
Slava Monich
8583a72d11 [gbinder] Disassociate auto-created proxies. JB#56889
They are independent on each other and can be destroyed in any order.
2022-01-07 21:22:32 +02:00
Slava Monich
381446eb4f [gbinder] Expose gbinder_ipc_name as an internal function
To be used by other objects e.g. GBinderProxyObject
2022-01-07 18:26:17 +02:00
Slava Monich
eabf5683f4 [gbinder] Logging improvements
Logging device name is useful for understanding what's going on when
multiple binder devices are involved.
2022-01-07 18:25:25 +02:00
Slava Monich
f4712be3b5 Version 1.1.17 2022-01-07 14:44:53 +02:00
Slava Monich
08f701c96b Merge pull request #88 from monich/late_release
Don't release remote proxy handle too early
2022-01-07 14:38:34 +02:00
Slava Monich
8c5618aaab [gbinder] Don't release remote proxy handle too early. JB#56889
Release it when the local one is finalized.
2022-01-05 05:08:40 +02:00
Slava Monich
1bc2efd724 Version 1.1.16 2022-01-03 14:01:34 +02:00
Slava Monich
066464f3af [license] Freshened up copyright 2022-01-03 13:55:34 +02:00
Slava Monich
f5b399d775 [unit] Improved gbinder_ipc_find_local_object coverage 2022-01-03 13:53:37 +02:00
Slava Monich
6e127bd184 Merge pull request #87 from monich/invalidate
Make sure stale object pointers don't hang around
2022-01-03 13:34:28 +02:00
Slava Monich
95277d1b3d [gbinder] Properly shut down remote object inside the proxy. JB#56341
Every gbinder_driver_release() must be accompanied by
gbinder_ipc_invalidate_remote_handle() because the former
releases the node and allows the kernel to reuse the handle.
2022-01-03 01:00:12 +02:00
Slava Monich
e0c56c1226 [gbinder] Make sure stale object pointers don't hang around. JB#56341
When an object is being finalized, other thread may re-reference the
object right before it gets removed from the table (making ref_count
greater than 1) and then quickly release that reference before
g_object_unref() re-checks the refcount.

If that happens, the object may remain in the table by time when its
finalize() callback is called. That applies both to local and remote
objects.

We still have to invalidate the handle in dispose() callback because
it's the last point when GObject can be legitimately re-referenced and
brought back to life.
2022-01-02 22:01:47 +02:00
Slava Monich
5e3df46da9 Merge pull request #86 from monich/atomic
Read ref_count from GObject atomically
2022-01-02 19:40:43 +02:00
Slava Monich
393006f051 Merge pull request #85 from monich/txcode
Print transaction code in debug build
2022-01-02 19:40:17 +02:00
Slava Monich
e10e3df1eb [gbinder] Read ref_count from GObject atomically. JB#42956 2022-01-02 18:52:55 +02:00
Slava Monich
86ba34dc67 [gbinder] Print transaction code in debug build. JB#42956 2022-01-02 18:01:01 +02:00
Slava Monich
b0b5595f20 Version 1.1.15 2021-12-27 15:16:26 +02:00
Slava Monich
757908cd6c [gbinder] Updated README 2021-12-27 15:12:46 +02:00
Slava Monich
e6ca4b50ec Merge pull request #84 from monich/pad
Add readers and writers for int8 and int16
2021-12-27 15:00:44 +02:00
Slava Monich
97831a65da [gbinder] Added readers for int8 and int16. JB#42956 2021-12-27 06:36:22 +02:00
Slava Monich
5798434ead [gbinder] Added writers for int8 and int16. JB#42956
Those have to be padded to 4-byte boundary.
2021-12-27 06:08:53 +02:00
Slava Monich
54b1149a75 [gbinder] Housekeeping 2021-12-27 06:06:15 +02:00
Slava Monich
e9f873b3a4 Version 1.1.14 2021-11-24 17:16:33 +02:00
Slava Monich
8b621fe7d3 [gbinder] Don't compile fmq code if __NR_memfd_create is undefined 2021-11-24 17:08:29 +02:00
Slava Monich
e5542027c2 Merge pull request #82 from mer-hybris/jb54946-atomic
Replace use of stdatomic.h and linux/memfd.h.
2021-11-24 16:42:07 +02:00
Matti Lehtimäki
8539f6e944 [gbinder] Replace use of stdatomic.h and linux/memfd.h. 2021-11-24 05:22:32 +02:00
Slava Monich
fa53d0cf70 [rpm] Install license file. JB#55991 2021-11-23 20:19:49 +02:00
Slava Monich
d6c3ddb4e3 Merge pull request #81 from monich/misc
Assorted changes
2021-11-23 20:17:26 +02:00
Slava Monich
fd081601a3 [gbinder] Tolerate NULL const GBinderReader pointers.
Non-const pointers are still assumed to point to a valid, presumably
stack-allocated structure.
2021-11-23 19:44:09 +02:00
Slava Monich
7b319ba822 [gbinder] Added gbinder_client_rpc_header(). JB#55014
Mostly for logging purposes.
2021-11-23 19:25:49 +02:00
Slava Monich
d439bd467a [gbinder] Added gbinder_reader_get_data(). JB#55014
Mostly for logging purposes.
2021-11-23 19:25:49 +02:00
Slava Monich
c99df04daf [gbinder] Added gbinder_writer_get_data(). JB#55014
Mostly for logging purposes.
2021-11-23 19:25:49 +02:00
Slava Monich
81b6b7f087 [gbinder] Added gbinder_servicemanager_device(). JB#55014
Returns the associated binder device name.
2021-11-23 19:25:49 +02:00
Slava Monich
91bc5253e4 Merge pull request #80 from monich/housekeeping
Housekeeping
2021-11-23 19:24:21 +02:00
Slava Monich
ddf67e83eb [gbinder] Housekeeping. JB#54946 2021-11-23 18:10:30 +02:00
Slava Monich
fc257ec23c Merge pull request #78 from mer-hybris/jb54946
Add FMQ support
2021-11-23 01:57:41 +02:00
Matti Lehtimäki
8148f03ae6 [gbinder] Add FMQ unit tests. JB#54946 2021-11-22 18:56:48 +02:00
Matti Lehtimäki
a1616163e7 [gbinder] Add support for FMQ (Fast Message Queue). JB#54946 2021-11-22 18:56:48 +02:00
Slava Monich
7f12f1a476 [gbinder] Housekeeping. JB#56344 2021-11-20 03:20:06 +02:00
Slava Monich
f3cf738265 [unit] Assert that dummy type functions don't get invoked. JB#42956 2021-11-20 02:53:41 +02:00
Slava Monich
f8916148a9 Merge pull request #79 from mer-hybris/jb56344
Support libgbinder for Android 11
2021-11-20 00:25:37 +02:00
gary-wzl77
fe2d441e25 [gbinder] Added "aidl3" variant of service manager. JB#56344
Introduce "aidl3" variant of service manager to adapt the changes
to service related protocol in Android 11.

List services command no longer has index parameter and all data
is in single transaction.

Add service command now has additional "stability" parameter.
2021-11-20 00:17:01 +02:00
gary-wzl77
85c7d8f311 [gbinder] Add preset gbinder config to support Android API version 30. JB#56344 2021-11-19 23:12:51 +02:00
gary-wzl77
597fb84367 [gbinder] Added "aidl3" variant of RPC protocol. JB#56344
Due to the following change in the upstream,

d70160f298%5E%21/#F0

The system and vendor binder have a different header in Android 11.
To adapt this change to Android 11, we have to introduce a new
"aidl3" variant of service manager in libgbinder, which target to
Android 11 or higher if the rpc protocol remains for the upcoming
major Android release.
2021-11-11 18:09:13 +02:00
Slava Monich
30242d7124 [unit] Added test for gbinder_local_reply_append_fd() 2021-11-02 01:34:36 +02:00
Slava Monich
14327ed5f1 Housekeeping 2021-11-02 01:33:31 +02:00
Slava Monich
36e1fed889 Acknowledge contributions 2021-11-02 01:32:42 +02:00
gary-wzl77
cecdea76bc [gbinder] Support writing file descriptor via local reply
For now, the missing API gbinder_local_reply_append_fd() which
supports sending a file descriptor via libgbinder blocks us from
forwarding the file descriptor from host to Android container
throughout a bridge established between host and Android container.
Essentially, libgbinder has related logic implemented but the function
gbinder_writer_data_append_fdi() for now is an static function only
visible to the translation unit.

In order to support our use case, we create a new API called
gbinder_local_reply_append_fd(), which is just a simple wrapper
of gbinder_writer_data_append_fd(), which meets our expectation.
2021-11-02 01:27:35 +02:00
Slava Monich
7f72021075 Version 1.1.13 2021-10-28 14:33:18 +03:00
Slava Monich
846037073b Merge pull request #77 from monich/noprepare
Simplify writer a bit
2021-10-28 14:23:48 +03:00
Slava Monich
f0b55886b2 [gbinder] Simplify writer a bit. JB#42956 2021-10-28 02:25:55 +03:00
Slava Monich
165d386436 [test] Added ashmem-test. JB#42956 2021-10-27 19:53:00 +03:00
Slava Monich
a07e0f2a99 [gbinder] Add gbinder_writer_append_hidl_string_copy(). JB#42956 2021-10-22 20:59:08 +03:00
Slava Monich
bc172346e0 [gbinder] Drop pkgconfig requirement for devel package. JB#42956 2021-10-10 05:21:16 +03:00
Slava Monich
5801ed4f15 [gbinder] Added gbinder_writer_strdup(). JB#42956 2021-10-10 05:02:06 +03:00
101 changed files with 7899 additions and 3602 deletions

View File

@@ -6,3 +6,6 @@ Andrew Branson <andrew.branson@jolla.com>
Rinigus <rinigus.git@gmail.com>
George Hopkins <george-hopkins@null.net>
Bart Ribbers <bribbers@disroot.org>
Gary Wang <gary.wang@canonical.com>
Eugenio Paolantonio <me@medesimo.eu>
Alessandro Astone <ales.astone@gmail.com>

View File

@@ -1,5 +1,5 @@
Copyright (C) 2018-2021 Jolla Ltd.
Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
Copyright (C) 2018-2022 Jolla Ltd.
Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:

View File

@@ -16,7 +16,7 @@
VERSION_MAJOR = 1
VERSION_MINOR = 1
VERSION_RELEASE = 12
VERSION_RELEASE = 31
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
@@ -82,6 +82,7 @@ SRC = \
gbinder_config.c \
gbinder_driver.c \
gbinder_eventloop.c \
gbinder_fmq.c \
gbinder_io_32.c \
gbinder_io_64.c \
gbinder_ipc.c \
@@ -103,6 +104,8 @@ SRC += \
gbinder_servicemanager.c \
gbinder_servicemanager_aidl.c \
gbinder_servicemanager_aidl2.c \
gbinder_servicemanager_aidl3.c \
gbinder_servicemanager_aidl4.c \
gbinder_servicemanager_hidl.c
SRC += \

12
README
View File

@@ -5,7 +5,7 @@ Key features:
1. Integration with GLib event loop
2. Detection of 32 vs 64 bit kernel at runtime
3. Asynchronous transactions that don't block the event thread
4. Stable service manager and low-level transation APIs
4. Stable service manager and low-level transaction APIs
Android keeps changing both low-level RPC and service manager
protocols from version to version. To counter that, libgbinder
@@ -22,8 +22,8 @@ directory is scanned for .conf files, the file list is sorted, files are
loaded one by one, overwriting the entries loaded from /etc/gbinder.conf
or from the previously processed file.
Known protocol and service manager variants are aidl, aidl2 and hidl.
This list is expected to expand further in the future. The default
Known protocol and service manager variants are aidl, aidl2, aidl3 and
hidl. This list is expected to expand further in the future. The default
configuration is as follows:
[Protocol]
@@ -36,9 +36,11 @@ configuration is as follows:
/dev/binder = aidl
/dev/hwbinder = hidl
Alternatively, one can specify the desired Android API level:
Alternatively and preferably, one can specify the desired Android API
level:
[General]
ApiLevel = 29
and let libgbinder pick the appropriate preset.
and let libgbinder pick the appropriate preset. Full list of presets can
be found in src/gbinder_config.c

129
debian/changelog vendored
View File

@@ -1,3 +1,132 @@
libgbinder (1.1.31) unstable; urgency=low
* Fixed serialization issues on big-endian
* Refactored binder simulation for unit tests
-- Slava Monich <slava@monich.com> Wed, 04 Jan 2023 19:10:37 +0200
libgbinder (1.1.30) unstable; urgency=low
* Fixed BC_ACQUIRE_DONE encoding
-- Slava Monich <slava.monich@jolla.com> Sun, 04 Dec 2022 19:50:10 +0200
libgbinder (1.1.29) unstable; urgency=low
* Added gbinder_writer_append_struct_vec
-- Slava Monich <slava.monich@jolla.com> Fri, 25 Nov 2022 00:01:41 +0200
libgbinder (1.1.28) unstable; urgency=low
* Allow to pass negative number as a parameter to binder-call
* Compile tools as PIE
-- Slava Monich <slava.monich@jolla.com> Tue, 22 Nov 2022 18:21:29 +0200
libgbinder (1.1.27) unstable; urgency=low
* Added gbinder_writer_append_struct()
-- Slava Monich <slava.monich@jolla.com> Thu, 17 Nov 2022 03:25:37 +0200
libgbinder (1.1.26) unstable; urgency=low
* Use BINDER_TYPE_HANDLE for NULL binders
* Fixed binder object encoding in aidl3 protocol
-- Slava Monich <slava.monich@jolla.com> Fri, 14 Oct 2022 16:48:29 +0300
libgbinder (1.1.25) unstable; urgency=low
* Handle RPC protocol change at run time
-- Slava Monich <slava.monich@jolla.com> Tue, 19 Jul 2022 02:02:41 +0300
libgbinder (1.1.24) unstable; urgency=low
* Bumped debhelper compat level to 7
-- Slava Monich <slava.monich@jolla.com> Thu, 14 Jul 2022 01:32:11 +0300
libgbinder (1.1.23) unstable; urgency=low
* Fixed Debian build dependencies
-- Slava Monich <slava.monich@jolla.com> Thu, 23 Jun 2022 20:09:35 +0300
libgbinder (1.1.22) unstable; urgency=low
* Added support for Android 12 (API level 31)
* Made binder device configurable for binder-dump
-- Slava Monich <slava.monich@jolla.com> Wed, 22 Jun 2022 17:02:20 +0300
libgbinder (1.1.21) unstable; urgency=low
* Properly finalize GBinderIpc and GBinderServicePoll
-- Slava Monich <slava.monich@jolla.com> Mon, 20 Jun 2022 18:53:26 +0300
libgbinder (1.1.20) unstable; urgency=low
* Made RPC protocol selectable at runtime
-- Slava Monich <slava.monich@jolla.com> Sat, 11 Jun 2022 02:49:49 +0300
libgbinder (1.1.19) unstable; urgency=low
* Added reader and writer for aidl parcelables
-- Slava Monich <slava.monich@jolla.com> Sun, 20 Feb 2022 03:26:24 +0200
libgbinder (1.1.18) unstable; urgency=low
* Disassociate auto-created proxies to stop them from piling up
-- Slava Monich <slava.monich@jolla.com> Sat, 08 Jan 2022 15:35:56 +0200
libgbinder (1.1.17) unstable; urgency=low
* Don't release remote proxy handle too early (sometimes hever)
-- Slava Monich <slava.monich@jolla.com> Fri, 07 Jan 2022 14:43:51 +0200
libgbinder (1.1.16) unstable; urgency=low
* Make sure stale object pointers don't hang around
* Properly shut down remote object inside the proxy
* Read ref_count from GObject atomically
-- Slava Monich <slava.monich@jolla.com> Mon, 03 Jan 2022 13:58:44 +0200
libgbinder (1.1.15) unstable; urgency=low
* Added readers and writers for int8 and int16
-- Slava Monich <slava.monich@jolla.com> Mon, 27 Dec 2021 15:13:23 +0200
libgbinder (1.1.14) unstable; urgency=low
* Support for FMQ (Fast Message Queues)
* Support for Android 11 (API level 30)
* Made GBinderReader API slightly more NULL tolerant
* Added gbinder_client_rpc_header()
* Added gbinder_reader_get_data()
* Added gbinder_writer_get_data()
* Added gbinder_servicemanager_device()
* Added gbinder_local_reply_append_fd()
-- Slava Monich <slava.monich@jolla.com> Wed, 24 Nov 2021 17:15:48 +0200
libgbinder (1.1.13) unstable; urgency=low
* Added gbinder_writer_strdup()
* Added gbinder_writer_append_hidl_string_copy()
* Dropped pkgconfig requirement for devel package
-- Slava Monich <slava.monich@jolla.com> Thu, 28 Oct 2021 14:31:01 +0300
libgbinder (1.1.12) unstable; urgency=low
* Added binder-call test tool

2
debian/compat vendored
View File

@@ -1 +1 @@
5
7

4
debian/control vendored
View File

@@ -2,7 +2,7 @@ Source: libgbinder
Section: libs
Priority: optional
Maintainer: Slava Monich <slava.monich@jolla.com>
Build-Depends: debhelper (>= 8.1.3), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.52), flex, bison
Build-Depends: debhelper (>= 8.1.3), libglib2.0-dev (>= 2.0), libglibutil-dev (>= 1.0.52), flex, bison
Standards-Version: 3.8.4
Package: libgbinder
@@ -14,7 +14,7 @@ Description: Binder client library
Package: libgbinder-dev
Section: libdevel
Architecture: any
Depends: libgbinder (= ${binary:Version}), ${misc:Depends}
Depends: libgbinder (= ${binary:Version}), libglibutil-dev (>= 1.0.52)
Description: Development files for libgbinder
Package: libgbinder-tools

4
debian/copyright vendored
View File

@@ -1,5 +1,5 @@
Copyright (C) 2018-2021 Jolla Ltd.
Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
Copyright (C) 2018-2022 Jolla Ltd.
Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:

View File

@@ -38,6 +38,7 @@
#include "gbinder_bridge.h"
#include "gbinder_buffer.h"
#include "gbinder_client.h"
#include "gbinder_fmq.h"
#include "gbinder_local_object.h"
#include "gbinder_local_reply.h"
#include "gbinder_local_request.h"

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -78,6 +78,11 @@ gbinder_client_interface2(
GBinderClient* client,
guint32 code); /* since 1.0.42 */
GBytes*
gbinder_client_rpc_header(
GBinderClient* client,
guint32 code); /* since 1.1.14 */
GBinderLocalRequest*
gbinder_client_new_request(
GBinderClient* client);

154
include/gbinder_fmq.h Normal file
View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2021 Jolla Ltd.
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_FMQ_H
#define GBINDER_FMQ_H
#include <gbinder_types.h>
G_BEGIN_DECLS
/* Since 1.1.14 */
typedef enum gbinder_fmq_type {
GBINDER_FMQ_TYPE_SYNC_READ_WRITE = 1,
GBINDER_FMQ_TYPE_UNSYNC_WRITE
} GBINDER_FMQ_TYPE;
typedef enum gbinder_fmq_flags {
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG = 0x1,
GBINDER_FMQ_FLAG_NO_RESET_POINTERS = 0x2
} GBINDER_FMQ_FLAGS;
GBinderFmq*
gbinder_fmq_new(
gsize item_size,
gsize max_num_items,
GBINDER_FMQ_TYPE type,
GBINDER_FMQ_FLAGS flags,
gint fd,
gsize buffer_size);
GBinderFmq*
gbinder_fmq_ref(
GBinderFmq* fmq);
void
gbinder_fmq_unref(
GBinderFmq* fmq);
/* Functions for checking how many items are available in queue */
gsize
gbinder_fmq_available_to_read(
GBinderFmq* fmq);
gsize
gbinder_fmq_available_to_write(
GBinderFmq* fmq);
gsize
gbinder_fmq_available_to_read_contiguous(
GBinderFmq* fmq);
gsize
gbinder_fmq_available_to_write_contiguous(
GBinderFmq* fmq);
/* Functions for obtaining data pointer for zero copy read/write */
const void*
gbinder_fmq_begin_read(
GBinderFmq* fmq,
gsize items);
void*
gbinder_fmq_begin_write(
GBinderFmq* fmq,
gsize items);
/* Functions for ending zero copy read/write
* The number of items must match the value provided to gbinder_fmq_begin_read
* or gbinder_fmq_begin_write */
void
gbinder_fmq_end_read(
GBinderFmq* fmq,
gsize items);
void
gbinder_fmq_end_write(
GBinderFmq* fmq,
gsize items);
/* Regular read/write functions (non-zero-copy) */
gboolean
gbinder_fmq_read(
GBinderFmq* fmq,
void* data,
gsize items);
gboolean
gbinder_fmq_write(
GBinderFmq* fmq,
const void* data,
gsize items);
/*
* Functions for waiting and waking message queue.
* Requires configured event flag in message queue.
*/
int
gbinder_fmq_wait_timeout(
GBinderFmq* fmq,
guint32 bit_mask,
guint32* state,
int timeout_ms);
#define gbinder_fmq_try_wait(fmq, mask, state) \
gbinder_fmq_wait_timeout(fmq, mask, state, 0)
#define gbinder_fmq_wait(fmq, mask, state) \
gbinder_fmq_wait_timeout(fmq, mask, state, -1)
int
gbinder_fmq_wake(
GBinderFmq* fmq,
guint32 bit_mask);
G_END_DECLS
#endif /* GBINDER_FMQ_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-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -112,6 +112,11 @@ gbinder_local_reply_append_remote_object(
GBinderLocalReply* reply,
GBinderRemoteObject* obj);
GBinderLocalReply*
gbinder_local_reply_append_fd(
GBinderLocalReply* reply,
int fd); /* Since 1.1.14 */
G_END_DECLS
#endif /* GBINDER_LOCAL_OBJECT_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -65,6 +65,26 @@ gbinder_reader_read_bool(
GBinderReader* reader,
gboolean* value);
gboolean
gbinder_reader_read_int8(
GBinderReader* reader,
gint8* value); /* Since 1.1.15 */
gboolean
gbinder_reader_read_uint8(
GBinderReader* reader,
guint8* value); /* Since 1.1.15 */
gboolean
gbinder_reader_read_int16(
GBinderReader* reader,
gint16* value); /* Since 1.1.15 */
gboolean
gbinder_reader_read_uint16(
GBinderReader* reader,
guint16* value); /* Since 1.1.15 */
gboolean
gbinder_reader_read_int32(
GBinderReader* reader,
@@ -122,6 +142,11 @@ gbinder_reader_read_buffer(
GBinderReader* reader)
G_GNUC_WARN_UNUSED_RESULT;
const void*
gbinder_reader_read_parcelable(
GBinderReader* reader,
gsize* size); /* Since 1.1.19 */
const void*
gbinder_reader_read_hidl_struct1(
GBinderReader* reader,
@@ -201,6 +226,11 @@ gbinder_reader_read_byte_array(
GBinderReader* reader,
gsize* len); /* Since 1.0.12 */
const void*
gbinder_reader_get_data(
const GBinderReader* reader,
gsize* size); /* Since 1.1.14 */
gsize
gbinder_reader_bytes_read(
const GBinderReader* reader);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -76,7 +76,15 @@ void
GBinderServiceManager*
gbinder_servicemanager_new(
const char* dev);
const char* dev)
G_GNUC_WARN_UNUSED_RESULT;
GBinderServiceManager*
gbinder_servicemanager_new2(
const char* dev,
const char* sm_protocol,
const char* rpc_protocol) /* Since 1.1.20 */
G_GNUC_WARN_UNUSED_RESULT;
GBinderServiceManager*
gbinder_defaultservicemanager_new(
@@ -112,6 +120,10 @@ void
gbinder_servicemanager_unref(
GBinderServiceManager* sm);
const char*
gbinder_servicemanager_device(
GBinderServiceManager* sm); /* Since 1.1.14 */
gboolean
gbinder_servicemanager_is_present(
GBinderServiceManager* sm); /* Since 1.0.25 */
@@ -189,7 +201,7 @@ gbinder_servicemanager_remove_handlers(
gulong* ids,
guint count); /* Since 1.0.25 */
#define gbinder_servicemanager_remove_all_handlers(r,ids) \
#define gbinder_servicemanager_remove_all_handlers(sm,ids) \
gbinder_servicemanager_remove_handlers(sm, ids, G_N_ELEMENTS(ids))
G_END_DECLS

View File

@@ -62,6 +62,7 @@ G_BEGIN_DECLS
typedef struct gbinder_bridge GBinderBridge; /* Since 1.1.5 */
typedef struct gbinder_buffer GBinderBuffer;
typedef struct gbinder_client GBinderClient;
typedef struct gbinder_fmq GBinderFmq; /* Since 1.1.14 */
typedef struct gbinder_ipc GBinderIpc;
typedef struct gbinder_local_object GBinderLocalObject;
typedef struct gbinder_local_reply GBinderLocalReply;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -55,6 +55,119 @@ struct gbinder_parent {
guint32 offset;
};
/*
* Note that gbinder_writer_append_struct() doesn't copy the data, it writes
* buffer objects pointing to whatever was passed in. The caller must make
* sure that those pointers outlive the transaction. That's most commonly
* done with by using gbinder_writer_malloc() and friends for allocating
* memory for the transaction.
*
* Below is an example of initializing GBinderWriterType which can then
* be passed to gbinder_writer_append_struct(). Fields have to be listed
* in the order in which they appear in the structure.
*
* typedef struct data {
* int x;
* } Data;
*
* typedef struct data2 {
* int y;
* GBinderHidlString str;
* GBinderHidlVec vec; // vec<Data>
* } Data2;
*
* static const GBinderWriterType data_t = {
* GBINDER_WRITER_STRUCT_NAME_AND_SIZE(Data), NULL
* };
*
* static const GBinderWriterField data2_f[] = {
* GBINDER_WRITER_FIELD_HIDL_STRING(Data2,str),
* GBINDER_WRITER_FIELD_HIDL_VEC(Data2, vec, &data_t),
* GBINDER_WRITER_FIELD_END()
* };
*
* static const GBinderWriterType data2_t = {
* GBINDER_WRITER_STRUCT_NAME_AND_SIZE(Data2), data2_f
* };
*/
typedef struct gbinder_writer_type {
const char* name;
gsize size;
const struct gbinder_writer_field* fields;
} GBinderWriterType; /* Since 1.1.27 */
typedef struct gbinder_writer_field {
const char* name;
gsize offset;
const GBinderWriterType* type;
void (*write_buf)(GBinderWriter* writer, const void* ptr,
const struct gbinder_writer_field* field, const GBinderParent* parent);
gpointer reserved;
} GBinderWriterField; /* Since 1.1.27 */
#define GBINDER_WRITER_STRUCT_NAME_AND_SIZE(type) \
#type, sizeof(type)
#define GBINDER_WRITER_FIELD_NAME_AND_OFFSET(type,field) \
#type "." #field, G_STRUCT_OFFSET(type,field)
#define GBINDER_WRITER_FIELD_POINTER(type,field,field_type) { \
GBINDER_WRITER_FIELD_NAME_AND_OFFSET(type,field), field_type, NULL, NULL }
#define GBINDER_WRITER_FIELD_HIDL_VEC(type,field,elem) { \
GBINDER_WRITER_FIELD_NAME_AND_OFFSET(type,field), elem, \
gbinder_writer_field_hidl_vec_write_buf, NULL }
#define GBINDER_WRITER_FIELD_HIDL_VEC_INT32(type,field) \
GBINDER_WRITER_FIELD_HIDL_VEC(type,field, &gbinder_writer_type_int32)
#define GBINDER_WRITER_FIELD_HIDL_VEC_BYTE(type,field) \
GBINDER_WRITER_FIELD_HIDL_VEC(type,field, &gbinder_writer_type_byte)
#define GBINDER_WRITER_FIELD_HIDL_VEC_STRING(type,field) \
GBINDER_WRITER_FIELD_HIDL_VEC(type,field, &gbinder_writer_type_hidl_string)
#define GBINDER_WRITER_FIELD_HIDL_STRING(type,field) { \
GBINDER_WRITER_FIELD_NAME_AND_OFFSET(type,field), NULL, \
gbinder_writer_field_hidl_string_write_buf, NULL }
#define GBINDER_WRITER_FIELD_END() { NULL, 0, NULL, NULL, NULL }
extern const GBinderWriterType gbinder_writer_type_byte; /* Since 1.1.27 */
extern const GBinderWriterType gbinder_writer_type_int32; /* Since 1.1.27 */
extern const GBinderWriterType gbinder_writer_type_hidl_string; /* 1.1.27 */
void
gbinder_writer_append_struct(
GBinderWriter* writer,
const void* ptr,
const GBinderWriterType* type,
const GBinderParent* parent); /* Since 1.1.27 */
void
gbinder_writer_append_struct_vec(
GBinderWriter* writer,
const void* ptr,
guint count,
const GBinderWriterType* type); /* Since 1.1.29 */
void
gbinder_writer_field_hidl_vec_write_buf(
GBinderWriter* writer,
const void* ptr,
const GBinderWriterField* field,
const GBinderParent* parent); /* Since 1.1.27 */
void
gbinder_writer_field_hidl_string_write_buf(
GBinderWriter* writer,
const void* ptr,
const GBinderWriterField* field,
const GBinderParent* parent); /* Since 1.1.27 */
void
gbinder_writer_append_int8(
GBinderWriter* writer,
guint8 value); /* Since 1.1.15 */
void
gbinder_writer_append_int16(
GBinderWriter* writer,
guint16 value); /* Since 1.1.15 */
void
gbinder_writer_append_int32(
GBinderWriter* writer,
@@ -119,15 +232,11 @@ 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(
gbinder_writer_append_fds(
GBinderWriter* writer,
gsize offset,
gint32 value); /* since 1.0.21 */
const GBinderFds* fds,
const GBinderParent* parent); /* Since 1.1.14 */
guint
gbinder_writer_append_buffer_object_with_parent(
@@ -142,18 +251,29 @@ gbinder_writer_append_buffer_object(
const void* buf,
gsize len);
void
gbinder_writer_append_parcelable(
GBinderWriter* writer,
const void* buf,
gsize len); /* Since 1.1.19 */
void
gbinder_writer_append_hidl_vec(
GBinderWriter* writer,
const void* base,
guint count,
guint elemsize); /* since 1.0.8 */
guint elemsize); /* Since 1.0.8 */
void
gbinder_writer_append_hidl_string(
GBinderWriter* writer,
const char* str);
void
gbinder_writer_append_hidl_string_copy(
GBinderWriter* writer,
const char* str); /* Since 1.1.13 */
void
gbinder_writer_append_hidl_string_vec(
GBinderWriter* writer,
@@ -174,17 +294,39 @@ void
gbinder_writer_append_byte_array(
GBinderWriter* writer,
const void* byte_array,
gint32 len); /* since 1.0.12 */
gint32 len); /* Since 1.0.12 */
void
gbinder_writer_append_fmq_descriptor(
GBinderWriter* writer,
const GBinderFmq* queue); /* since 1.1.14 */
const void*
gbinder_writer_get_data(
GBinderWriter* writer,
gsize* size); /* Since 1.1.14 */
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 */
/* Note: memory allocated by GBinderWriter is owned by GBinderWriter */
void*
gbinder_writer_malloc(
GBinderWriter* writer,
gsize size); /* since 1.0.19 */
gsize size); /* Since 1.0.19 */
void*
gbinder_writer_malloc0(
GBinderWriter* writer,
gsize size); /* since 1.0.19 */
gsize size); /* Since 1.0.19 */
#define gbinder_writer_new(writer,type) \
((type*) gbinder_writer_malloc(writer, sizeof(type)))
@@ -192,17 +334,22 @@ gbinder_writer_malloc0(
#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 */
gpointer data); /* Since 1.0.19 */
void*
gbinder_writer_memdup(
GBinderWriter* writer,
const void* buf,
gsize size); /* Since 1.0.19 */
char*
gbinder_writer_strdup(
GBinderWriter* writer,
const char* str); /* Since 1.1.13 */
G_END_DECLS

View File

@@ -1,6 +1,6 @@
Name: libgbinder
Version: 1.1.12
Version: 1.1.31
Release: 0
Summary: Binder client library
License: BSD
@@ -11,8 +11,14 @@ Source: %{name}-%{version}.tar.bz2
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libglibutil) >= %{libglibutil_version}
BuildRequires: pkgconfig
BuildRequires: bison
BuildRequires: flex
# license macro requires rpm >= 4.11
BuildRequires: pkgconfig(rpm)
%define license_support %(pkg-config --exists 'rpm >= 4.11'; echo $?)
Requires: libglibutil >= %{libglibutil_version}
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
@@ -23,7 +29,6 @@ C interfaces for Android binder
%package devel
Summary: Development library for %{name}
Requires: %{name} = %{version}
Requires: pkgconfig
%description devel
This package contains the development library for %{name}.
@@ -39,7 +44,6 @@ make -C test/binder-ping KEEP_SYMBOLS=1 release
make -C test/binder-call KEEP_SYMBOLS=1 release
%install
rm -rf %{buildroot}
make LIBDIR=%{_libdir} DESTDIR=%{buildroot} install-dev
make -C test/binder-bridge DESTDIR=%{buildroot} install
make -C test/binder-list DESTDIR=%{buildroot} install
@@ -56,9 +60,13 @@ make -C unit test
%files
%defattr(-,root,root,-)
%{_libdir}/%{name}.so.*
%if %{license_support} == 0
%license LICENSE
%endif
%files devel
%defattr(-,root,root,-)
%dir %{_includedir}/gbinder
%{_libdir}/pkgconfig/*.pc
%{_libdir}/%{name}.so
%{_includedir}/gbinder/*.h

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -251,6 +251,15 @@ gbinder_buffer_io(
return driver ? gbinder_driver_io(driver) : NULL;
}
const GBinderRpcProtocol*
gbinder_buffer_protocol(
GBinderBuffer* buf)
{
GBinderDriver* driver = gbinder_buffer_driver(buf);
return driver ? gbinder_driver_protocol(driver) : NULL;
}
void**
gbinder_buffer_objects(
GBinderBuffer* self)

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -73,6 +73,11 @@ gbinder_buffer_io(
GBinderBuffer* buf)
GBINDER_INTERNAL;
const GBinderRpcProtocol*
gbinder_buffer_protocol(
GBinderBuffer* buf)
GBINDER_INTERNAL;
void**
gbinder_buffer_objects(
GBinderBuffer* buffer)

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -282,7 +282,8 @@ gbinder_client_new2(
priv->ranges = g_new0(GBinderClientIfaceRange, 1);
priv->ranges[0].last_code = UINT_MAX;
priv->ranges[0].basic_req = gbinder_local_request_new
(gbinder_driver_io(driver), NULL);
(gbinder_driver_io(driver), gbinder_driver_protocol(driver),
NULL);
}
return self;
}
@@ -351,15 +352,32 @@ gbinder_client_interface2(
return NULL;
}
GBytes*
gbinder_client_rpc_header(
GBinderClient* self,
guint32 code) /* since 1.1.14 */
{
if (G_LIKELY(self)) {
const GBinderClientIfaceRange* r =
gbinder_client_find_range(gbinder_client_cast(self), code);
if (r) {
return r->rpc_header;
}
}
return NULL;
}
GBinderLocalRequest*
gbinder_client_new_request(
GBinderClient* self)
{
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
const GBinderIo* io = gbinder_driver_io(self->remote->ipc->driver);
GBinderDriver* driver = self->remote->ipc->driver;
return gbinder_local_request_new(io, priv->ranges->rpc_header);
return gbinder_local_request_new(gbinder_driver_io(driver),
gbinder_driver_protocol(driver), priv->ranges->rpc_header);
}
return NULL;
}
@@ -371,13 +389,14 @@ gbinder_client_new_request2(
{
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
const GBinderClientIfaceRange* r = gbinder_client_find_range
const GBinderClientIfaceRange* range = gbinder_client_find_range
(priv, code);
if (r) {
const GBinderIo* io = gbinder_driver_io(self->remote->ipc->driver);
if (range) {
GBinderDriver* driver = self->remote->ipc->driver;
return gbinder_local_request_new(io, r->rpc_header);
return gbinder_local_request_new(gbinder_driver_io(driver),
gbinder_driver_protocol(driver), range->rpc_header);
}
}
return NULL;

View File

@@ -113,9 +113,45 @@ static const GBinderConfigPresetGroup gbinder_config_29[] = {
{ NULL, NULL }
};
/* API level 30 */
static const GBinderConfigPresetEntry gbinder_config_30_protocol[] = {
{ "/dev/binder", "aidl3" },
{ "/dev/vndbinder", "aidl3" },
{ NULL, NULL }
};
static const GBinderConfigPresetEntry gbinder_config_30_servicemanager[] = {
{ "/dev/binder", "aidl3" },
{ "/dev/vndbinder", "aidl3" },
{ NULL, NULL }
};
static const GBinderConfigPresetGroup gbinder_config_30[] = {
{ GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_30_protocol },
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_30_servicemanager },
{ NULL, NULL }
};
/* API level 31 */
static const GBinderConfigPresetEntry gbinder_config_31_servicemanager[] = {
{ "/dev/binder", "aidl4" },
{ "/dev/vndbinder", "aidl4" },
{ NULL, NULL }
};
static const GBinderConfigPresetGroup gbinder_config_31[] = {
{ GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_30_protocol },
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_31_servicemanager },
{ NULL, NULL }
};
/* Presets sorted by API level in descending order */
static const GBinderConfigPreset gbinder_config_presets[] = {
{ 31, gbinder_config_31 },
{ 30, gbinder_config_30 },
{ 29, gbinder_config_29 },
{ 28, gbinder_config_28 }
};

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -82,6 +82,7 @@ struct gbinder_driver {
void* vm;
gsize vmsize;
char* dev;
const char* name;
const GBinderIo* io;
const GBinderRpcProtocol* protocol;
};
@@ -169,6 +170,14 @@ gbinder_driver_verbose_transaction_data(
GVERBOSE("> %s %d (%u bytes, %u objects)", name,
tx->status, (guint)tx->size, n);
}
} else if (tx->code) {
if (tx->target) {
GVERBOSE("> %s %p 0x%08x (%u bytes, %u objects)", name,
tx->target, tx->code, (guint)tx->size, n);
} else {
GVERBOSE("> %s 0x%08x (%u bytes, %u objects)", name,
tx->code, (guint)tx->size, n);
}
} else {
if (tx->target) {
GVERBOSE("> %s %p (%u bytes, %u objects)", name,
@@ -187,6 +196,14 @@ gbinder_driver_verbose_transaction_data(
GVERBOSE("> %s %d (%u bytes)", name, tx->status, (guint)
tx->size);
}
} else if (tx->code) {
if (tx->target) {
GVERBOSE("> %s %p 0x%08x (%u bytes)", name,
tx->target, tx->code, (guint)tx->size);
} else {
GVERBOSE("> %s 0x%08x (%u bytes)", name,
tx->code, (guint)tx->size);
}
} else {
if (tx->target) {
GVERBOSE("> %s %p (%u bytes)", name, tx->target, (guint)
@@ -549,7 +566,8 @@ gbinder_driver_handle_transaction(
tx.flags, &txstatus);
break;
default:
GWARN("Unhandled transaction %s 0x%08x", iface, tx.code);
GWARN("Unhandled transaction %s 0x%08x from %s", iface, tx.code,
self->name);
break;
}
@@ -879,6 +897,9 @@ gbinder_driver_new(
self->vm = vm;
self->vmsize = vmsize;
self->dev = g_strdup(dev);
self->name = self->dev + /* Shorter version for logging */
(g_str_has_prefix(self->dev, "/dev/") ? 5 : 0);
if (gbinder_system_ioctl(fd, BINDER_SET_MAX_THREADS,
&max_threads) < 0) {
GERR("%s failed to set max threads (%u): %s", dev,
@@ -1303,8 +1324,9 @@ GBinderLocalRequest*
gbinder_driver_local_request_new_ping(
GBinderDriver* self)
{
GBinderLocalRequest* req = gbinder_local_request_new(self->io, NULL);
GBinderWriter writer;
GBinderLocalRequest* req = gbinder_local_request_new(self->io,
self->protocol, NULL);
gbinder_local_request_init_writer(req, &writer);
self->protocol->write_ping(&writer);

699
src/gbinder_fmq.c Normal file
View File

@@ -0,0 +1,699 @@
/*
* Copyright (C) 2021 Jolla Ltd.
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_fmq_p.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/futex.h>
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#if GBINDER_FMQ_SUPPORTED
/* Grantor data positions */
enum {
READ_PTR_POS = 0,
WRITE_PTR_POS,
DATA_PTR_POS,
EVENT_FLAG_PTR_POS
};
typedef struct gbinder_fmq {
GBinderMQDescriptor* desc;
guint8* ring;
guint64* read_ptr;
guint64* write_ptr;
guint32* event_flag_ptr;
guint32 refcount;
} GBinderFmq;
GBINDER_INLINE_FUNC
GBinderFmqGrantorDescriptor*
gbinder_fmq_get_grantor_descriptor(
GBinderFmq* self,
gint index)
{
return (GBinderFmqGrantorDescriptor*)(self->desc->grantors.data.ptr) +
index;
}
static
gsize
gbinder_fmq_available_to_read_bytes(
GBinderFmq* self,
gboolean contiguous)
{
const guint64 read_ptr = __atomic_load_n(self->read_ptr, __ATOMIC_ACQUIRE);
const gsize available_total = __atomic_load_n(self->write_ptr,
__ATOMIC_ACQUIRE) - read_ptr;
if (contiguous) {
/*
* The number of bytes that can be read contiguously from
* read offset without wrapping around the ring buffer.
*/
const gsize size = gbinder_fmq_get_grantor_descriptor(self,
DATA_PTR_POS)->extent;
const gsize available_contiguous = size - (read_ptr % size);
return (available_contiguous < available_total) ?
available_contiguous : available_total;
} else {
return available_total;
}
}
static
gsize
gbinder_fmq_available_to_write_bytes(
GBinderFmq* self,
gboolean contiguous)
{
const guint32 size = gbinder_fmq_get_grantor_descriptor(self,
DATA_PTR_POS)->extent;
const gsize available_total = size -
gbinder_fmq_available_to_read_bytes(self, FALSE);
if (contiguous) {
/*
* The number of bytes that can be written contiguously starting from
* write_offset without wrapping around the ring buffer.
*/
const guint64 write_ptr = __atomic_load_n(self->write_ptr,
__ATOMIC_RELAXED);
const gsize available_contiguous = size - (write_ptr % size);
return (available_contiguous < available_total) ?
available_contiguous : available_total;
} else {
return available_total;
}
}
static
GBinderFmqGrantorDescriptor*
gbinder_fmq_create_grantors(
gsize queue_size_bytes,
gsize num_fds,
gboolean configure_event_flag)
{
const gsize num_grantors = configure_event_flag ?
(EVENT_FLAG_PTR_POS + 1) : (DATA_PTR_POS + 1);
GBinderFmqGrantorDescriptor* grantors =
g_new0(GBinderFmqGrantorDescriptor, num_grantors);
gsize pos, offset;
gsize mem_sizes[] = {
sizeof(guint64), /* read pointer counter */
sizeof(guint64), /* write pointer counter */
queue_size_bytes, /* data buffer */
sizeof(guint32) /* event flag pointer */
};
for (pos = 0, offset = 0; pos < num_grantors; pos++) {
GBinderFmqGrantorDescriptor* grantor = grantors + pos;
guint32 grantor_fd_index;
gsize grantor_offset;
if (pos == DATA_PTR_POS && num_fds == 2) {
grantor_fd_index = 1;
grantor_offset = 0;
} else {
grantor_fd_index = 0;
grantor_offset = offset;
offset += mem_sizes[pos];
}
grantor->fd_index = grantor_fd_index;
grantor->offset = (guint32)G_ALIGN8(grantor_offset);
grantor->extent = mem_sizes[pos];
}
return grantors;
}
static
void*
gbinder_fmq_map_grantor_descriptor(
GBinderFmq* self,
guint32 index)
{
if (index < self->desc->grantors.count) {
const GBinderFmqGrantorDescriptor* desc =
gbinder_fmq_get_grantor_descriptor(self, index);
/* Offset for mmap must be a multiple of PAGE_SIZE */
const guint32 map_offset = (desc->offset & ~(getpagesize()-1));
const guint32 map_length = desc->offset - map_offset + desc->extent;
const GBinderFds* fds = self->desc->data.fds;
void* address = mmap(0, map_length, PROT_READ | PROT_WRITE, MAP_SHARED,
gbinder_fds_get_fd(fds, desc->fd_index), map_offset);
if (address != MAP_FAILED) {
return (guint8*)address + (desc->offset - map_offset);
} else {
GWARN("mmap failed: %d", errno);
}
}
return NULL;
}
static
void
gbinder_fmq_unmap_grantor_descriptor(
GBinderFmq* self,
void* address,
guint index)
{
if (index < self->desc->grantors.count && address) {
const GBinderFmqGrantorDescriptor* desc =
gbinder_fmq_get_grantor_descriptor(self, index);
const gsize remainder = desc->offset & (getpagesize() - 1);
munmap((guint8*)address - remainder, remainder + desc->extent);
}
}
static
void
gbinder_fmq_free(
GBinderFmq* self)
{
if (self->desc) {
if (self->desc->flags == GBINDER_FMQ_TYPE_UNSYNC_WRITE) {
g_free(self->read_ptr);
} else {
gbinder_fmq_unmap_grantor_descriptor(self, self->read_ptr,
READ_PTR_POS);
}
gbinder_fmq_unmap_grantor_descriptor(self, self->write_ptr,
WRITE_PTR_POS);
gbinder_fmq_unmap_grantor_descriptor(self, self->ring,
DATA_PTR_POS);
gbinder_fmq_unmap_grantor_descriptor(self, self->event_flag_ptr,
EVENT_FLAG_PTR_POS);
g_free((GBinderFmqGrantorDescriptor*)self->desc->grantors.data.ptr);
g_free((GBinderFds*)self->desc->data.fds);
g_free(self->desc);
}
g_slice_free(GBinderFmq, self);
}
/* Private API */
GBinderMQDescriptor*
gbinder_fmq_get_descriptor(
const GBinderFmq* self)
{
return self->desc;
}
/* Public API */
GBinderFmq*
gbinder_fmq_new(
gsize item_size,
gsize num_items,
GBINDER_FMQ_TYPE type,
GBINDER_FMQ_FLAGS flags,
gint fd,
gsize buffer_size)
{
if (item_size <= 0) {
GWARN("Incorrect item size");
} else if (num_items <= 0) {
GWARN("Empty queue requested");
} else if (num_items > SIZE_MAX / item_size) {
GWARN("Requested message queue size too large");
} else if (fd != -1 && num_items * item_size > buffer_size) {
GWARN("The size needed for items (%"G_GSIZE_FORMAT") is larger "
"than the supplied buffer size (%"G_GSIZE_FORMAT")",
num_items * item_size, buffer_size);
} else {
GBinderFmq* self = g_slice_new0(GBinderFmq);
gboolean configure_event_flag =
(flags & GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG) != 0;
gsize queue_size_bytes = num_items * item_size;
gsize meta_data_size;
gsize shmem_size;
int shmem_fd;
meta_data_size = 2 * sizeof(guint64);
if (configure_event_flag) {
meta_data_size += sizeof(guint32);
}
/* Allocate shared memory */
if (fd != -1) {
/* User-supplied ringbuffer memory provided,
* allocating memory only for meta data */
shmem_size = (meta_data_size + getpagesize() - 1) &
~(getpagesize() - 1);
} else {
/* Allocate ringbuffer, read counter and write counter */
shmem_size = (G_ALIGN8(queue_size_bytes) +
meta_data_size + getpagesize() - 1) & ~(getpagesize() - 1);
}
shmem_fd = syscall(__NR_memfd_create, "MessageQueue", MFD_CLOEXEC);
if (shmem_fd >= 0 && ftruncate(shmem_fd, shmem_size) == 0) {
GBinderFmqGrantorDescriptor* grantors;
gsize num_fds = (fd != -1) ? 2 : 1;
gsize fds_size = sizeof(GBinderFds) + sizeof(int) * num_fds;
GBinderFds* fds = (GBinderFds*)g_malloc0(fds_size);
fds->version = fds_size;
fds->num_fds = num_fds;
(((int*)((fds) + 1))[0]) = shmem_fd;
if (fd != -1) {
/* Use user-supplied file descriptor for fd_index 1 */
(((int*)((fds) + 1))[1]) = fd;
}
grantors = gbinder_fmq_create_grantors(queue_size_bytes,
num_fds, configure_event_flag);
/* Fill FMQ descriptor */
self->desc = g_new0(GBinderMQDescriptor, 1);
self->desc->data.fds = fds;
self->desc->quantum = item_size;
self->desc->flags = type;
self->desc->grantors.data.ptr = grantors;
self->desc->grantors.count = configure_event_flag ?
(EVENT_FLAG_PTR_POS + 1) : (DATA_PTR_POS + 1);
self->desc->grantors.owns_buffer = TRUE;
/* Initialize memory pointers */
if (type == GBINDER_FMQ_TYPE_SYNC_READ_WRITE) {
self->read_ptr = gbinder_fmq_map_grantor_descriptor(self,
READ_PTR_POS);
} else {
/*
* Unsynchronized write FMQs may have multiple readers and
* each reader would have their own read pointer counter.
*/
self->read_ptr = g_new0(guint64, 1);
}
if (!self->read_ptr) {
GWARN("Read pointer is null");
}
self->write_ptr = gbinder_fmq_map_grantor_descriptor(self,
WRITE_PTR_POS);
if (!self->write_ptr) {
GWARN("Write pointer is null");
}
if (!(flags & GBINDER_FMQ_FLAG_NO_RESET_POINTERS)) {
__atomic_store_n(self->read_ptr, 0, __ATOMIC_RELEASE);
__atomic_store_n(self->write_ptr, 0, __ATOMIC_RELEASE);
} else if (type != GBINDER_FMQ_TYPE_SYNC_READ_WRITE) {
/* Always reset the read pointer */
__atomic_store_n(self->read_ptr, 0, __ATOMIC_RELEASE);
}
self->ring = gbinder_fmq_map_grantor_descriptor(self,
DATA_PTR_POS);
if (!self->ring) {
GWARN("Ring buffer pointer is null");
}
if (self->desc->grantors.count > EVENT_FLAG_PTR_POS) {
self->event_flag_ptr = gbinder_fmq_map_grantor_descriptor(self,
EVENT_FLAG_PTR_POS);
if (!self->event_flag_ptr) {
GWARN("Event flag pointer is null");
}
}
g_atomic_int_set(&self->refcount, 1);
return self;
}
GWARN("Failed to allocate shared memory: %s", strerror(errno));
gbinder_fmq_free(self);
}
return NULL;
}
GBinderFmq*
gbinder_fmq_ref(
GBinderFmq* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_fmq_unref(
GBinderFmq* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_fmq_free(self);
}
}
}
gsize
gbinder_fmq_available_to_read(
GBinderFmq* self)
{
return G_LIKELY(self) ? (gbinder_fmq_available_to_read_bytes(self, FALSE) /
self->desc->quantum) : 0;
}
gsize
gbinder_fmq_available_to_write(
GBinderFmq* self)
{
return G_LIKELY(self) ? (gbinder_fmq_available_to_write_bytes(self, FALSE) /
self->desc->quantum) : 0;
}
gsize
gbinder_fmq_available_to_read_contiguous(
GBinderFmq* self)
{
return G_LIKELY(self) ? (gbinder_fmq_available_to_read_bytes(self, TRUE) /
self->desc->quantum) : 0;
}
gsize
gbinder_fmq_available_to_write_contiguous(
GBinderFmq* self)
{
return G_LIKELY(self) ? (gbinder_fmq_available_to_write_bytes(self, TRUE) /
self->desc->quantum) : 0;
}
const void*
gbinder_fmq_begin_read(
GBinderFmq* self,
gsize items)
{
void* ptr = NULL;
if (G_LIKELY(self) && G_LIKELY(items > 0)) {
gsize size = gbinder_fmq_get_grantor_descriptor(self,
DATA_PTR_POS)->extent;
gsize item_size = self->desc->quantum;
gsize bytes_desired = items * item_size;
guint64 write_ptr = __atomic_load_n(self->write_ptr, __ATOMIC_ACQUIRE);
guint64 read_ptr = __atomic_load_n(self->read_ptr, __ATOMIC_RELAXED);
if ((write_ptr % item_size) || (read_ptr % item_size)) {
GWARN("Unable to write data because of misaligned pointer");
} else if (write_ptr - read_ptr > size) {
__atomic_store_n(self->read_ptr, write_ptr, __ATOMIC_RELEASE);
} else if (write_ptr - read_ptr < bytes_desired) {
/* Not enough data to read in FMQ. */
} else {
ptr = self->ring + (read_ptr % size);
}
}
return ptr;
}
void*
gbinder_fmq_begin_write(
GBinderFmq* self,
gsize items)
{
void* ptr = NULL;
if (G_LIKELY(self) && G_LIKELY(items > 0)) {
const gsize item_size = self->desc->quantum;
const gsize size = gbinder_fmq_get_grantor_descriptor(self,
DATA_PTR_POS)->extent;
if ((self->desc->flags == GBINDER_FMQ_TYPE_SYNC_READ_WRITE &&
(gbinder_fmq_available_to_write(self) < items)) ||
items > size / item_size) {
/* Incorrect parameters */
} else {
guint64 write_ptr = __atomic_load_n(self->write_ptr,
__ATOMIC_RELAXED);
if (write_ptr % item_size) {
GWARN("The write pointer has become misaligned.");
} else {
ptr = self->ring + (write_ptr % size);
}
}
}
return ptr;
}
void
gbinder_fmq_end_read(
GBinderFmq* self,
gsize items)
{
if (G_LIKELY(self) && G_LIKELY(items > 0)) {
gsize size = gbinder_fmq_get_grantor_descriptor(self,
DATA_PTR_POS)->extent;
guint64 read_ptr = __atomic_load_n(self->read_ptr, __ATOMIC_RELAXED);
guint64 write_ptr = __atomic_load_n(self->write_ptr, __ATOMIC_ACQUIRE);
/*
* If queue type is unsynchronized, it is possible that a write
* overflow may have occurred.
*/
if (write_ptr - read_ptr > size) {
__atomic_store_n(self->read_ptr, write_ptr, __ATOMIC_RELEASE);
} else {
read_ptr += items * self->desc->quantum;
__atomic_store_n(self->read_ptr, read_ptr, __ATOMIC_RELEASE);
}
}
}
void
gbinder_fmq_end_write(
GBinderFmq* self,
gsize items)
{
if (G_LIKELY(self) && G_LIKELY(items > 0)) {
guint64 write_ptr = __atomic_load_n(self->write_ptr, __ATOMIC_RELAXED);
write_ptr += items * self->desc->quantum;
__atomic_store_n(self->write_ptr, write_ptr, __ATOMIC_RELEASE);
}
}
gboolean
gbinder_fmq_read(
GBinderFmq* self,
void* data,
gsize items)
{
if (G_LIKELY(self) && G_LIKELY(data) && G_LIKELY(items > 0)) {
const void* in_data = gbinder_fmq_begin_read(self, items);
if (in_data) {
/*
* The number of messages that can be read contiguously without
* wrapping around the ring buffer.
*/
const gsize contiguous_messages =
gbinder_fmq_available_to_read_contiguous(self);
const gsize item_size = self->desc->quantum;
if (contiguous_messages < items) {
/* A wrap around is required */
memcpy(data, in_data, contiguous_messages * item_size);
memcpy((char*)data + contiguous_messages * item_size,
self->ring, (items - contiguous_messages) * item_size);
} else {
/* A wrap around is not required */
memcpy(data, in_data, items * item_size);
}
gbinder_fmq_end_read(self, items);
return TRUE;
}
}
return FALSE;
}
gboolean
gbinder_fmq_write(
GBinderFmq* self,
const void* data,
gsize items)
{
if (G_LIKELY(self) && G_LIKELY(data) && G_LIKELY(items > 0)) {
void *out_data = gbinder_fmq_begin_write(self, items);
if (out_data) {
/*
* The number of messages that can be written contiguously without
* wrapping around the ring buffer.
*/
const gsize contiguous_messages =
gbinder_fmq_available_to_write_contiguous(self);
const gsize item_size = self->desc->quantum;
if (contiguous_messages < items) {
/* A wrap around is required. */
memcpy(out_data, data, contiguous_messages * item_size);
memcpy(self->ring, (char *)data + contiguous_messages *
item_size / sizeof(char),
(items - contiguous_messages) * item_size);
} else {
/* A wrap around is not required to write items */
memcpy(out_data, data, items * item_size);
}
gbinder_fmq_end_write(self, items);
return TRUE;
}
}
return FALSE;
}
int
gbinder_fmq_wait_timeout(
GBinderFmq* self,
guint32 bit_mask,
guint32* state,
int timeout_ms)
{
if (G_UNLIKELY(!state) || G_UNLIKELY(!self)) {
return (-EINVAL);
} else if (!self->event_flag_ptr) {
return (-ENOSYS);
} else if (!bit_mask) {
return (-EINVAL);
} else {
guint32 old_value = __atomic_fetch_and(self->event_flag_ptr, ~bit_mask,
__ATOMIC_SEQ_CST);
guint32 set_bits = old_value & bit_mask;
/* Check if any of the bits was already set */
if (set_bits != 0) {
*state = set_bits;
return 0;
} else if (!timeout_ms) {
return (-ETIMEDOUT);
} else {
int ret;
if (timeout_ms > 0) {
struct timespec deadline;
const guint64 ms = 1000000;
const guint64 sec = 1000 * ms;
clock_gettime(CLOCK_MONOTONIC, &deadline);
deadline.tv_sec += timeout_ms / 1000;
deadline.tv_nsec += (timeout_ms % 1000) * ms;
if (deadline.tv_nsec >= sec) {
deadline.tv_sec++;
deadline.tv_nsec -= sec;
}
ret = syscall(__NR_futex, self->event_flag_ptr,
FUTEX_WAIT_BITSET, old_value, &deadline, NULL, bit_mask);
} else {
ret = syscall(__NR_futex, self->event_flag_ptr,
FUTEX_WAIT_BITSET, old_value, NULL, NULL, bit_mask);
}
if (ret == -1) {
return errno ? (-errno) : -EFAULT;
} else {
old_value = __atomic_fetch_and(self->event_flag_ptr, ~bit_mask,
__ATOMIC_SEQ_CST);
*state = old_value & bit_mask;
return (*state) ? 0 : (-EAGAIN);
}
}
}
}
int
gbinder_fmq_wake(
GBinderFmq* self,
guint32 bit_mask)
{
int ret = 0;
if (G_LIKELY(self)) {
if (!self->event_flag_ptr) {
/* Event flag is not configured */
ret = -ENOSYS;
} else if (!bit_mask) {
/* Ignore zero bit mask */
} else {
/* Set bit mask only if needed */
guint32 old_value = __atomic_fetch_or(self->event_flag_ptr,
bit_mask, __ATOMIC_SEQ_CST);
if (~old_value & bit_mask) {
ret = syscall(__NR_futex, self->event_flag_ptr,
FUTEX_WAKE_BITSET, G_MAXUINT32, NULL, NULL, bit_mask);
}
if (ret == -1) {
/* Report error code */
ret = -errno;
}
}
} else {
ret = -EINVAL;
}
return ret;
}
#else /* !GBINDER_FMQ_SUPPORTED */
#pragma message("Not compiling FMQ")
#endif
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

102
src/gbinder_fmq_p.h Normal file
View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2021 Jolla Ltd.
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_FMQ_PRIVATE_H
#define GBINDER_FMQ_PRIVATE_H
#include <gbinder_fmq.h>
#include "gbinder_types_p.h"
/* FMQ functionality requires __NR_memfd_create syscall */
#include <sys/syscall.h>
#ifdef __NR_memfd_create
# define GBINDER_FMQ_SUPPORTED 1
#else
# define GBINDER_FMQ_SUPPORTED 0
#endif
/*
* From linux/memfd.h
*/
#ifndef MFD_CLOEXEC
# define MFD_CLOEXEC 0x0001U
#endif
/*
* FMQ types
*/
typedef struct gbinder_fmq_grantor_descriptor {
guint32 flags GBINDER_ALIGNED(4);
guint32 fd_index GBINDER_ALIGNED(4);
guint32 offset GBINDER_ALIGNED(4);
guint64 extent GBINDER_ALIGNED(8);
} GBinderFmqGrantorDescriptor;
G_STATIC_ASSERT(G_STRUCT_OFFSET(GBinderFmqGrantorDescriptor, flags) == 0);
G_STATIC_ASSERT(G_STRUCT_OFFSET(GBinderFmqGrantorDescriptor, fd_index) == 4);
G_STATIC_ASSERT(G_STRUCT_OFFSET(GBinderFmqGrantorDescriptor, offset) == 8);
G_STATIC_ASSERT(G_STRUCT_OFFSET(GBinderFmqGrantorDescriptor, extent) == 16);
G_STATIC_ASSERT(sizeof(GBinderFmqGrantorDescriptor) == 24);
typedef struct gbinder_mq_descriptor {
GBinderHidlVec grantors;
union {
guint64 value;
const GBinderFds* fds;
} data;
guint32 quantum;
guint32 flags;
} GBinderMQDescriptor;
#define GBINDER_MQ_DESCRIPTOR_GRANTORS_OFFSET (0)
#define GBINDER_MQ_DESCRIPTOR_FDS_OFFSET (16)
G_STATIC_ASSERT(G_STRUCT_OFFSET(GBinderMQDescriptor, grantors) ==
GBINDER_MQ_DESCRIPTOR_GRANTORS_OFFSET);
G_STATIC_ASSERT(G_STRUCT_OFFSET(GBinderMQDescriptor, data) ==
GBINDER_MQ_DESCRIPTOR_FDS_OFFSET);
G_STATIC_ASSERT(sizeof(GBinderMQDescriptor) == 32);
GBinderMQDescriptor*
gbinder_fmq_get_descriptor(
const GBinderFmq* self)
GBINDER_INTERNAL;
#endif /* GBINDER_FMQ_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -35,6 +35,7 @@
#include "gbinder_local_object_p.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_writer.h"
#include "gbinder_system.h"
#include "gbinder_log.h"
@@ -94,7 +95,8 @@ GBINDER_IO_FN(write_read)(
static
gsize
GBINDER_IO_FN(object_size)(
const void* obj)
const void* obj,
const GBinderRpcProtocol* protocol)
{
if (obj) {
const struct binder_object_header* hdr = obj;
@@ -104,7 +106,8 @@ GBINDER_IO_FN(object_size)(
case BINDER_TYPE_WEAK_BINDER:
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE:
return sizeof(struct flat_binder_object);
return sizeof(struct flat_binder_object) +
protocol->flat_binder_object_extra;
case BINDER_TYPE_FD:
return sizeof(struct binder_fd_object);
case BINDER_TYPE_FDA:
@@ -166,7 +169,8 @@ static
guint
GBINDER_IO_FN(encode_local_object)(
void* out,
GBinderLocalObject* obj)
GBinderLocalObject* obj,
const GBinderRpcProtocol* protocol)
{
struct flat_binder_object* dest = out;
@@ -176,9 +180,14 @@ GBINDER_IO_FN(encode_local_object)(
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
} else {
dest->hdr.type = BINDER_TYPE_WEAK_BINDER;
dest->hdr.type = BINDER_TYPE_HANDLE;
}
return sizeof(*dest);
if (protocol->finish_flatten_binder) {
protocol->finish_flatten_binder(dest + 1, obj);
} else if (protocol->flat_binder_object_extra) {
memset(dest + 1, 0, protocol->flat_binder_object_extra);
}
return sizeof(*dest) + protocol->flat_binder_object_extra;
}
static
@@ -215,6 +224,23 @@ GBINDER_IO_FN(encode_fd_object)(
return sizeof(*dest);
}
static
guint
GBINDER_IO_FN(encode_fda_object)(
void* out,
const GBinderFds *fds,
const GBinderParent* parent)
{
struct binder_fd_array_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_FDA;
dest->num_fds = fds->num_fds;
dest->parent = parent->index;
dest->parent_offset = parent->offset;
return sizeof(*dest);
}
/* Encodes binder_buffer_object */
static
guint
@@ -263,7 +289,7 @@ GBINDER_IO_FN(encode_ptr_cookie)(
/* We never send these cookies and don't expect them back */
dest->ptr = (uintptr_t)obj;
dest->cookie = 0;
return sizeof(dest);
return sizeof(*dest);
}
/* Fills binder_transaction_data for BC_TRANSACTION/REPLY */
@@ -483,7 +509,8 @@ static
guint
GBINDER_IO_FN(decode_binder_handle)(
const void* data,
guint32* handle)
guint32* handle,
const GBinderRpcProtocol* protocol)
{
const struct flat_binder_object* obj = data;
@@ -492,7 +519,7 @@ GBINDER_IO_FN(decode_binder_handle)(
if (handle) {
*handle = obj->handle;
}
return sizeof(*obj);
return sizeof(*obj) + protocol->flat_binder_object_extra;
}
return 0;
}
@@ -503,7 +530,8 @@ GBINDER_IO_FN(decode_binder_object)(
const void* data,
gsize size,
GBinderObjectRegistry* reg,
GBinderRemoteObject** out)
GBinderRemoteObject** out,
const GBinderRpcProtocol* protocol)
{
const struct flat_binder_object* obj = data;
@@ -513,15 +541,18 @@ GBINDER_IO_FN(decode_binder_object)(
if (out) {
*out = gbinder_object_registry_get_remote(reg, obj->handle,
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE);
if (*out && protocol->finish_unflatten_binder) {
protocol->finish_unflatten_binder(obj + 1, *out);
}
}
return sizeof(*obj);
return sizeof(*obj) + protocol->flat_binder_object_extra;
case BINDER_TYPE_BINDER:
if (!obj->binder) {
/* That's a NULL reference */
if (out) {
*out = NULL;
}
return sizeof(*obj);
return sizeof(*obj) + protocol->flat_binder_object_extra;
}
/* fallthrough */
default:
@@ -637,6 +668,7 @@ const GBinderIo GBINDER_IO_PREFIX = {
.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_fda_object = GBINDER_IO_FN(encode_fda_object),
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
.encode_handle_cookie = GBINDER_IO_FN(encode_handle_cookie),
.encode_ptr_cookie = GBINDER_IO_FN(encode_ptr_cookie),
@@ -663,6 +695,10 @@ const GBinderIo GBINDER_IO_PREFIX = {
G_STATIC_ASSERT(GBINDER_POINTER_SIZE <= GBINDER_MAX_POINTER_SIZE);
G_STATIC_ASSERT(sizeof(struct flat_binder_object) <=
GBINDER_MAX_BINDER_OBJECT_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_fd_object) <=
GBINDER_MAX_BUFFER_OBJECT_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_fd_array_object) <=
GBINDER_MAX_BUFFER_OBJECT_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_buffer_object) <=
GBINDER_MAX_BUFFER_OBJECT_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_handle_cookie) <=

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -126,7 +126,7 @@ struct gbinder_io {
} br;
/* Size of the object and its extra data */
gsize (*object_size)(const void* obj);
gsize (*object_size)(const void* obj, const GBinderRpcProtocol* protocol);
gsize (*object_data_size)(const void* obj);
/* Writes pointer to the buffer. The destination buffer must have
@@ -142,10 +142,13 @@ struct gbinder_io {
guint (*encode_cookie)(void* out, guint64 cookie);
/* Encode flat_buffer_object */
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
#define GBINDER_MAX_BINDER_OBJECT_SIZE (28)
guint (*encode_local_object)(void* out, GBinderLocalObject* obj,
const GBinderRpcProtocol* protocol);
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
guint (*encode_fd_object)(void* out, int fd);
guint (*encode_fda_object)(void* out, const GBinderFds *fds,
const GBinderParent* parent);
/* Encode binder_buffer_object */
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
@@ -187,9 +190,11 @@ struct gbinder_io {
void (*decode_transaction_data)(const void* data, GBinderIoTxData* tx);
void* (*decode_ptr_cookie)(const void* data);
guint (*decode_cookie)(const void* data, guint64* cookie);
guint (*decode_binder_handle)(const void* obj, guint32* handle);
guint (*decode_binder_handle)(const void* obj, guint32* handle,
const GBinderRpcProtocol* protocol);
guint (*decode_binder_object)(const void* data, gsize size,
GBinderObjectRegistry* reg, GBinderRemoteObject** obj);
GBinderObjectRegistry* reg, GBinderRemoteObject** obj,
const GBinderRpcProtocol* protocol);
guint (*decode_buffer_object)(GBinderBuffer* buf, gsize offset,
GBinderIoBufferObject* out);
guint (*decode_fd_object)(const void* data, gsize size, int* fd);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -58,11 +58,13 @@
#include <time.h>
typedef struct gbinder_ipc_looper GBinderIpcLooper;
typedef GObjectClass GBinderIpcClass;
struct gbinder_ipc_priv {
GBinderIpc* self;
GThreadPool* tx_pool;
GHashTable* tx_table;
char* dev;
char* key;
const char* name;
GBinderObjectRegistry object_registry;
@@ -78,11 +80,12 @@ struct gbinder_ipc_priv {
GBinderIpcLooper* blocked_loopers;
};
typedef GObjectClass GBinderIpcClass;
#define PARENT_CLASS gbinder_ipc_parent_class
#define THIS_TYPE gbinder_ipc_get_type()
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, THIS_TYPE, GBinderIpc)
GType THIS_TYPE GBINDER_INTERNAL;
G_DEFINE_TYPE(GBinderIpc, gbinder_ipc, G_TYPE_OBJECT)
#define GBINDER_TYPE_IPC (gbinder_ipc_get_type())
#define GBINDER_IPC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_IPC, GBinderIpc))
/*
* Binder requests are blocking, worker threads are needed in order to
@@ -207,9 +210,6 @@ typedef struct gbinder_ipc_tx_custom {
GDestroyNotify fn_custom_destroy;
} GBinderIpcTxCustom;
GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self)
{ return self->priv->name; }
static
GBinderIpcLooper*
gbinder_ipc_looper_new(
@@ -266,6 +266,15 @@ gbinder_ipc_wait(
return FALSE;
}
static
char*
gbinder_ipc_make_key(
const char* dev,
const char* protocol)
{
return g_strdup_printf("%s:%s", protocol, dev);
}
/*==========================================================================*
* GBinderIpcLooperTx
*==========================================================================*/
@@ -1115,6 +1124,23 @@ gbinder_ipc_tx_handler_transact(
* GBinderObjectRegistry
*==========================================================================*/
static
void
gbinder_ipc_invalidate_local_object_locked(
GBinderIpc* self,
GBinderLocalObject* obj)
{
GBinderIpcPriv* priv = self->priv;
if (priv->local_objects && g_hash_table_remove(priv->local_objects, obj)) {
GVERBOSE_("%p %s", obj, gbinder_ipc_name(self));
if (g_hash_table_size(priv->local_objects) == 0) {
g_hash_table_unref(priv->local_objects);
priv->local_objects = NULL;
}
}
}
static
void
gbinder_ipc_invalidate_remote_handle_locked(
@@ -1140,6 +1166,20 @@ gbinder_ipc_invalidate_remote_handle_locked(
}
}
void
gbinder_ipc_invalidate_local_object(
GBinderIpc* self,
GBinderLocalObject* obj)
{
GBinderIpcPriv* priv = self->priv;
/* Lock */
g_mutex_lock(&priv->local_objects_mutex);
gbinder_ipc_invalidate_local_object_locked(self, obj);
g_mutex_unlock(&priv->local_objects_mutex);
/* Unlock */
}
void
gbinder_ipc_invalidate_remote_handle(
GBinderIpc* self,
@@ -1183,14 +1223,8 @@ gbinder_ipc_local_object_disposed(
/* Lock */
g_mutex_lock(&priv->local_objects_mutex);
if (obj->object.ref_count == 1 && priv->local_objects) {
if (g_hash_table_remove(priv->local_objects, obj)) {
GVERBOSE_("%p %s", obj, gbinder_ipc_name(self));
if (g_hash_table_size(priv->local_objects) == 0) {
g_hash_table_unref(priv->local_objects);
priv->local_objects = NULL;
}
}
if (g_atomic_int_get(&obj->object.ref_count) == 1) {
gbinder_ipc_invalidate_local_object_locked(self, obj);
}
g_mutex_unlock(&priv->local_objects_mutex);
/* Unlock */
@@ -1203,9 +1237,32 @@ gbinder_ipc_remote_object_disposed(
{
GBinderIpcPriv* priv = self->priv;
/*
* Check of ref_count for 1 makes it possible (albeit quite unlikely)
* that GBinderRemoteObject still remains in remote_objects table
* when it's being finalized.
*
* For this to happen, other thread must re-reference GBinderRemoteObject
* right before we grab the lock here (making ref_count greater than 1)
* and then release that reference before g_object_unref() re-checks the
* refcount.
*
* That's why another gbinder_ipc_invalidate_remote_handle() call from
* gbinder_remote_object_finalize() is necessary to make sure that stale
* object pointer isn't stored in the hashtable.
*
* We still have to invalidate the handle here because it's the last
* point when GObject can be legitimately re-referenced and brought
* back to life. Which means that GBinderIpc mutex has to acquired
* twice during GBinderRemoteObject destruction.
*
* The same applies to GBinderLocalObject too, except that it calls
* gbinder_ipc_invalidate_local_object() from its finalize() handler.
*/
/* Lock */
g_mutex_lock(&priv->remote_objects_mutex);
if (obj->object.ref_count == 1) {
if (g_atomic_int_get(&obj->object.ref_count) == 1) {
gbinder_ipc_invalidate_remote_handle_locked(self, obj->handle);
}
g_mutex_unlock(&priv->remote_objects_mutex);
@@ -1250,10 +1307,10 @@ gbinder_ipc_priv_get_local_object(
if (obj) {
gbinder_local_object_ref(obj);
} else {
GWARN("Unknown local object %p", pointer);
GWARN("Unknown local object %p %s", pointer, priv->name);
}
} else {
GWARN("Unknown local object %p", pointer);
GWARN("Unknown local object %p %s", pointer, priv->name);
}
g_mutex_unlock(&priv->local_objects_mutex);
/* Unlock */
@@ -1297,6 +1354,8 @@ gbinder_ipc_priv_get_remote_object(
}
GVERBOSE_("%p handle %u %s", obj, handle, gbinder_ipc_name(self));
g_hash_table_replace(priv->remote_objects, key, obj);
} else {
GWARN("Unknown handle %u %s", handle, priv->name);
}
g_mutex_unlock(&priv->remote_objects_mutex);
/* Unlock */
@@ -1794,20 +1853,25 @@ const GBinderIpcSyncApi gbinder_ipc_sync_main = {
GBinderIpc*
gbinder_ipc_new(
const char* dev)
const char* dev,
const char* protocol_name)
{
GBinderIpc* self = NULL;
const GBinderRpcProtocol* protocol;
char* key;
const GBinderRpcProtocol* protocol = (protocol_name ?
gbinder_rpc_protocol_by_name(protocol_name) : NULL);
if (!dev || !dev[0]) dev = GBINDER_DEFAULT_BINDER;
protocol = gbinder_rpc_protocol_for_device(dev); /* Never returns NULL */
if (!protocol) protocol = gbinder_rpc_protocol_for_device(dev);
key = gbinder_ipc_make_key(dev, protocol->name);
/* Lock */
pthread_mutex_lock(&gbinder_ipc_mutex);
if (gbinder_ipc_table) {
self = g_hash_table_lookup(gbinder_ipc_table, dev);
self = g_hash_table_lookup(gbinder_ipc_table, key);
}
if (self) {
g_free(key);
gbinder_ipc_ref(self);
} else {
GBinderDriver* driver = gbinder_driver_new(dev, protocol);
@@ -1815,10 +1879,11 @@ gbinder_ipc_new(
if (driver) {
GBinderIpcPriv* priv;
self = g_object_new(GBINDER_TYPE_IPC, NULL);
self = g_object_new(THIS_TYPE, NULL);
priv = self->priv;
self->driver = driver;
self->dev = priv->key = g_strdup(dev);
self->dev = priv->dev = g_strdup(dev);
priv->key = key;
self->priv->object_registry.io = gbinder_driver_io(driver);
/* gbinder_ipc_dispose will remove iself from the table */
if (!gbinder_ipc_table) {
@@ -1826,8 +1891,10 @@ gbinder_ipc_new(
}
g_hash_table_replace(gbinder_ipc_table, priv->key, self);
/* With "/dev/" prefix, it may be too long to be a thread name */
priv->name = priv->key +
(g_str_has_prefix(priv->key, "/dev/") ? 5 : 0);
priv->name = self->dev +
(g_str_has_prefix(priv->dev, "/dev/") ? 5 : 0);
} else {
g_free(key);
}
}
pthread_mutex_unlock(&gbinder_ipc_mutex);
@@ -1840,7 +1907,7 @@ gbinder_ipc_ref(
GBinderIpc* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_IPC(self));
g_object_ref(THIS(self));
return self;
} else {
return NULL;
@@ -1852,10 +1919,17 @@ gbinder_ipc_unref(
GBinderIpc* self)
{
if (G_LIKELY(self)) {
g_object_unref(GBINDER_IPC(self));
g_object_unref(THIS(self));
}
}
const char*
gbinder_ipc_name(
GBinderIpc* self)
{
return G_LIKELY(self) ? self->priv->name : NULL;
}
GBinderObjectRegistry*
gbinder_ipc_object_registry(
GBinderIpc* self)
@@ -1983,7 +2057,7 @@ gbinder_ipc_init(
.get_local = gbinder_ipc_object_registry_get_local,
.get_remote = gbinder_ipc_object_registry_get_remote
};
GBinderIpcPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self, GBINDER_TYPE_IPC,
GBinderIpcPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self, THIS_TYPE,
GBinderIpcPriv);
g_mutex_init(&priv->looper_mutex);
@@ -2034,7 +2108,7 @@ void
gbinder_ipc_dispose(
GObject* object)
{
GBinderIpc* self = GBINDER_IPC(object);
GBinderIpc* self = THIS(object);
GVERBOSE_("%s", self->dev);
/* Lock */
@@ -2058,7 +2132,7 @@ gbinder_ipc_dispose(
/* Unlock */
gbinder_ipc_stop_loopers(self);
G_OBJECT_CLASS(gbinder_ipc_parent_class)->finalize(object);
G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
}
static
@@ -2066,7 +2140,7 @@ void
gbinder_ipc_finalize(
GObject* object)
{
GBinderIpc* self = GBINDER_IPC(object);
GBinderIpc* self = THIS(object);
GBinderIpcPriv* priv = self->priv;
GASSERT(!priv->local_objects);
@@ -2080,8 +2154,9 @@ gbinder_ipc_finalize(
GASSERT(!g_hash_table_size(priv->tx_table));
g_hash_table_unref(priv->tx_table);
gbinder_driver_unref(self->driver);
g_free(priv->dev);
g_free(priv->key);
G_OBJECT_CLASS(gbinder_ipc_parent_class)->finalize(object);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
@@ -2117,9 +2192,8 @@ gbinder_ipc_exit()
/* Unlock */
for (i = ipcs; i; i = i->next) {
GBinderIpc* ipc = GBINDER_IPC(i->data);
GBinderIpc* ipc = THIS(i->data);
GBinderIpcPriv* priv = ipc->priv;
GThreadPool* pool = priv->tx_pool;
GSList* local_objs = NULL;
GSList* tx_keys = NULL;
GSList* k;
@@ -2130,8 +2204,12 @@ gbinder_ipc_exit()
gbinder_ipc_stop_loopers(ipc);
/* Make sure pooled transaction complete too */
priv->tx_pool = NULL;
g_thread_pool_free(pool, FALSE, TRUE);
if (priv->tx_pool) {
GThreadPool* pool = priv->tx_pool;
priv->tx_pool = NULL;
g_thread_pool_free(pool, FALSE, TRUE);
}
/*
* Since this function is supposed to be invoked on the main thread,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -100,7 +100,8 @@ extern const GBinderIpcSyncApi gbinder_ipc_sync_worker GBINDER_INTERNAL;
GBinderIpc*
gbinder_ipc_new(
const char* dev)
const char* dev,
const char* protocol)
GBINDER_INTERNAL;
GBinderIpc*
@@ -113,6 +114,11 @@ gbinder_ipc_unref(
GBinderIpc* ipc)
GBINDER_INTERNAL;
const char*
gbinder_ipc_name(
GBinderIpc* ipc)
GBINDER_INTERNAL;
void
gbinder_ipc_looper_check(
GBinderIpc* ipc)
@@ -149,7 +155,7 @@ gbinder_ipc_register_local_object(
GBinderRemoteObject*
gbinder_ipc_get_service_manager(
GBinderIpc* self)
GBinderIpc* ipc)
GBINDER_INTERNAL
G_GNUC_WARN_UNUSED_RESULT;
@@ -196,21 +202,27 @@ gbinder_ipc_cancel(
/* Internal for GBinderLocalObject */
void
gbinder_ipc_local_object_disposed(
GBinderIpc* self,
GBinderIpc* ipc,
GBinderLocalObject* obj)
GBINDER_INTERNAL;
void
gbinder_ipc_invalidate_local_object(
GBinderIpc* ipc,
GBinderLocalObject* obj)
GBINDER_INTERNAL;
/* Internal for GBinderRemoteObject */
void
gbinder_ipc_remote_object_disposed(
GBinderIpc* self,
GBinderIpc* ipc,
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
/* Needed by unit tests */
gboolean
gbinder_ipc_set_max_threads(
GBinderIpc* self,
GBinderIpc* ipc,
gint max_threads)
GBINDER_INTERNAL;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -89,6 +89,15 @@ static const char hidl_base_interface[] = "android.hidl.base@1.0::IBase";
* Implementation
*==========================================================================*/
static
GBinderLocalReply*
gbinder_local_object_create_reply(
GBinderLocalObject* self)
{
return gbinder_local_reply_new(gbinder_local_object_io(self),
gbinder_local_object_protocol(self));
}
static
GBINDER_LOCAL_TRANSACTION_SUPPORT
gbinder_local_object_default_can_handle_transaction(
@@ -139,8 +148,7 @@ gbinder_local_object_ping_transaction(
GBinderRemoteRequest* req,
int* status)
{
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderLocalReply* reply = gbinder_local_object_create_reply(self);
GVERBOSE(" PING_TRANSACTION");
gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK);
@@ -155,9 +163,8 @@ gbinder_local_object_interface_transaction(
GBinderRemoteRequest* req,
int* status)
{
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalObjectPriv* priv = self->priv;
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderLocalReply* reply = gbinder_local_object_create_reply(self);
GVERBOSE(" INTERFACE_TRANSACTION");
gbinder_local_reply_append_string16(reply, priv->ifaces[0]);
@@ -173,8 +180,7 @@ gbinder_local_object_hidl_ping_transaction(
int* status)
{
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderLocalReply* reply = gbinder_local_object_create_reply(self);
GVERBOSE(" HIDL_PING_TRANSACTION \"%s\"",
gbinder_remote_request_interface(req));
@@ -191,9 +197,8 @@ gbinder_local_object_hidl_get_descriptor_transaction(
int* status)
{
/*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);
GBinderLocalReply* reply = gbinder_local_object_create_reply(self);
GBinderWriter writer;
GVERBOSE(" HIDL_GET_DESCRIPTOR_TRANSACTION \"%s\"",
@@ -213,8 +218,7 @@ gbinder_local_object_hidl_descriptor_chain_transaction(
int* status)
{
/*android.hidl.base@1.0::IBase interfaceChain() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderLocalReply* reply = gbinder_local_object_create_reply(self);
GBinderWriter writer;
GVERBOSE(" HIDL_DESCRIPTOR_CHAIN_TRANSACTION \"%s\"",
@@ -480,7 +484,7 @@ gbinder_local_object_new_reply(
GBinderLocalObject* self)
{
if (G_LIKELY(self)) {
return gbinder_local_reply_new(gbinder_local_object_io(self));
return gbinder_local_object_create_reply(self);
}
return NULL;
}
@@ -644,6 +648,7 @@ gbinder_local_object_finalize(
GBinderLocalObjectPriv* priv = self->priv;
GASSERT(!self->strong_refs);
gbinder_ipc_invalidate_local_object(self->ipc, self);
gbinder_ipc_unref(self->ipc);
g_strfreev(priv->ifaces);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -92,6 +92,8 @@ GType gbinder_local_object_get_type(void) GBINDER_INTERNAL;
#define gbinder_local_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
#define gbinder_local_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
#define gbinder_local_object_protocol(obj) \
(gbinder_driver_protocol((obj)->ipc->driver))
GBinderLocalObject*
gbinder_local_object_new_with_type(

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -72,10 +72,12 @@ gbinder_local_reply_output_buffers_size(
GBinderLocalReply*
gbinder_local_reply_new(
const GBinderIo* io)
const GBinderIo* io,
const GBinderRpcProtocol* protocol)
{
GASSERT(io);
if (io) {
GASSERT(protocol);
if (io && protocol) {
GBinderLocalReply* self = g_slice_new0(GBinderLocalReply);
GBinderWriterData* data = &self->data;
GBinderOutputData* out = &self->out;
@@ -87,6 +89,7 @@ gbinder_local_reply_new(
g_atomic_int_set(&self->refcount, 1);
data->io = io;
data->protocol = protocol;
out->bytes = data->bytes = g_byte_array_new();
out->f = &local_reply_output_fn;
return self;
@@ -307,6 +310,17 @@ gbinder_local_reply_append_remote_object(
return self;
}
GBinderLocalReply*
gbinder_local_reply_append_fd(
GBinderLocalReply* self,
int fd) /* Since 1.1.14 */
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_fd(&self->data, fd);
}
return self;
}
/*
* Local Variables:
* mode: C

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -39,7 +39,8 @@
GBinderLocalReply*
gbinder_local_reply_new(
const GBinderIo* io)
const GBinderIo* io,
const GBinderRpcProtocol* protocol)
GBINDER_INTERNAL;
GBinderOutputData*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -74,10 +74,12 @@ gbinder_local_request_output_buffers_size(
GBinderLocalRequest*
gbinder_local_request_new(
const GBinderIo* io,
const GBinderRpcProtocol* protocol,
GBytes* init)
{
GASSERT(io);
if (io) {
GASSERT(protocol);
if (io && protocol) {
GBinderLocalRequest* self = g_slice_new0(GBinderLocalRequest);
GBinderWriterData* writer = &self->data;
GBinderOutputData* out = &self->out;
@@ -89,6 +91,7 @@ gbinder_local_request_new(
g_atomic_int_set(&self->refcount, 1);
writer->io = io;
writer->protocol = protocol;
if (init) {
gsize size;
gconstpointer data = g_bytes_get_data(init, &size);
@@ -111,9 +114,10 @@ gbinder_local_request_new_iface(
const GBinderRpcProtocol* protocol,
const char* iface)
{
GBinderLocalRequest* self = gbinder_local_request_new(io, NULL);
GBinderLocalRequest* self = gbinder_local_request_new(io, protocol, NULL);
if (self && G_LIKELY(protocol) && G_LIKELY(iface)) {
/* gbinder_local_request_new() fails if protocol is NULL */
if (self && G_LIKELY(iface)) {
GBinderWriter writer;
gbinder_local_request_init_writer(self, &writer);
@@ -128,7 +132,7 @@ gbinder_local_request_new_from_data(
GBinderObjectConverter* convert)
{
GBinderLocalRequest* self = gbinder_local_request_new
(gbinder_buffer_io(buffer), NULL);
(gbinder_buffer_io(buffer), gbinder_buffer_protocol(buffer), NULL);
if (self) {
gbinder_writer_data_append_contents(&self->data, buffer, 0, convert);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -40,6 +40,7 @@
GBinderLocalRequest*
gbinder_local_request_new(
const GBinderIo* io,
const GBinderRpcProtocol* protocol,
GBytes* init)
GBINDER_INTERNAL;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -60,11 +60,9 @@ struct gbinder_proxy_tx {
};
struct gbinder_proxy_object_priv {
gulong remote_death_id;
gboolean acquired;
gboolean dropped;
GBinderProxyTx* tx;
GMutex mutex; /* Protects the hashtable below */
GHashTable* subproxies;
};
G_DEFINE_TYPE(GBinderProxyObject, gbinder_proxy_object, \
@@ -76,79 +74,12 @@ G_DEFINE_TYPE(GBinderProxyObject, gbinder_proxy_object, \
#define THIS_TYPE GBINDER_TYPE_PROXY_OBJECT
#define PARENT_CLASS gbinder_proxy_object_parent_class
static
void
gbinder_proxy_object_subproxy_gone(
gpointer proxy,
GObject* subproxy)
{
GBinderProxyObject* self = THIS(proxy);
GBinderProxyObjectPriv* priv = self->priv;
/* Lock */
g_mutex_lock(&priv->mutex);
g_hash_table_remove(priv->subproxies, subproxy);
if (g_hash_table_size(priv->subproxies) == 0) {
g_hash_table_unref(priv->subproxies);
priv->subproxies = NULL;
}
g_mutex_unlock(&priv->mutex);
/* Unlock */
}
static
void
gbinder_proxy_object_drop_subproxies(
GBinderProxyObject* self)
{
GBinderProxyObjectPriv* priv = self->priv;
GSList* list = NULL;
/* Lock */
g_mutex_lock(&priv->mutex);
if (priv->subproxies) {
GHashTableIter it;
gpointer value;
g_hash_table_iter_init(&it, priv->subproxies);
while (g_hash_table_iter_next(&it, NULL, &value)) {
list = g_slist_append(list, gbinder_local_object_ref(value));
g_object_weak_unref(G_OBJECT(value),
gbinder_proxy_object_subproxy_gone, self);
}
g_hash_table_destroy(priv->subproxies);
priv->subproxies = NULL;
}
g_mutex_unlock(&priv->mutex);
/* Unlock */
/* Drop (and possibly destroy) the objects outside of the lock */
g_slist_free_full(list, (GDestroyNotify) gbinder_local_object_drop);
}
static
void
gbinder_proxy_remote_death_proc(
GBinderRemoteObject* obj,
void* proxy)
{
GBinderProxyObject* self = THIS(proxy);
GBinderProxyObjectPriv* priv = self->priv;
GDEBUG("Remote object %u died on %s", obj->handle, obj->ipc->dev);
gbinder_remote_object_remove_handler(obj, priv->remote_death_id);
priv->remote_death_id = 0;
/* Drop the implicit reference */
gbinder_local_object_unref(&self->parent);
}
/*==========================================================================*
* Converter
*==========================================================================*/
typedef struct gbinder_proxy_object_converter {
GBinderObjectConverter pub;
GBinderProxyObject* proxy;
GBinderIpc* remote;
GBinderIpc* local;
} GBinderProxyObjectConverter;
@@ -182,8 +113,6 @@ gbinder_proxy_object_converter_handle_to_local(
guint32 handle)
{
GBinderProxyObjectConverter* c = gbinder_proxy_object_converter_cast(pub);
GBinderProxyObject* proxy = c->proxy;
GBinderProxyObjectPriv* priv = proxy->priv;
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(c->remote);
GBinderRemoteObject* remote = gbinder_object_registry_get_remote(reg,
handle, REMOTE_REGISTRY_CAN_CREATE /* but don't acquire */);
@@ -192,32 +121,7 @@ gbinder_proxy_object_converter_handle_to_local(
if (!local && !remote->dead) {
/* GBinderProxyObject will reference GBinderRemoteObject */
GBinderProxyObject* subp = gbinder_proxy_object_new(c->local, remote);
/*
* Auto-created proxies may get spontaneously destroyed and
* not necessarily on the UI thread.
*/
subp->priv->remote_death_id = gbinder_remote_object_add_death_handler
(remote, gbinder_proxy_remote_death_proc, subp);
/*
* Remote keeps an implicit reference to this auto-created
* proxy. The reference gets released when the remote object
* dies, i.e. by gbinder_proxy_remote_death_proc().
*/
gbinder_local_object_ref(local = GBINDER_LOCAL_OBJECT(subp));
/* Lock */
g_mutex_lock(&priv->mutex);
if (!priv->subproxies) {
priv->subproxies = g_hash_table_new(g_direct_hash, g_direct_equal);
}
g_hash_table_insert(priv->subproxies, subp, subp);
g_object_weak_ref(G_OBJECT(subp),
gbinder_proxy_object_subproxy_gone, proxy);
g_mutex_unlock(&priv->mutex);
/* Unlock */
local = &gbinder_proxy_object_new(c->local, remote)->parent;
}
/* Release the reference returned by gbinder_object_registry_get_remote */
@@ -241,7 +145,6 @@ gbinder_proxy_object_converter_init(
GBinderIpc* dest = proxy->parent.ipc;
memset(convert, 0, sizeof(*convert));
convert->proxy = proxy;
convert->remote = remote;
convert->local = local;
pub->f = &gbinder_converter_fn;
@@ -346,7 +249,7 @@ gbinder_proxy_object_handle_transaction(
GBinderProxyObjectPriv* priv = self->priv;
GBinderRemoteObject* remote = self->remote;
if (!priv->dropped && !gbinder_remote_object_is_dead(remote)) {
if (!priv->dropped && !remote->dead) {
GBinderLocalRequest* fwd;
GBinderProxyTx* tx = g_slice_new0(GBinderProxyTx);
GBinderProxyObjectConverter convert;
@@ -374,6 +277,7 @@ gbinder_proxy_object_handle_transaction(
gbinder_local_request_unref(fwd);
*status = GBINDER_STATUS_OK;
} else {
GVERBOSE_("dropped: %d dead:%d", priv->dropped, remote->dead);
*status = (-EBADMSG);
}
return NULL;
@@ -397,33 +301,16 @@ gbinder_proxy_object_acquire(
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
GBinderRemoteObject* remote = self->remote;
if (priv->remote_death_id && !object->strong_refs) {
GBinderRemoteObject* remote = self->remote;
/* First strong ref, acquire the attached remote object */
if (!remote->dead && !priv->dropped && !priv->acquired) {
/* Not acquired yet */
priv->acquired = TRUE;
gbinder_driver_acquire(remote->ipc->driver, remote->handle);
}
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->acquire(object);
}
static
void
gbinder_proxy_object_release(
GBinderLocalObject* object)
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
if (priv->remote_death_id && object->strong_refs == 1) {
GBinderRemoteObject* remote = self->remote;
/* Last strong ref, release the attached remote object */
gbinder_driver_release(remote->ipc->driver, remote->handle);
}
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->release(object);
}
static
void
gbinder_proxy_object_drop(
@@ -433,7 +320,6 @@ gbinder_proxy_object_drop(
GBinderProxyObjectPriv* priv = self->priv;
priv->dropped = TRUE;
gbinder_proxy_object_drop_subproxies(self);
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->drop(object);
}
@@ -459,6 +345,8 @@ gbinder_proxy_object_new(
if (object) {
GBinderProxyObject* self = THIS(object);
GDEBUG("Proxy %p %s => %u %s created", self, gbinder_ipc_name(src),
remote->handle, gbinder_ipc_name(remote->ipc));
self->remote = gbinder_remote_object_ref(remote);
return self;
}
@@ -477,11 +365,25 @@ gbinder_proxy_object_finalize(
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
GBinderLocalObject* local = &self->parent;
GBinderRemoteObject* remote = self->remote;
gbinder_proxy_object_drop_subproxies(self);
gbinder_remote_object_remove_handler(self->remote, priv->remote_death_id);
gbinder_remote_object_unref(self->remote);
g_mutex_clear(&priv->mutex);
/*
* gbinder_local_object_finalize() will also try to do the same thing
* i.e. invalidate self but proxy objects need to do it before releasing
* the handle, to leave no room for race conditions. That's not very good
* because it grabs ipc-wide mutex but shouldn'd have much of an impact
* on the performance because finalizing a proxy is not supposed to be a
* frequent operation.
*/
gbinder_ipc_invalidate_local_object(local->ipc, local);
if (priv->acquired) {
gbinder_driver_release(remote->ipc->driver, remote->handle);
}
GDEBUG("Proxy %p %s => %u %s gone", self,
gbinder_ipc_name(self->parent.ipc), remote->handle,
gbinder_ipc_name(remote->ipc));
gbinder_remote_object_unref(remote);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
@@ -494,7 +396,6 @@ gbinder_proxy_object_init(
THIS_TYPE, GBinderProxyObjectPriv);
self->priv = priv;
g_mutex_init(&priv->mutex);
}
static
@@ -509,7 +410,6 @@ gbinder_proxy_object_class_init(
klass->can_handle_transaction = gbinder_proxy_object_can_handle_transaction;
klass->handle_transaction = gbinder_proxy_object_handle_transaction;
klass->acquire = gbinder_proxy_object_acquire;
klass->release = gbinder_proxy_object_release;
klass->drop = gbinder_proxy_object_drop;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2023 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -90,7 +90,7 @@ gbinder_reader_at_end(
{
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
return p->ptr >= p->end;
return !p || p->ptr >= p->end;
}
static
@@ -123,13 +123,74 @@ gboolean
gbinder_reader_read_bool(
GBinderReader* reader,
gboolean* value)
{
/*
* Android's libhwbinder writes bool as a single byte and pads it
* with zeros, but libbinder writes bool as int32 in native byte
* order. The latter becomes either [0x01, 0x00, 0x00, 0x00] or
* [0x00, 0x00, 0x00, 0x01] depending on the byte order. Reading
* uint32 and comparing it with zero works in either case.
*/
if (value) {
guint32 padded;
if (gbinder_reader_read_uint32(reader, &padded)) {
*value = (padded != 0);
return TRUE;
} else {
return FALSE;
}
} else {
return gbinder_reader_read_uint32(reader, NULL);
}
}
gboolean
gbinder_reader_read_int8(
GBinderReader* reader,
gint8* value) /* Since 1.1.15 */
{
return gbinder_reader_read_uint8(reader, (guint8*)value);
}
gboolean
gbinder_reader_read_uint8(
GBinderReader* reader,
guint8* value) /* Since 1.1.15 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
/* Boolean values are supposed to be padded to 4-byte boundary */
/* Primitive values are supposed to be padded to 4-byte boundary */
if (gbinder_reader_can_read(p, 4)) {
if (value) {
*value = (p->ptr[0] != 0);
*value = p->ptr[0];
}
p->ptr += 4;
return TRUE;
} else {
return FALSE;
}
}
gboolean
gbinder_reader_read_int16(
GBinderReader* reader,
gint16* value) /* Since 1.1.15 */
{
return gbinder_reader_read_uint16(reader, (guint16*)value);
}
gboolean
gbinder_reader_read_uint16(
GBinderReader* reader,
guint16* value) /* Since 1.1.15 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
/* Primitive values are supposed to be padded to 4-byte boundary */
if (gbinder_reader_can_read(p, 4)) {
if (value) {
*value = *(guint16*)p->ptr;
}
p->ptr += 4;
return TRUE;
@@ -296,7 +357,8 @@ gbinder_reader_read_nullable_object(
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);
gbinder_reader_bytes_remaining(reader), data->reg, out,
gbinder_buffer_protocol(data->buffer));
if (eaten) {
p->ptr += eaten;
@@ -364,6 +426,40 @@ gbinder_reader_skip_buffer(
return gbinder_reader_read_buffer_object(reader, NULL);
}
/*
* This is supposed to be used to read aidl parcelables, and is not
* guaranteed to work on any other kind of parcelable.
*/
const void*
gbinder_reader_read_parcelable(
GBinderReader* reader,
gsize* size) /* Since 1.1.19 */
{
guint32 non_null, payload_size = 0;
if (gbinder_reader_read_uint32(reader, &non_null) && non_null &&
gbinder_reader_read_uint32(reader, &payload_size) &&
payload_size >= sizeof(payload_size)) {
GBinderReaderPriv* p = gbinder_reader_cast(reader);
payload_size -= sizeof(payload_size);
if (p->ptr + payload_size <= p->end) {
const void* out = p->ptr;
/* Success */
p->ptr += payload_size;
if (size) {
*size = payload_size;
}
return out;
}
}
if (size) {
*size = 0;
}
return NULL;
}
/* Helper for gbinder_reader_read_hidl_struct() macro */
const void*
gbinder_reader_read_hidl_struct1(
@@ -680,13 +776,38 @@ gbinder_reader_read_byte_array(
return data;
}
const void*
gbinder_reader_get_data(
const GBinderReader* reader,
gsize* size) /* Since 1.1.14 */
{
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
if (p) {
const GBinderReaderData* data = p->data;
if (data && data->buffer) {
if (size) {
*size = data->buffer->size;
}
return data->buffer->data;
}
}
/* No data */
if (size) {
*size = 0;
}
return NULL;
}
gsize
gbinder_reader_bytes_read(
const GBinderReader* reader)
{
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
return p->ptr - p->start;
return p ? (p->ptr - p->start) : 0;
}
gsize
@@ -695,7 +816,7 @@ gbinder_reader_bytes_remaining(
{
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
return p->end - p->ptr;
return p ? (p->end - p->ptr) : 0;
}
void
@@ -703,8 +824,11 @@ gbinder_reader_copy(
GBinderReader* dest,
const GBinderReader* src)
{
/* It's actually quite simple :) */
memcpy(dest, src, sizeof(*dest));
if (src) {
memcpy(dest, src, sizeof(*dest));
} else {
memset(dest, 0, sizeof(*dest));
}
}
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -149,6 +149,7 @@ gbinder_remote_object_commit_suicide(
GBinderRemoteObjectPriv* priv = self->priv;
self->dead = TRUE;
gbinder_driver_clear_death_notification(driver, self);
if (priv->acquired) {
priv->acquired = FALSE;
/* Release the dead node */
@@ -294,6 +295,7 @@ gbinder_remote_object_finalize(
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
gbinder_ipc_invalidate_remote_handle(ipc, self->handle);
if (!self->dead) {
gbinder_driver_clear_death_notification(driver, self);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -131,8 +131,9 @@ gbinder_remote_reply_convert_to_local(
GBinderObjectRegistry* reg = d->reg;
if (reg) {
return gbinder_local_reply_set_contents
(gbinder_local_reply_new(reg->io), d->buffer, convert);
return gbinder_local_reply_set_contents(gbinder_local_reply_new
(reg->io, gbinder_buffer_protocol(d->buffer)),
d->buffer, convert);
}
}
return NULL;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -40,6 +40,9 @@
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
#define UNSET_WORK_SOURCE (-1)
#define BINDER_VND_HEADER GBINDER_FOURCC('V', 'N', 'D', 'R')
#define BINDER_SYS_HEADER GBINDER_FOURCC('S', 'Y', 'S', 'T')
/*==========================================================================*
* GBinderIpcProtocol callbacks (see Parcel::writeInterfaceToken in Android)
* Note that there are two slightly different kinds of Parcels:
@@ -173,6 +176,61 @@ static const GBinderRpcProtocol gbinder_rpc_protocol_aidl2 = {
.read_rpc_header = gbinder_rpc_protocol_aidl2_read_rpc_header
};
/*==========================================================================*
* AIDL protocol appeared in Android 11 (API level 30)
*==========================================================================*/
static
void
gbinder_rpc_protocol_aidl3_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
gbinder_writer_append_int32(writer, BINDER_RPC_FLAGS);
gbinder_writer_append_int32(writer, UNSET_WORK_SOURCE);
gbinder_writer_append_int32(writer, BINDER_SYS_HEADER);
gbinder_writer_append_string16(writer, iface);
}
static
const char*
gbinder_rpc_protocol_aidl3_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
{
if (txcode > GBINDER_TRANSACTION(0,0,0)) {
*iface = NULL;
} else if (gbinder_reader_read_int32(reader, NULL) /* flags */ &&
gbinder_reader_read_int32(reader, NULL) /* work source */ &&
gbinder_reader_read_int32(reader, NULL) /* sys header */) {
*iface = gbinder_reader_read_string16(reader);
} else {
*iface = NULL;
}
return *iface;
}
static
void
gbinder_rpc_protocol_aidl3_finish_flatten_binder(
void* out,
GBinderLocalObject* obj)
{
*(guint32*)out = GBINDER_STABILITY_SYSTEM;
}
static const GBinderRpcProtocol gbinder_rpc_protocol_aidl3 = {
.name = "aidl3",
.ping_tx = GBINDER_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_aidl_write_ping, /* no payload */
.write_rpc_header = gbinder_rpc_protocol_aidl3_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl3_read_rpc_header,
.flat_binder_object_extra = 4,
.finish_flatten_binder = gbinder_rpc_protocol_aidl3_finish_flatten_binder
};
/*==========================================================================*
* The original /dev/hwbinder protocol.
*==========================================================================*/
@@ -225,6 +283,7 @@ static const GBinderRpcProtocol gbinder_rpc_protocol_hidl = {
static const GBinderRpcProtocol* gbinder_rpc_protocol_list[] = {
&gbinder_rpc_protocol_aidl,
&gbinder_rpc_protocol_aidl2,
&gbinder_rpc_protocol_aidl3,
&gbinder_rpc_protocol_hidl
};
@@ -331,6 +390,13 @@ gbinder_rpc_protocol_for_device(
return gbinder_rpc_protocol_default;
}
const GBinderRpcProtocol*
gbinder_rpc_protocol_by_name(
const char* protocol_name)
{
return gbinder_rpc_protocol_find(protocol_name);
}
/*
* Local Variables:
* mode: C

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -47,8 +47,24 @@ struct gbinder_rpc_protocol {
void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
const char* (*read_rpc_header)(GBinderReader* reader, guint32 txcode,
char** iface);
/*
* For the sake of simplicity, let's assume that the trailer has a
* fixed size and that size is the same on both 32 and 64 bit platforms.
* Also note that finish_unflatten_binder() is only invoked for the
* remote objects that are not NULL, otherwise flat_binder_object_extra
* bytes are just skipped.
*/
gsize flat_binder_object_extra;
void (*finish_flatten_binder)(void* out, GBinderLocalObject* obj);
void (*finish_unflatten_binder)(const void* in, GBinderRemoteObject* obj);
};
const GBinderRpcProtocol*
gbinder_rpc_protocol_by_name(
const char* protocol_name)
GBINDER_INTERNAL;
/* Returns one of the above based on the device name */
const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device(

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -82,11 +82,13 @@ typedef struct gbinder_servicemanager_type {
static const GBinderServiceManagerType gbinder_servicemanager_types[] = {
{ "aidl", gbinder_servicemanager_aidl_get_type },
{ "aidl2", gbinder_servicemanager_aidl2_get_type },
{ "aidl3", gbinder_servicemanager_aidl3_get_type },
{ "aidl4", gbinder_servicemanager_aidl4_get_type },
{ "hidl", gbinder_servicemanager_hidl_get_type }
};
#define SERVICEMANAGER_TYPE_AIDL (gbinder_servicemanager_types + 0)
#define SERVICEMANAGER_TYPE_HIDL (gbinder_servicemanager_types + 2)
#define SERVICEMANAGER_TYPE_HIDL (gbinder_servicemanager_types + 4)
#define SERVICEMANAGER_TYPE_DEFAULT SERVICEMANAGER_TYPE_AIDL
static GHashTable* gbinder_servicemanager_map = NULL;
@@ -518,7 +520,8 @@ gbinder_servicemanager_exit(
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
GType type,
const char* dev)
const char* dev,
const char* rpc_protocol)
{
GBinderServiceManager* self = NULL;
GBinderServiceManagerClass* klass = gbinder_servicemanager_class_ref(type);
@@ -527,7 +530,7 @@ gbinder_servicemanager_new_with_type(
GBinderIpc* ipc;
if (!dev) dev = klass->default_device;
ipc = gbinder_ipc_new(dev);
ipc = gbinder_ipc_new(dev, rpc_protocol);
if (ipc) {
/* Create a (possibly) dead service manager object */
GBinderRemoteObject* object = gbinder_ipc_get_service_manager(ipc);
@@ -619,25 +622,36 @@ GBinderServiceManager*
gbinder_servicemanager_new(
const char* dev)
{
if (dev) {
const GBinderServiceManagerType* type = NULL;
return gbinder_servicemanager_new2(dev, NULL, NULL);
}
GBinderServiceManager*
gbinder_servicemanager_new2(
const char* dev,
const char* sm_protocol,
const char* rpc_protocol) /* Since 1.1.20 */
{
if (!dev) {
return NULL;
} else if (!sm_protocol) {
const GBinderServiceManagerType* type;
/* One-time initialization */
if (!gbinder_servicemanager_map) {
const GBinderServiceManagerType* t;
/* One-time initialization */
gbinder_servicemanager_map = gbinder_servicemanager_load_config();
/* "Default" is a special value stored in a special variable */
t = g_hash_table_lookup(gbinder_servicemanager_map, CONF_DEFAULT);
if (t) {
type = g_hash_table_lookup(gbinder_servicemanager_map,
CONF_DEFAULT);
if (type) {
g_hash_table_remove(gbinder_servicemanager_map, CONF_DEFAULT);
gbinder_servicemanager_default = t;
gbinder_servicemanager_default = type;
} else {
gbinder_servicemanager_default = SERVICEMANAGER_TYPE_DEFAULT;
}
}
/* If no protocol is specified, pick one up based on the device name */
type = g_hash_table_lookup(gbinder_servicemanager_map, dev);
if (type) {
GDEBUG("Using %s service manager for %s", type->name, dev);
@@ -645,9 +659,21 @@ gbinder_servicemanager_new(
type = gbinder_servicemanager_default;
GDEBUG("Using default service manager %s for %s", type->name, dev);
}
return gbinder_servicemanager_new_with_type(type->get_type(), dev);
return gbinder_servicemanager_new_with_type(type->get_type(), dev,
rpc_protocol);
} else {
/* If protocol name is specified, it must be a valid one */
const GBinderServiceManagerType* type =
gbinder_servicemanager_value_map(sm_protocol);
if (type) {
return gbinder_servicemanager_new_with_type(type->get_type(), dev,
rpc_protocol);
} else {
GWARN("Unknown servicemanager protocol %s", sm_protocol);
return NULL;
}
}
return NULL;
}
GBinderLocalObject*
@@ -698,6 +724,13 @@ gbinder_servicemanager_unref(
}
}
const char*
gbinder_servicemanager_device(
GBinderServiceManager* self) /* Since 1.1.14 */
{
return G_LIKELY(self) ? self->dev : NULL;
}
gboolean
gbinder_servicemanager_is_present(
GBinderServiceManager* self) /* Since 1.0.25 */
@@ -1008,7 +1041,7 @@ gbinder_defaultservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_servicemanager_aidl_get_type(), dev);
(gbinder_servicemanager_aidl_get_type(), dev, NULL);
}
GBinderServiceManager*
@@ -1016,7 +1049,7 @@ gbinder_hwservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_servicemanager_hidl_get_type(), dev);
(gbinder_servicemanager_hidl_get_type(), dev, NULL);
}
/*==========================================================================*

View File

@@ -61,16 +61,6 @@ G_DEFINE_TYPE(GBinderServiceManagerAidl,
#define GBINDER_SERVICEMANAGER_AIDL(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
GBinderServiceManagerAidl)
#define GBINDER_SERVICEMANAGER_AIDL_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
GBinderServiceManagerAidlClass)
enum gbinder_servicemanager_aidl_calls {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
#define SERVICEMANAGER_AIDL_IFACE "android.os.IServiceManager"

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2020-2022 Jolla Ltd.
* Copyright (C) 2020-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -51,10 +51,20 @@ typedef struct gbinder_servicemanager_aidl_class {
#define GBINDER_TYPE_SERVICEMANAGER_AIDL \
gbinder_servicemanager_aidl_get_type()
#define GBINDER_SERVICEMANAGER_AIDL_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
#define GBINDER_SERVICEMANAGER_AIDL_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
GBinderServiceManagerAidlClass)
enum gbinder_servicemanager_aidl_calls {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
#define DUMP_FLAG_PRIORITY_DEFAULT (0x08)
#define DUMP_FLAG_PRIORITY_ALL (0x0f)
#endif /* GBINDER_SERVICEMANAGER_AIDL_H */
/*
@@ -64,3 +74,4 @@ typedef struct gbinder_servicemanager_aidl_class {
* indent-tabs-mode: nil
* End:
*/

View File

@@ -45,8 +45,6 @@ G_DEFINE_TYPE(GBinderServiceManagerAidl2,
GBINDER_TYPE_SERVICEMANAGER_AIDL)
#define PARENT_CLASS gbinder_servicemanager_aidl2_parent_class
#define DUMP_FLAG_PRIORITY_DEFAULT (0x08)
#define DUMP_FLAG_PRIORITY_ALL (0x0f)
static
GBinderLocalRequest*

View File

@@ -0,0 +1,162 @@
/*
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021 Gary Wang <gary.wang@canonical.com>
* Copyright (C) 2021 Madhushan Nishantha <jlmadushan@gmail.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_servicemanager_aidl_p.h"
#include "gbinder_client_p.h"
#include "gbinder_reader_p.h"
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
/* Variant of AIDL servicemanager appeared in Android 11 (API level 30) */
typedef GBinderServiceManagerAidl GBinderServiceManagerAidl3;
typedef GBinderServiceManagerAidlClass GBinderServiceManagerAidl3Class;
G_DEFINE_TYPE(GBinderServiceManagerAidl3,
gbinder_servicemanager_aidl3,
GBINDER_TYPE_SERVICEMANAGER_AIDL)
#define PARENT_CLASS gbinder_servicemanager_aidl3_parent_class
GBinderRemoteObject*
gbinder_servicemanager_aidl3_get_service(
GBinderServiceManager* self,
const char* name,
int* status,
const GBinderIpcSyncApi* api)
{
GBinderClient* client = self->client;
GBinderLocalRequest* req = gbinder_client_new_request(client);
GBinderRemoteObject* obj;
GBinderRemoteReply* reply;
GBinderReader reader;
gbinder_local_request_append_string16(req, name);
reply = gbinder_client_transact_sync_reply2(client,
CHECK_SERVICE_TRANSACTION, req, status, api);
gbinder_remote_reply_init_reader(reply, &reader);
gbinder_reader_read_int32(&reader, NULL /* status? */);
obj = gbinder_reader_read_object(&reader);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return obj;
}
char**
gbinder_servicemanager_aidl3_list(
GBinderServiceManager* manager,
const GBinderIpcSyncApi* api)
{
GPtrArray* list = g_ptr_array_new();
GBinderClient* client = manager->client;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(client);
/*
* Starting from Android 11, no `index` field is required but
* only with `dump priority` field to request to list services.
* As a result, a vector of strings which stands for service
* list is given in the binder response.
*/
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_ALL);
reply = gbinder_client_transact_sync_reply2(client,
LIST_SERVICES_TRANSACTION, req, NULL, api);
if (reply) {
GBinderReader reader;
gint32 count;
gbinder_remote_reply_init_reader(reply, &reader);
gbinder_reader_read_int32(&reader, NULL /* status */);
if (gbinder_reader_read_int32(&reader, &count)) {
int i;
/* Iterate each service name */
for (i = 0; i < count; i++) {
g_ptr_array_add(list, gbinder_reader_read_string16(&reader));
}
}
gbinder_remote_reply_unref(reply);
}
gbinder_local_request_unref(req);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
static
GBinderLocalRequest*
gbinder_servicemanager_aidl3_add_service_req(
GBinderClient* client,
const char* name,
GBinderLocalObject* obj)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT);
return req;
}
static
void
gbinder_servicemanager_aidl3_init(
GBinderServiceManagerAidl3* self)
{
}
static
void
gbinder_servicemanager_aidl3_class_init(
GBinderServiceManagerAidl3Class* klass)
{
GBinderServiceManagerClass* manager = GBINDER_SERVICEMANAGER_CLASS(klass);
klass->add_service_req = gbinder_servicemanager_aidl3_add_service_req;
manager->list = gbinder_servicemanager_aidl3_list;
manager->get_service = gbinder_servicemanager_aidl3_get_service;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2020-2022 Jolla Ltd.
* Copyright (C) 2020-2022 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021 Gary Wang <gary.wang@canonical.com>
* Copyright (C) 2021 Madhushan Nishantha <jlmadushan@gmail.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_servicemanager_aidl_p.h"
#include "gbinder_client_p.h"
#include "gbinder_reader_p.h"
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
/* Variant of AIDL servicemanager appeared in Android 12 (API level 31) */
typedef GBinderServiceManagerAidl GBinderServiceManagerAidl4;
typedef GBinderServiceManagerAidlClass GBinderServiceManagerAidl4Class;
G_DEFINE_TYPE(GBinderServiceManagerAidl4,
gbinder_servicemanager_aidl4,
GBINDER_TYPE_SERVICEMANAGER_AIDL)
#define PARENT_CLASS gbinder_servicemanager_aidl4_parent_class
#define BINDER_WIRE_FORMAT_VERSION (1)
static
GBinderLocalRequest*
gbinder_servicemanager_aidl4_add_service_req(
GBinderClient* client,
const char* name,
GBinderLocalObject* obj)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
/*
* When reading nullable strong binder, from Android 12, the format of
* the `stability` field passed on the wire was changed and evolved to
* `struct Category`, which consists of the following members with 4 bytes
* long.
*
* struct Category {
* uint8_t version;
* uint8_t reserved[2];
* Level level; <- bitmask of Stability::Level
* }
*
* Hmmm, is that ^ really true?
*/
gbinder_local_request_append_int32(req,
GBINDER_FOURCC(GBINDER_STABILITY_SYSTEM, 0, 0,
BINDER_WIRE_FORMAT_VERSION));
gbinder_local_request_append_int32(req, 0);
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT);
return req;
}
static
void
gbinder_servicemanager_aidl4_init(
GBinderServiceManagerAidl* self)
{
}
static
void
gbinder_servicemanager_aidl4_class_init(
GBinderServiceManagerAidl4Class* cls)
{
GBinderServiceManagerClass* manager = GBINDER_SERVICEMANAGER_CLASS(cls);
cls->add_service_req = gbinder_servicemanager_aidl4_add_service_req;
manager->list = gbinder_servicemanager_aidl3_list;
manager->get_service = gbinder_servicemanager_aidl3_get_service;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021 Gary Wang <gary.wang@canonical.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_SERVICEMANAGER_AIDL_PRIVATE_H
#define GBINDER_SERVICEMANAGER_AIDL_PRIVATE_H
#include "gbinder_servicemanager_aidl.h"
char**
gbinder_servicemanager_aidl3_list(
GBinderServiceManager* manager,
const GBinderIpcSyncApi* api)
GBINDER_INTERNAL;
GBinderRemoteObject*
gbinder_servicemanager_aidl3_get_service(
GBinderServiceManager* manager,
const char* name,
int* status,
const GBinderIpcSyncApi* api)
GBINDER_INTERNAL;
#endif /* GBINDER_SERVICEMANAGER_AIDL_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -90,7 +90,8 @@ GType gbinder_servicemanager_get_type(void) GBINDER_INTERNAL;
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
GType type,
const char* dev)
const char* dev,
const char* rpc_protocol)
GBINDER_INTERNAL;
void
@@ -110,6 +111,8 @@ gbinder_servicemanager_exit(
GType gbinder_servicemanager_aidl_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_aidl2_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_aidl3_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_aidl4_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_hidl_get_type(void) GBINDER_INTERNAL;
#endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -50,10 +50,12 @@ struct gbinder_servicepoll {
GBinderEventLoopTimeout* timer;
};
#define PARENT_CLASS gbinder_servicepoll_parent_class
#define THIS_TYPE gbinder_servicepoll_get_type()
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, THIS_TYPE, GBinderServicePoll)
GType THIS_TYPE GBINDER_INTERNAL;
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,
@@ -76,7 +78,7 @@ gbinder_servicepoll_list(
char** services,
void* user_data)
{
GBinderServicePoll* self = GBINDER_SERVICEPOLL(user_data);
GBinderServicePoll* self = THIS(user_data);
gbinder_servicepoll_ref(self);
self->list_id = 0;
@@ -122,7 +124,7 @@ gboolean
gbinder_servicepoll_timer(
gpointer user_data)
{
GBinderServicePoll* self = GBINDER_SERVICEPOLL(user_data);
GBinderServicePoll* self = THIS(user_data);
if (!self->list_id) {
self->list_id = gbinder_servicemanager_list(self->manager,
@@ -136,7 +138,7 @@ GBinderServicePoll*
gbinder_servicepoll_create(
GBinderServiceManager* manager)
{
GBinderServicePoll* self = g_object_new(GBINDER_TYPE_SERVICEPOLL, NULL);
GBinderServicePoll* self = g_object_new(THIS_TYPE, NULL);
self->manager = gbinder_servicemanager_ref(manager);
self->list_id = gbinder_servicemanager_list(manager,
@@ -171,7 +173,7 @@ gbinder_servicepoll_ref(
GBinderServicePoll* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_SERVICEPOLL(self));
g_object_ref(THIS(self));
return self;
} else {
return NULL;
@@ -183,7 +185,7 @@ gbinder_servicepoll_unref(
GBinderServicePoll* self)
{
if (G_LIKELY(self)) {
g_object_unref(GBINDER_SERVICEPOLL(self));
g_object_unref(THIS(self));
}
}
@@ -240,12 +242,13 @@ void
gbinder_servicepoll_finalize(
GObject* object)
{
GBinderServicePoll* self = GBINDER_SERVICEPOLL(object);
GBinderServicePoll* self = THIS(object);
gbinder_timeout_remove(self->timer);
gbinder_servicemanager_cancel(self->manager, self->list_id);
gbinder_servicemanager_unref(self->manager);
g_strfreev(self->list);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -77,6 +77,13 @@ typedef struct gbinder_ipc_sync_api GBinderIpcSyncApi;
/* As a special case, ServiceManager's handle is zero */
#define GBINDER_SERVICEMANAGER_HANDLE (0)
typedef enum gbinder_stability_level {
GBINDER_STABILITY_UNDECLARED = 0,
GBINDER_STABILITY_VENDOR = 0x03,
GBINDER_STABILITY_SYSTEM = 0x0c,
GBINDER_STABILITY_VINTF = 0x3f
} GBINDER_STABILITY_LEVEL;
#endif /* GBINDER_TYPES_PRIVATE_H */
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2023 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -32,6 +32,7 @@
#include "gbinder_writer_p.h"
#include "gbinder_buffer_p.h"
#include "gbinder_fmq_p.h"
#include "gbinder_local_object.h"
#include "gbinder_object_converter.h"
#include "gbinder_io.h"
@@ -51,6 +52,20 @@ typedef struct gbinder_writer_priv {
GBinderWriterData* data;
} GBinderWriterPriv;
const GBinderWriterType gbinder_writer_type_byte = { "int32", 4, NULL };
const GBinderWriterType gbinder_writer_type_int32 = { "byte", 1, NULL };
static const GBinderWriterField gbinder_writer_type_hidl_string_f[] = {
{
"hidl_string.data.str", 0, NULL,
gbinder_writer_field_hidl_string_write_buf, NULL
},
GBINDER_WRITER_FIELD_END()
};
const GBinderWriterType gbinder_writer_type_hidl_string = {
"hidl_string", sizeof(GBinderHidlString),
gbinder_writer_type_hidl_string_f
};
G_STATIC_ASSERT(sizeof(GBinderWriter) >= sizeof(GBinderWriterPriv));
GBINDER_INLINE_FUNC GBinderWriterPriv* gbinder_writer_cast(GBinderWriter* pub)
@@ -91,6 +106,7 @@ gbinder_writer_data_append_contents(
gbinder_buffer_contents_ref(contents));
if (objects && *objects) {
const GBinderIo* io = gbinder_buffer_io(buffer);
const GBinderRpcProtocol* proto = gbinder_buffer_protocol(buffer);
/* GBinderIo must be the same because it's defined by the kernel */
GASSERT(io == data->io);
@@ -113,21 +129,22 @@ gbinder_writer_data_append_contents(
gutil_int_array_append(data->offsets, dest->len);
/* Convert remote object into local if necessary */
if (convert && io->decode_binder_handle(obj, &handle) &&
if (convert && io->decode_binder_handle(obj, &handle, proto) &&
(local = gbinder_object_converter_handle_to_local
(convert, handle))) {
const guint pos = dest->len;
g_byte_array_set_size(dest, pos +
GBINDER_MAX_BINDER_OBJECT_SIZE);
objsize = io->encode_local_object(dest->data + pos, local);
objsize = io->encode_local_object(dest->data + pos,
local, proto);
g_byte_array_set_size(dest, pos + objsize);
/* Keep the reference */
data->cleanup = gbinder_cleanup_add(data->cleanup,
(GDestroyNotify) gbinder_local_object_unref, local);
} else {
objsize = io->object_size(obj);
objsize = io->object_size(obj, proto);
g_byte_array_append(dest, obj, objsize);
}
@@ -155,30 +172,6 @@ gbinder_writer_data_record_offset(
gutil_int_array_append(data->offsets, offset);
}
static
void
gbinder_writer_data_write_buffer_object(
GBinderWriterData* data,
const void* ptr,
gsize size,
const GBinderParent* parent)
{
GByteArray* buf = data->bytes;
const guint offset = buf->len;
guint n;
/* Preallocate enough space */
g_byte_array_set_size(buf, offset + GBINDER_MAX_BUFFER_OBJECT_SIZE);
/* Write the object */
n = data->io->encode_buffer_object(buf->data + offset, ptr, size, parent);
/* Fix the data size */
g_byte_array_set_size(buf, offset + n);
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
/* The driver seems to require each buffer to be 8-byte aligned */
data->buffers_size += G_ALIGN8(size);
}
void
gbinder_writer_init(
GBinderWriter* self,
@@ -188,12 +181,52 @@ gbinder_writer_init(
gbinder_writer_cast(self)->data = data;
}
const void*
gbinder_writer_get_data(
GBinderWriter* self,
gsize* size) /* Since 1.1.14 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
GByteArray* buf = data->bytes;
if (size) {
*size = buf->len;
}
return buf->data;
} else {
if (size) {
*size = 0;
}
return NULL;
}
}
gsize
gbinder_writer_bytes_written(
GBinderWriter* self) /* since 1.0.21 */
{
GBinderWriterData* data = gbinder_writer_data(self);
return data->bytes->len;
return G_LIKELY(data) ? data->bytes->len : 0;
}
static
void
gbinder_writer_data_append_padded(
GByteArray* buf,
const void* data,
guint size)
{
/* Primitive values are padded to 4-byte boundary */
const guint padded_size = 4;
guint8* ptr;
g_byte_array_set_size(buf, buf->len + padded_size);
ptr = buf->data + (buf->len - padded_size);
memcpy(ptr, data, size);
memset(ptr + size, 0, padded_size - size);
}
void
@@ -213,12 +246,33 @@ gbinder_writer_data_append_bool(
GBinderWriterData* data,
gboolean value)
{
guint8 padded[4];
const guint8 b = (value != FALSE);
/* Boolean values are padded to 4-byte boundary */
padded[0] = (value != FALSE);
padded[1] = padded[2] = padded[3] = 0;
g_byte_array_append(data->bytes, padded, sizeof(padded));
gbinder_writer_data_append_padded(data->bytes, &b, sizeof(b));
}
void
gbinder_writer_append_int8(
GBinderWriter* self,
guint8 value) /* Since 1.1.15 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_padded(data->bytes, &value, sizeof(value));
}
}
void
gbinder_writer_append_int16(
GBinderWriter* self,
guint16 value) /* Since 1.1.15 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_padded(data->bytes, &value, sizeof(value));
}
}
void
@@ -581,17 +635,6 @@ gbinder_writer_append_bytes(
}
}
static
guint
gbinder_writer_data_prepare(
GBinderWriterData* data)
{
if (!data->offsets) {
data->offsets = gutil_int_array_new();
}
return data->offsets->count;
}
static
void
gbinder_writer_data_close_fd(
@@ -604,7 +647,6 @@ gbinder_writer_data_close_fd(
}
}
static
void
gbinder_writer_data_append_fd(
GBinderWriterData* data,
@@ -646,6 +688,50 @@ gbinder_writer_append_fd(
}
}
void
gbinder_writer_data_append_fda_object(
GBinderWriterData* data,
const GBinderFds *fds,
const GBinderParent* parent)
{
GByteArray* buf = data->bytes;
const guint offset = buf->len;
guint written;
/* Preallocate enough space */
g_byte_array_set_size(buf, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
written = data->io->encode_fda_object(buf->data + offset, fds, parent);
/* 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_data_append_fds(
GBinderWriterData* data,
const GBinderFds *fds,
const GBinderParent* parent)
{
if (fds) {
/* Size, fds data buffer and fd_array_object */
const gsize fds_total = sizeof(GBinderFds) +
sizeof(int) * (fds->num_fds + fds->num_ints);
GBinderParent fds_parent;
gbinder_writer_data_append_int64(data, fds_total);
fds_parent.index = gbinder_writer_data_append_buffer_object(data,
fds, fds_total, parent);
fds_parent.offset = sizeof(GBinderFds);
gbinder_writer_data_append_fda_object(data, fds, &fds_parent);
} else {
/* If the pointer is null only write zero size */
gbinder_writer_data_append_int64(data, 0);
}
}
guint
gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* self,
@@ -675,6 +761,135 @@ gbinder_writer_append_buffer_object(
return 0;
}
static
void
gbinder_writer_append_fields(
GBinderWriter* writer,
const void* obj,
const GBinderWriterField* fields,
const GBinderParent* parent) /* Since 1.1.27 */
{
if (fields) {
const GBinderWriterField* field = fields;
const guint8* base_ptr = obj;
GBinderParent parent2;
parent2.index = parent->index;
for (field = fields; field->type || field->write_buf; field++) {
const void* field_ptr = base_ptr + field->offset;
parent2.offset = parent->offset + field->offset;
if (field->write_buf) {
field->write_buf(writer, field_ptr, field, &parent2);
} else {
gbinder_writer_append_buffer_object_with_parent(writer,
*(void**)field_ptr, field->type->size, &parent2);
}
}
}
}
/*
* Note that gbinder_writer_append_struct doesn't copy the data, it writes
* buffer objects pointing to whatever was passed in. The caller must make
* sure that those pointers outlive the transaction. That's most commonly
* done with by using gbinder_writer_malloc() and friends for allocating
* memory for the transaction.
*/
void
gbinder_writer_append_struct(
GBinderWriter* writer,
const void* ptr,
const GBinderWriterType* type,
const GBinderParent* parent) /* Since 1.1.27 */
{
if (type) {
GBinderParent child;
child.offset = 0;
child.index = gbinder_writer_append_buffer_object_with_parent(writer,
ptr, type->size, parent);
gbinder_writer_append_fields(writer, ptr, type->fields, &child);
} else {
/* No type - no fields */
gbinder_writer_append_buffer_object_with_parent(writer, ptr, 0, parent);
}
}
/*
* Appends top-level vec<type>. Allocates GBinderHidlVec for that, but
* unlike gbinder_writer_append_hidl_vec(), doesn't copy the contents
* of the vector.
*/
void
gbinder_writer_append_struct_vec(
GBinderWriter* writer,
const void* ptr,
guint count,
const GBinderWriterType* type) /* Since 1.1.29 */
{
GBinderHidlVec* vec = gbinder_writer_new0(writer, GBinderHidlVec);
GBinderWriterField vec_f[2];
GBinderWriterType vec_t;
memset(vec_f, 0, sizeof(vec_f));
vec_f->name = "hidl_vec.data.ptr";
vec_f->type = type;
vec_f->write_buf = gbinder_writer_field_hidl_vec_write_buf;
memset(&vec_t, 0, sizeof(vec_t));
vec_t.name = "hidl_vec";
vec_t.size = sizeof(GBinderHidlVec);
vec_t.fields = vec_f;
vec->owns_buffer = TRUE;
vec->data.ptr = ptr;
vec->count = count;
gbinder_writer_append_struct(writer, vec, &vec_t, NULL);
}
void
gbinder_writer_field_hidl_vec_write_buf(
GBinderWriter* writer,
const void* ptr,
const GBinderWriterField* field,
const GBinderParent* parent) /* Since 1.1.27 */
{
const GBinderHidlVec* vec = ptr;
const guint8* buf = vec->data.ptr;
const GBinderWriterType* elem_type = field->type;
if (elem_type) {
GBinderParent child;
guint i;
child.index = gbinder_writer_append_buffer_object_with_parent
(writer, buf, vec->count * elem_type->size, parent);
for (i = 0; i < vec->count; i++) {
child.offset = elem_type->size * i;
gbinder_writer_append_fields(writer, buf + child.offset,
elem_type->fields, &child);
}
} else {
/* Probably a programming error but write an empty buffer anyway */
gbinder_writer_append_buffer_object_with_parent(writer, buf, 0, parent);
}
}
void
gbinder_writer_field_hidl_string_write_buf(
GBinderWriter* writer,
const void* ptr,
const GBinderWriterField* field,
const GBinderParent* parent) /* Since 1.1.27 */
{
const GBinderHidlString* str = ptr;
gbinder_writer_append_buffer_object_with_parent(writer, str->data.str,
str->data.str ? (str->len + 1) : 0, parent);
}
guint
gbinder_writer_data_append_buffer_object(
GBinderWriterData* data,
@@ -682,12 +897,69 @@ gbinder_writer_data_append_buffer_object(
gsize size,
const GBinderParent* parent)
{
guint index = gbinder_writer_data_prepare(data);
const guint index = data->offsets ? data->offsets->count : 0;
GByteArray* buf = data->bytes;
const guint offset = buf->len;
guint n;
gbinder_writer_data_write_buffer_object(data, ptr, size, parent);
/* Preallocate enough space */
g_byte_array_set_size(buf, offset + GBINDER_MAX_BUFFER_OBJECT_SIZE);
/* Write the object */
n = data->io->encode_buffer_object(buf->data + offset, ptr, size, parent);
/* Fix the data size */
g_byte_array_set_size(buf, offset + n);
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
/* The driver seems to require each buffer to be 8-byte aligned */
data->buffers_size += G_ALIGN8(size);
return index;
}
/*
* This is supposed to be used to write aidl parcelables, and is not
* guaranteed to work on any other kind of parcelable.
*/
void
gbinder_writer_append_parcelable(
GBinderWriter* self,
const void* buf,
gsize len) /* Since 1.1.19 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_parcelable(data, buf, len);
}
}
/*
* This is compatible with aidl parcelables, and is not guaranteed to work
* with any other kind of parcelable.
*/
void
gbinder_writer_data_append_parcelable(
GBinderWriterData* data,
const void* ptr,
gsize size)
{
if (ptr) {
/* Non-null */
gbinder_writer_data_append_int32(data, 1);
/*
* Write the parcelable size, taking in account the size of this
* integer as well.
*/
gbinder_writer_data_append_int32(data, size + sizeof(gint32));
/* Append the parcelable data */
g_byte_array_append(data->bytes, ptr, size);
} else {
/* Null */
gbinder_writer_data_append_int32(data, 0);
}
}
void
gbinder_writer_append_hidl_string(
GBinderWriter* self,
@@ -700,6 +972,21 @@ gbinder_writer_append_hidl_string(
}
}
void
gbinder_writer_append_hidl_string_copy(
GBinderWriter* self,
const char* str) /* Since 1.1.13 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
static const char empty[] = "";
gbinder_writer_data_append_hidl_string(data, str ? (str[0] ?
gbinder_writer_strdup(self, str) : empty) : NULL);
}
}
void
gbinder_writer_data_append_hidl_vec(
GBinderWriterData* data,
@@ -712,10 +999,6 @@ gbinder_writer_data_append_hidl_vec(
const gsize total = count * elemsize;
void* buf = gutil_memdup(base, total);
/* Prepare parent descriptor for the string data */
vec_parent.index = gbinder_writer_data_prepare(data);
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
/* Fill in the vector descriptor */
if (buf) {
vec->data.ptr = buf;
@@ -726,8 +1009,10 @@ gbinder_writer_data_append_hidl_vec(
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, vec);
/* Every vector, even the one without data, requires two buffer objects */
gbinder_writer_data_write_buffer_object(data, vec, sizeof(*vec), NULL);
gbinder_writer_data_write_buffer_object(data, buf, total, &vec_parent);
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
vec_parent.index = gbinder_writer_data_append_buffer_object(data,
vec, sizeof(*vec), NULL);
gbinder_writer_data_append_buffer_object(data, buf, total, &vec_parent);
}
void
@@ -753,10 +1038,6 @@ gbinder_writer_data_append_hidl_string(
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 = GBINDER_HIDL_STRING_BUFFER_OFFSET;
/* Fill in the string descriptor and store it */
hidl_string->data.str = str;
hidl_string->len = len;
@@ -764,17 +1045,18 @@ gbinder_writer_data_append_hidl_string(
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, hidl_string);
/* Write the buffer object pointing to the string descriptor */
gbinder_writer_data_write_buffer_object(data, hidl_string,
sizeof(*hidl_string), NULL);
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
str_parent.index = gbinder_writer_data_append_buffer_object(data,
hidl_string, sizeof(*hidl_string), NULL);
if (str) {
/* Write the buffer pointing to the string data including the
* NULL terminator, referencing string descriptor as a parent. */
gbinder_writer_data_write_buffer_object(data, str, len+1, &str_parent);
gbinder_writer_data_append_buffer_object(data, str, len+1, &str_parent);
GVERBOSE_("\"%s\" %u %u %u", str, (guint)len, (guint)str_parent.index,
(guint)data->buffers_size);
} else {
gbinder_writer_data_write_buffer_object(data, NULL, 0, &str_parent);
gbinder_writer_data_append_buffer_object(data, NULL, 0, &str_parent);
}
}
@@ -807,10 +1089,6 @@ gbinder_writer_data_append_hidl_string_vec(
count = gutil_strv_length((char**)strv);
}
/* Prepare parent descriptor for the vector data */
vec_parent.index = gbinder_writer_data_prepare(data);
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
/* Fill in the vector descriptor */
if (count > 0) {
strings = g_new0(GBinderHidlString, count);
@@ -833,7 +1111,10 @@ gbinder_writer_data_append_hidl_string_vec(
}
/* Write the vector object */
gbinder_writer_data_write_buffer_object(data, vec, sizeof(*vec), NULL);
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
vec_parent.index = gbinder_writer_data_append_buffer_object(data,
vec, sizeof(*vec), NULL);
if (strings) {
GBinderParent str_parent;
@@ -842,7 +1123,7 @@ gbinder_writer_data_append_hidl_string_vec(
str_parent.offset = GBINDER_HIDL_STRING_BUFFER_OFFSET;
/* Write the vector data (it's parent for the string data) */
gbinder_writer_data_write_buffer_object(data, strings,
gbinder_writer_data_append_buffer_object(data, strings,
sizeof(*strings) * count, &vec_parent);
/* Write the string data */
@@ -850,7 +1131,7 @@ gbinder_writer_data_append_hidl_string_vec(
GBinderHidlString* hidl_str = strings + i;
if (hidl_str->data.str) {
gbinder_writer_data_write_buffer_object(data,
gbinder_writer_data_append_buffer_object(data,
hidl_str->data.str, hidl_str->len + 1, &str_parent);
GVERBOSE_("%d. \"%s\" %u %u %u", i + 1, hidl_str->data.str,
(guint)hidl_str->len, (guint)str_parent.index,
@@ -858,13 +1139,13 @@ gbinder_writer_data_append_hidl_string_vec(
} else {
GVERBOSE_("%d. NULL %u %u %u", i + 1, (guint)hidl_str->len,
(guint)str_parent.index, (guint)data->buffers_size);
gbinder_writer_data_write_buffer_object(data, NULL, 0,
gbinder_writer_data_append_buffer_object(data, NULL, 0,
&str_parent);
}
str_parent.offset += sizeof(GBinderHidlString);
}
} else {
gbinder_writer_data_write_buffer_object(data, NULL, 0, &vec_parent);
gbinder_writer_data_append_buffer_object(data, NULL, 0, &vec_parent);
}
}
@@ -892,7 +1173,7 @@ gbinder_writer_data_append_local_object(
/* Preallocate enough space */
g_byte_array_set_size(buf, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
/* Write the object */
n = data->io->encode_local_object(buf->data + offset, obj);
n = data->io->encode_local_object(buf->data + offset, obj, data->protocol);
/* Fix the data size */
g_byte_array_set_size(buf, offset + n);
/* Record the offset */
@@ -941,6 +1222,67 @@ gbinder_writer_append_byte_array(
}
}
#if GBINDER_FMQ_SUPPORTED
static
void
gbinder_writer_data_append_fmq_descriptor(
GBinderWriterData* data,
const GBinderFmq* queue)
{
GBinderParent parent;
GBinderMQDescriptor* desc = gbinder_fmq_get_descriptor(queue);
GBinderMQDescriptor* mqdesc = gutil_memdup(desc,
sizeof(GBinderMQDescriptor));
const gsize vec_total =
desc->grantors.count * sizeof(GBinderFmqGrantorDescriptor);
void* vec_buf = gutil_memdup(desc->grantors.data.ptr, vec_total);
const gsize fds_total = sizeof(GBinderFds) +
sizeof(int) * (desc->data.fds->num_fds + desc->data.fds->num_ints);
GBinderFds* fds = gutil_memdup(desc->data.fds, fds_total);
mqdesc->data.fds = fds;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, fds);
/* Fill in the grantor vector descriptor */
if (vec_buf) {
mqdesc->grantors.count = desc->grantors.count;
mqdesc->grantors.data.ptr = vec_buf;
mqdesc->grantors.owns_buffer = TRUE;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, vec_buf);
}
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, mqdesc);
/* Write the FMQ descriptor object */
parent.index = gbinder_writer_data_append_buffer_object(data,
mqdesc, sizeof(*mqdesc), NULL);
/* Write the vector data buffer */
parent.offset = GBINDER_MQ_DESCRIPTOR_GRANTORS_OFFSET;
gbinder_writer_data_append_buffer_object(data, vec_buf, vec_total,
&parent);
/* Write the fds */
parent.offset = GBINDER_MQ_DESCRIPTOR_FDS_OFFSET;
gbinder_writer_data_append_fds(data, mqdesc->data.fds, &parent);
}
void
gbinder_writer_append_fmq_descriptor(
GBinderWriter* self,
const GBinderFmq* queue) /* since 1.1.14 */
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data) && G_LIKELY(queue)) {
gbinder_writer_data_append_fmq_descriptor(data, queue);
}
}
#endif /* GBINDER_FMQ_SUPPORTED */
void
gbinder_writer_data_append_remote_object(
GBinderWriterData* data,
@@ -995,6 +1337,14 @@ gbinder_writer_malloc0(
return gbinder_writer_alloc(self, size, g_malloc0, g_free);
}
char*
gbinder_writer_strdup(
GBinderWriter* writer,
const char* str) /* since 1.1.13 */
{
return str ? gbinder_writer_memdup(writer, str, strlen(str) + 1) : NULL;
}
void*
gbinder_writer_memdup(
GBinderWriter* self,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -39,6 +39,7 @@
typedef struct gbinder_writer_data {
const GBinderIo* io;
const GBinderRpcProtocol* protocol;
GByteArray* bytes;
GUtilIntArray* offsets;
gsize buffers_size;
@@ -130,6 +131,13 @@ gbinder_writer_data_append_buffer_object(
const GBinderParent* parent)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_parcelable(
GBinderWriterData* data,
const void* ptr,
gsize size)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_hidl_vec(
GBinderWriterData* data,
@@ -163,6 +171,12 @@ gbinder_writer_data_append_remote_object(
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_fd(
GBinderWriterData* data,
int fd)
GBINDER_INTERNAL;
#endif /* GBINDER_WRITER_PRIVATE_H */
/*

View File

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

View File

@@ -0,0 +1,260 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gbinder.h>
#include <gutil_misc.h>
#include <gutil_log.h>
#include <sys/mman.h>
#define RET_OK (0)
#define RET_NOTFOUND (1)
#define RET_INVARG (2)
#define RET_ERR (3)
#define DEFAULT_BINDER GBINDER_DEFAULT_HWBINDER
#define ALLOCATOR_IFACE "android.hidl.allocator@1.0::IAllocator"
#define DEFAULT_FQNAME ALLOCATOR_IFACE "/ashmem"
#define TX_ALLOCATE GBINDER_FIRST_CALL_TRANSACTION
typedef struct app_options {
const char* fqname;
char* dev;
gsize size;
} AppOptions;
static
void
app_dumpmem(
const GBinderHidlMemory* mem)
{
const GBinderFds* fds = mem->data.fds;
GDEBUG("Name: %s", mem->name.data.str);
GDEBUG("Size: %" G_GUINT64_FORMAT " bytes", mem->size);
GASSERT(fds->version == GBINDER_HIDL_FDS_VERSION);
GDEBUG("Contains %u fd(s)", fds->num_fds);
if (fds->num_fds) {
guint i;
for (i = 0; i < fds->num_fds; i++) {
int fd = gbinder_fds_get_fd(fds, i);
guint8* ptr = mmap(NULL, mem->size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (ptr) {
gsize off = 0;
GDEBUG("fd %d => %p", fd, ptr);
while (off < mem->size) {
char line[GUTIL_HEXDUMP_BUFSIZE];
guint n = gutil_hexdump(line, ptr + off, mem->size - off);
GDEBUG("%04X: %s", (uint) off, line);
off += n;
}
munmap(ptr, mem->size);
} else {
GDEBUG("fd %d", fd);
}
}
}
}
static
int
app_allocate(
const AppOptions* opt,
GBinderClient* client)
{
GBinderLocalRequest* request = gbinder_client_new_request(client);
GBinderRemoteReply* reply;
int status, ret;
gbinder_local_request_append_int64(request, opt->size);
reply = gbinder_client_transact_sync_reply(client, TX_ALLOCATE,
request, &status);
if (reply) {
GBinderReader reader;
gint32 tx_status;
gboolean success;
gbinder_remote_reply_init_reader(reply, &reader);
if (gbinder_reader_read_int32(&reader, &tx_status) &&
gbinder_reader_read_bool(&reader, &success) &&
tx_status == GBINDER_STATUS_OK &&
success) {
const GBinderHidlMemory* mem = gbinder_reader_read_hidl_struct
(&reader, GBinderHidlMemory);
if (mem) {
GINFO("OK");
app_dumpmem(mem);
} else {
GINFO("OOPS");
}
} else {
GINFO("FAILED");
}
ret = RET_OK;
} else {
GERR("Call failed (%d)", status);
ret = RET_ERR;
}
gbinder_local_request_unref(request);
gbinder_remote_reply_unref(reply);
return ret;
}
static
int
app_run(
const AppOptions* opt)
{
int ret = RET_NOTFOUND;
GBinderServiceManager* sm = gbinder_servicemanager_new(opt->dev);
if (sm) {
int status = 0;
GBinderRemoteObject* remote = gbinder_servicemanager_get_service_sync
(sm, opt->fqname, &status);
if (remote) {
GBinderClient* client = gbinder_client_new(remote, ALLOCATOR_IFACE);
ret = app_allocate(opt, client);
gbinder_client_unref(client);
} else {
GERR("%s not found", opt->fqname);
}
gbinder_servicemanager_unref(sm);
} else {
GERR("No servicemanager at %s", opt->dev);
}
return ret;
}
static
gboolean
app_log_verbose(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
gutil_log_default.level = GLOG_LEVEL_VERBOSE;
return TRUE;
}
static
gboolean
app_log_quiet(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
gutil_log_default.level = GLOG_LEVEL_NONE;
return TRUE;
}
static
gboolean
app_init(
AppOptions* opt,
int argc,
char* argv[])
{
gboolean ok = FALSE;
GOptionEntry entries[] = {
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_verbose, "Enable verbose output", NULL },
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_quiet, "Be quiet", NULL },
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
"Binder device [" DEFAULT_BINDER "]", "DEVICE" },
{ NULL }
};
GError* error = NULL;
GOptionContext* options = g_option_context_new("[FQNAME]");
gutil_log_timestamp = FALSE;
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
g_option_context_add_main_entries(options, entries, NULL);
if (g_option_context_parse(options, &argc, &argv, &error)) {
if (!opt->dev || !opt->dev[0]) {
opt->dev = g_strdup(DEFAULT_BINDER);
}
if (argc < 3) {
opt->fqname = ((argc == 2) ? argv[1] : DEFAULT_FQNAME);
opt->size = 64;
ok = TRUE;
} else {
char* help = g_option_context_get_help(options, TRUE, NULL);
fprintf(stderr, "%s", help);
g_free(help);
}
} else {
GERR("%s", error->message);
g_error_free(error);
}
g_option_context_free(options);
return ok;
}
int main(int argc, char* argv[])
{
AppOptions opt;
int ret = RET_INVARG;
memset(&opt, 0, sizeof(opt));
if (app_init(&opt, argc, argv)) {
ret = app_run(&opt);
}
g_free(opt.dev);
return ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,154 +1,5 @@
# -*- Mode: makefile-gmake -*-
.PHONY: all debug release clean cleaner
.PHONY: libgbinder-release libgbinder-debug
#
# Required packages
#
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
#
# Default target
#
all: debug release
#
# Executable
#
EXE = binder-bridge
#
# Sources
#
SRC = $(EXE).c
#
# Directories
#
SRC_DIR = .
BUILD_DIR = build
LIB_DIR = ../..
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
#
# Tools and flags
#
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
QUIET_MAKE = make --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =
ifndef KEEP_SYMBOLS
KEEP_SYMBOLS = 0
endif
ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
SUBMAKE_OPTS += KEEP_SYMBOLS=1
endif
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
#
# Files
#
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
#
# Rules
#
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
debug: libgbinder-debug $(DEBUG_EXE)
release: libgbinder-release $(RELEASE_EXE)
clean:
rm -f *~
rm -fr $(BUILD_DIR)
cleaner: clean
@make -C $(LIB_DIR) clean
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
ifeq ($(KEEP_SYMBOLS),0)
strip $@
endif
libgbinder-debug:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
libgbinder-release:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
#
# Install
#
INSTALL = install
INSTALL_BIN_DIR = $(DESTDIR)/usr/bin
install: release $(INSTALL_BIN_DIR)
$(INSTALL) -m 755 $(RELEASE_EXE) $(INSTALL_BIN_DIR)
$(INSTALL_BIN_DIR):
$(INSTALL) -d $@
include ../common/Makefile

View File

@@ -49,10 +49,9 @@ CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include -I$(GEN_DIR) -I$(SRC_DIR)
BASE_FLAGS = -fPIC
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
CFLAGS += -fPIC $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
LDFLAGS += -pie $(shell pkg-config --libs $(PKGS))
QUIET_MAKE = make --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021 Franz-Josef Haider <franz.haider@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
@@ -80,9 +80,11 @@ go_through_transaction_ast(
switch(v->type) {
case INT8_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("int8");
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("int8 %u", (guint)(*((guint8*)v->value)));
}
if (parent_idx == -1) {
gbinder_writer_append_int32(&app->writer, *((int*)v->value));
gbinder_writer_append_int8(&app->writer, *((guint8*)v->value));
} else if (cur_pass == FILL_BUFFERS) {
*((unsigned char*)(((char*)buf)+offset)) =
*((unsigned char*)v->value);
@@ -91,7 +93,9 @@ go_through_transaction_ast(
break;
case INT32_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("int32");
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("int32 %d", *((int*)v->value));
}
if (parent_idx == -1) {
gbinder_writer_append_int32(&app->writer, *((int*)v->value));
} else if (cur_pass == FILL_BUFFERS) {
@@ -101,7 +105,9 @@ go_through_transaction_ast(
break;
case INT64_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("int64");
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("int64 %" G_GINT64_MODIFIER "d", *((gint64*)v->value));
}
if (parent_idx == -1) {
gbinder_writer_append_int64(&app->writer, *((gint64*)v->value));
} else if (cur_pass == FILL_BUFFERS) {
@@ -111,7 +117,9 @@ go_through_transaction_ast(
break;
case FLOAT_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("float");
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("float %g", (double)*((float*)v->value));
}
if (parent_idx == -1) {
gbinder_writer_append_float(&app->writer, *((float*)v->value));
} else if (cur_pass == FILL_BUFFERS) {
@@ -120,7 +128,9 @@ go_through_transaction_ast(
offset += sizeof(float);
break;
case DOUBLE_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("double");
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("double %g", *((double*)v->value));
}
if (parent_idx == -1) {
gbinder_writer_append_double(&app->writer,*((double*)v->value));
} else if (cur_pass == FILL_BUFFERS) {
@@ -130,7 +140,9 @@ go_through_transaction_ast(
break;
case STRING8_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("string8");
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("string8 %s", (char*)v->value);
}
gbinder_writer_append_string8(&app->writer, v->value);
/* offset not incremented since it only makes sense for hidl */
break;
@@ -579,7 +591,7 @@ app_run(
App* app)
{
const AppOptions* opt = app->opt;
char* iface = opt->iface ? g_strdup(opt->iface) : NULL;
char* iface;
int status = 0;
int rargc = 1;
char* service = opt->argv[rargc++];
@@ -598,7 +610,6 @@ app_run(
service, &status);
if (!obj) {
GERR("No such service: %s", service);
g_free(iface);
return;
}
@@ -764,14 +775,34 @@ app_init(
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
if (g_option_context_parse(options, &argc, &argv, &error)) {
char* help;
int i;
/*
* Remove the "--" argument. If any of our arguments is a negative
* number, the user will have to add the "--" flag to stop the parser.
* But "--" is still passed to us and we have to ignore it.
*/
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--")) {
if (i < (argc - 1)) {
memmove(argv + i, argv + (i + 1),
sizeof(char*) * (argc - i - 1));
}
i--;
argc--;
/*
* There's no need to have more than one "--", but let's
* remove any number of those.
*/
}
}
if (argc > 2) {
opt->argc = argc;
opt->argv = argv;
ok = TRUE;
} else {
help = g_option_context_get_help(options, TRUE, NULL);
char* help = g_option_context_get_help(options, TRUE, NULL);
fprintf(stderr, "%s", help);
g_free(help);
}
@@ -800,7 +831,6 @@ int main(int argc, char* argv[])
GERR("servicemanager seems to be missing");
}
}
g_free(opt.iface);
g_free(opt.dev);
return app.ret;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021-2022 Jolla Ltd.
*
* You may use this file under the terms of BSD license as follows:
*
@@ -36,7 +36,6 @@
typedef struct app_options {
char* dev;
char* iface;
gboolean oneway;
gboolean aidl;
gint transaction;

View File

@@ -55,11 +55,11 @@ char* handle_str8(char* text) {
"}" { return('}'); }
"[" { return('['); }
"]" { return(']'); }
{D}*{INT8_SUFFIX} { cmdlinelval.int8_value = atoi(yytext); return(INT8_VALUE); }
{D}*{INT64_SUFFIX} { cmdlinelval.int64_value = atol(yytext); return(INT64_VALUE); }
{D}* { cmdlinelval.int32_value = atoi(yytext); return(INT32_VALUE); }
{D}+"."{D}*{INT64_SUFFIX} { cmdlinelval.double_value = atof(yytext); return(DOUBLE_VALUE); }
{D}+"."{D}* { cmdlinelval.float_value = atof(yytext); return(FLOAT_VALUE); }
-?{D}+{INT8_SUFFIX} { cmdlinelval.int8_value = atoi(yytext); return(INT8_VALUE); }
-?{D}+{INT64_SUFFIX} { cmdlinelval.int64_value = atol(yytext); return(INT64_VALUE); }
-?{D}+ { cmdlinelval.int32_value = atoi(yytext); return(INT32_VALUE); }
-?{D}+"."{D}*{INT64_SUFFIX} { cmdlinelval.double_value = atof(yytext); return(DOUBLE_VALUE); }
-?{D}+"."{D}* { cmdlinelval.float_value = atof(yytext); return(FLOAT_VALUE); }
"reply" { return(REPLY); }
\".*\"{HSTRING_SUFFIX} { cmdlinelval.hstring_value = handle_str(yytext); return(HSTRING_VALUE); }
\".*\"{UTF16_SUFFIX} { cmdlinelval.string16_value = handle_str(yytext); return(STRING16_VALUE); }

View File

@@ -1,140 +1,5 @@
# -*- 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-client
#
# 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)
include ../common/Makefile

View File

@@ -1,140 +1,5 @@
# -*- 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)
include ../common/Makefile

View File

@@ -171,6 +171,8 @@ app_init(
app_log_verbose, "Enable verbose output", NULL },
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_quiet, "Be quiet", NULL },
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
"Binder device [" DEV_DEFAULT "]", "DEVICE" },
{ NULL }
};
@@ -187,7 +189,7 @@ app_init(
if (g_option_context_parse(options, &argc, &argv, &error)) {
char* help;
opt->dev = g_strdup(DEV_DEFAULT);
if (!opt->dev || !opt->dev[0]) opt->dev = g_strdup(DEV_DEFAULT);
switch (argc) {
case 2:
opt->service = argv[1];

View File

@@ -1,154 +1,5 @@
# -*- 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-list
#
# Sources
#
SRC = $(EXE).c
#
# Directories
#
SRC_DIR = .
BUILD_DIR = build
LIB_DIR = ../..
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
#
# Tools and flags
#
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
QUIET_MAKE = make --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =
ifndef KEEP_SYMBOLS
KEEP_SYMBOLS = 0
endif
ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
SUBMAKE_OPTS += KEEP_SYMBOLS=1
endif
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
#
# Files
#
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
#
# Rules
#
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
debug: libgbinder-debug $(DEBUG_EXE)
release: libgbinder-release $(RELEASE_EXE)
clean:
rm -f *~
rm -fr $(BUILD_DIR)
cleaner: clean
@make -C $(LIB_DIR) clean
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
ifeq ($(KEEP_SYMBOLS),0)
strip $@
endif
libgbinder-debug:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
libgbinder-release:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
#
# Install
#
INSTALL = install
INSTALL_BIN_DIR = $(DESTDIR)/usr/bin
install: release $(INSTALL_BIN_DIR)
$(INSTALL) -m 755 $(RELEASE_EXE) $(INSTALL_BIN_DIR)
$(INSTALL_BIN_DIR):
$(INSTALL) -d $@
include ../common/Makefile

View File

@@ -1,154 +1,5 @@
# -*- 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-ping
#
# Sources
#
SRC = $(EXE).c
#
# Directories
#
SRC_DIR = .
BUILD_DIR = build
LIB_DIR = ../..
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
#
# Tools and flags
#
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
QUIET_MAKE = make --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =
ifndef KEEP_SYMBOLS
KEEP_SYMBOLS = 0
endif
ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
SUBMAKE_OPTS += KEEP_SYMBOLS=1
endif
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
#
# Files
#
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
#
# Rules
#
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
debug: libgbinder-debug $(DEBUG_EXE)
release: libgbinder-release $(RELEASE_EXE)
clean:
rm -f *~
rm -fr $(BUILD_DIR)
cleaner: clean
@make -C $(LIB_DIR) clean
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
ifeq ($(KEEP_SYMBOLS),0)
strip $@
endif
libgbinder-debug:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
libgbinder-release:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
#
# Install
#
INSTALL = install
INSTALL_BIN_DIR = $(DESTDIR)/usr/bin
install: release $(INSTALL_BIN_DIR)
$(INSTALL) -m 755 $(RELEASE_EXE) $(INSTALL_BIN_DIR)
$(INSTALL_BIN_DIR):
$(INSTALL) -d $@
include ../common/Makefile

View File

@@ -1,140 +1,5 @@
# -*- 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-service
#
# 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)
include ../common/Makefile

152
test/common/Makefile Normal file
View File

@@ -0,0 +1,152 @@
# -*- Mode: makefile-gmake -*-
.PHONY: all debug release install clean cleaner
.PHONY: libgbinder-release libgbinder-debug
#
# Executable must be defined
#
ifndef EXE
${error EXE not defined}
endif
#
# Required packages
#
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
#
# Default target
#
all: debug release
#
# 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
CFLAGS += -fPIC $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
LDFLAGS += -pie $(shell pkg-config --libs $(PKGS))
QUIET_MAKE = make --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =
KEEP_SYMBOLS ?= 0
ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
SUBMAKE_OPTS += KEEP_SYMBOLS=1
endif
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
#
# Files
#
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
#
# Rules
#
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
debug: libgbinder-debug $(DEBUG_EXE)
release: libgbinder-release $(RELEASE_EXE)
clean:
rm -f *~
rm -fr $(BUILD_DIR)
cleaner: clean
@make -C $(LIB_DIR) clean
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
ifeq ($(KEEP_SYMBOLS),0)
strip $@
endif
libgbinder-debug:
@$(MAKE) $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
libgbinder-release:
@$(MAKE) $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
#
# Install
#
INSTALL = install
INSTALL_BIN_DIR = $(DESTDIR)/usr/bin
install: release $(INSTALL_BIN_DIR)
$(INSTALL) -m 755 $(RELEASE_EXE) $(INSTALL_BIN_DIR)
$(INSTALL_BIN_DIR):
$(INSTALL) -d $@

View File

@@ -1,140 +1,5 @@
# -*- 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 = rild-card-status
#
# 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)
include ../common/Makefile

View File

@@ -9,6 +9,7 @@ all:
@$(MAKE) -C unit_config $*
@$(MAKE) -C unit_driver $*
@$(MAKE) -C unit_eventloop $*
@$(MAKE) -C unit_fmq $*
@$(MAKE) -C unit_ipc $*
@$(MAKE) -C unit_local_object $*
@$(MAKE) -C unit_local_reply $*
@@ -23,6 +24,8 @@ all:
@$(MAKE) -C unit_servicemanager $*
@$(MAKE) -C unit_servicemanager_aidl $*
@$(MAKE) -C unit_servicemanager_aidl2 $*
@$(MAKE) -C unit_servicemanager_aidl3 $*
@$(MAKE) -C unit_servicemanager_aidl4 $*
@$(MAKE) -C unit_servicemanager_hidl $*
@$(MAKE) -C unit_servicename $*
@$(MAKE) -C unit_servicepoll $*

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -35,56 +35,82 @@
#include "test_common.h"
typedef struct test_binder TestBinder;
#define B_TYPE_LARGE 0x85
#define BINDER_TYPE_BINDER GBINDER_FOURCC('s', 'b', '*', B_TYPE_LARGE)
#define BINDER_TYPE_HANDLE GBINDER_FOURCC('s', 'h', '*', B_TYPE_LARGE)
#define BINDER_TYPE_PTR GBINDER_FOURCC('p', 't', '*', B_TYPE_LARGE)
#define BUFFER_OBJECT_SIZE_32 (24)
#define BUFFER_OBJECT_SIZE_64 (40)
#define BINDER_OBJECT_SIZE_32 (16)
#define BINDER_OBJECT_SIZE_64 (24)
typedef enum test_br_thread {
THIS_THREAD = -3,
LOOPER_THREAD = -2,
TX_THREAD = -1,
ANY_THREAD = 0
} TEST_BR_THREAD;
void
test_binder_br_noop(
int fd);
int fd,
TEST_BR_THREAD dest);
void
test_binder_br_increfs(
int fd,
TEST_BR_THREAD dest,
void* ptr);
void
test_binder_br_acquire(
int fd,
TEST_BR_THREAD dest,
void* ptr);
void
test_binder_br_release(
int fd,
TEST_BR_THREAD dest,
void* ptr);
void
test_binder_br_decrefs(
int fd,
TEST_BR_THREAD dest,
void* ptr);
void
test_binder_br_transaction_complete(
int fd);
void
test_binder_br_transaction_complete_later(
int fd);
int fd,
TEST_BR_THREAD dest);
void
test_binder_br_dead_binder(
int fd,
TEST_BR_THREAD dest,
guint handle);
void
test_binder_br_dead_binder_obj(
int fd,
GBinderLocalObject* obj);
void
test_binder_br_dead_reply(
int fd);
int fd,
TEST_BR_THREAD dest);
void
test_binder_br_failed_reply(
int fd);
int fd,
TEST_BR_THREAD dest);
void
test_binder_br_transaction(
int fd,
TEST_BR_THREAD dest,
void* target,
guint32 code,
const GByteArray* bytes);
@@ -92,6 +118,7 @@ test_binder_br_transaction(
void
test_binder_br_reply(
int fd,
TEST_BR_THREAD dest,
guint32 handle,
guint32 code,
const GByteArray* bytes);
@@ -99,35 +126,12 @@ test_binder_br_reply(
void
test_binder_br_reply_status(
int fd,
TEST_BR_THREAD dest,
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);
typedef enum test_looper {
TEST_LOOPER_DISABLE,
TEST_LOOPER_ENABLE,
TEST_LOOPER_ENABLE_ONE
} TEST_LOOPER;
void
test_binder_set_looper_enabled(
int fd,
TEST_LOOPER value);
void
test_binder_set_passthrough(
int fd,
gboolean passthrough);
test_binder_ignore_dead_object(
int fd);
int
test_binder_handle(

View File

@@ -80,6 +80,10 @@ test_run_in_context(
/* Helper macros */
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
# define TEST_INT8_BYTES_4(v) \
(guint8)(v), 0, 0, 0
# define TEST_INT16_BYTES_4(v) \
(guint8)(v), (guint8)((v) >> 8), 0, 0
# define TEST_INT16_BYTES(v) \
(guint8)(v), (guint8)((v) >> 8)
# define TEST_INT32_BYTES(v) \
@@ -91,6 +95,10 @@ test_run_in_context(
(guint8)(((guint64)(v)) >> 32), (guint8)(((guint64)(v)) >> 40), \
(guint8)(((guint64)(v)) >> 48), (guint8)(((guint64)(v)) >> 56)
#elif G_BYTE_ORDER == G_BIG_ENDIAN
# define TEST_INT8_BYTES_4(v) \
0, 0, 0, (guint8)(v)
# define TEST_INT16_BYTES_4(v) \
0, 0, (guint8)((v) >> 8), (guint8)(v)
# define TEST_INT16_BYTES(v) \
(guint8)((v) >> 8), (guint8)(v)
# define TEST_INT32_BYTES(v) \

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -277,9 +277,10 @@ test_servicemanager_hidl_add(
const char* sep = strrchr(instance, '/');
GDEBUG("Adding '%s'", instance);
/* Transfer remote_obj reference to the hashtable */
g_hash_table_replace(self->objects, g_strdup(instance), remote_obj);
if (sep) {
/* Alread know the interface */
/* Already know the interface */
char* iface = g_strndup(instance, sep - instance);
test_servicemanager_hidl_notify_all(self, iface, sep + 1, FALSE);
@@ -350,7 +351,7 @@ test_servicemanager_hidl_register_for_notifications(
iface = gbinder_reader_read_hidl_string_c(&reader);
instance = gbinder_reader_read_hidl_string_c(&reader);
watcher = gbinder_reader_read_object(&reader);
if (watcher) {
GBinderClient* wc = gbinder_client_new(watcher, NOTIFICATION_IFACE);
GHashTableIter it;
@@ -481,6 +482,38 @@ test_servicemanager_hidl_lookup(
return object;
}
gboolean
test_servicemanager_hidl_remove(
TestServiceManagerHidl* self,
const char* fqname)
{
gboolean removed = FALSE;
if (self) {
GBinderRemoteObject* obj;
/* Lock */
g_mutex_lock(&self->mutex);
obj = g_hash_table_lookup(self->objects, fqname);
if (obj) {
GHashTableIter it;
gpointer key, value;
g_hash_table_iter_init(&it, self->objects);
while (g_hash_table_iter_next(&it, &key, &value)) {
if (value == obj) {
GDEBUG("Removed name '%s' => %p", (char*) key, value);
g_hash_table_iter_remove(&it);
removed = TRUE;
}
}
}
g_mutex_unlock(&self->mutex);
/* Unlock */
}
return removed;
}
/*==========================================================================*
* Internals
*==========================================================================*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -58,6 +58,11 @@ test_servicemanager_hidl_lookup(
TestServiceManagerHidl* self,
const char* name);
gboolean
test_servicemanager_hidl_remove(
TestServiceManagerHidl* self,
const char* fqname);
#endif /* TEST_SERVICEMANAGER_HIDL_H */
/*

View File

@@ -11,6 +11,7 @@ unit_client \
unit_config \
unit_driver \
unit_eventloop \
unit_fmq \
unit_ipc \
unit_local_object \
unit_local_reply \
@@ -25,6 +26,8 @@ unit_remote_request \
unit_servicemanager \
unit_servicemanager_aidl \
unit_servicemanager_aidl2 \
unit_servicemanager_aidl3 \
unit_servicemanager_aidl4 \
unit_servicemanager_hidl \
unit_servicename \
unit_servicepoll \

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -52,9 +52,7 @@
static TestOpt test_opt;
#define SRC_DEV "/dev/srcbinder"
#define SRC_PRIV_DEV SRC_DEV "-private"
#define DEST_DEV "/dev/dstbinder"
#define DEST_PRIV_DEV DEST_DEV "-private"
#define TEST_IFACE "gbinder@1.0::ITest"
#define TX_CODE GBINDER_FIRST_CALL_TRANSACTION
@@ -74,75 +72,6 @@ typedef struct test_config {
char* file;
} TestConfig;
/*==========================================================================*
* Test object (registered with two GBinderIpc's)
*==========================================================================*/
typedef GBinderLocalObjectClass TestLocalObjectClass;
typedef struct test_local_object {
GBinderLocalObject parent;
GBinderIpc* ipc2;
} TestLocalObject;
G_DEFINE_TYPE(TestLocalObject, test_local_object, GBINDER_TYPE_LOCAL_OBJECT)
#define TEST_TYPE_LOCAL_OBJECT test_local_object_get_type()
#define TEST_LOCAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
TEST_TYPE_LOCAL_OBJECT, TestLocalObject))
TestLocalObject*
test_local_object_new(
GBinderIpc* ipc,
GBinderIpc* ipc2,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
{
TestLocalObject* self = TEST_LOCAL_OBJECT
(gbinder_local_object_new_with_type(TEST_TYPE_LOCAL_OBJECT,
ipc, ifaces, txproc, user_data));
self->ipc2 = gbinder_ipc_ref(ipc2);
gbinder_ipc_register_local_object(ipc2, &self->parent);
return self;
}
static
void
test_local_object_dispose(
GObject* object)
{
TestLocalObject* self = TEST_LOCAL_OBJECT(object);
gbinder_ipc_local_object_disposed(self->ipc2, &self->parent);
G_OBJECT_CLASS(test_local_object_parent_class)->dispose(object);
}
static
void
test_local_object_finalize(
GObject* object)
{
gbinder_ipc_unref(TEST_LOCAL_OBJECT(object)->ipc2);
G_OBJECT_CLASS(test_local_object_parent_class)->finalize(object);
}
static
void
test_local_object_init(
TestLocalObject* self)
{
}
static
void
test_local_object_class_init(
TestLocalObjectClass* klass)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->dispose = test_local_object_dispose;
object_class->finalize = test_local_object_finalize;
}
/*==========================================================================*
* Common
*==========================================================================*/
@@ -183,11 +112,10 @@ TestServiceManagerHidl*
test_servicemanager_impl_new(
const char* dev)
{
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
TestServiceManagerHidl* sm = test_servicemanager_hidl_new(ipc);
test_binder_set_looper_enabled(fd, TRUE);
test_binder_register_object(fd, GBINDER_LOCAL_OBJECT(sm),
GBINDER_SERVICEMANAGER_HANDLE);
gbinder_ipc_unref(ipc);
@@ -338,18 +266,15 @@ test_basic_run(
GBinderServiceManager* src;
GBinderServiceManager* dest;
GBinderIpc* src_ipc;
GBinderIpc* src_priv_ipc;
GBinderIpc* dest_ipc;
GBinderIpc* dest_priv_ipc;
GBinderBridge* bridge;
TestLocalObject* obj;
GBinderRemoteObject* br_src_obj;
GBinderLocalObject* obj;
GBinderRemoteObject* src_obj;
GBinderLocalRequest* req;
GBinderClient* src_client;
const char* name = "test";
const char* fqname = TEST_IFACE "/test";
int src_fd, dest_fd, h, n = 0;
int src_fd, dest_fd, n = 0;
gulong id;
test_config_init(&config, NULL);
@@ -357,22 +282,15 @@ test_basic_run(
test.loop = g_main_loop_new(NULL, FALSE);
/* obj (DEST) <=> bridge <=> (SRC) mirror */
src_ipc = gbinder_ipc_new(SRC_DEV);
src_priv_ipc = gbinder_ipc_new(SRC_PRIV_DEV);
dest_ipc = gbinder_ipc_new(DEST_DEV);
dest_priv_ipc = gbinder_ipc_new(DEST_PRIV_DEV);
test.src_impl = test_servicemanager_impl_new(SRC_PRIV_DEV);
dest_impl = test_servicemanager_impl_new(DEST_PRIV_DEV);
src_ipc = gbinder_ipc_new(SRC_DEV, NULL);
dest_ipc = gbinder_ipc_new(DEST_DEV, NULL);
test.src_impl = test_servicemanager_impl_new(SRC_DEV);
dest_impl = test_servicemanager_impl_new(DEST_DEV);
src_fd = gbinder_driver_fd(src_ipc->driver);
dest_fd = gbinder_driver_fd(dest_ipc->driver);
obj = test_local_object_new(dest_ipc, dest_priv_ipc, TEST_IFACES,
test_basic_cb, &n);
obj = gbinder_local_object_new(dest_ipc, TEST_IFACES, test_basic_cb, &n);
/* Set up binder simulator */
test_binder_set_passthrough(src_fd, TRUE);
test_binder_set_passthrough(dest_fd, TRUE);
test_binder_set_looper_enabled(src_fd, TEST_LOOPER_ENABLE);
test_binder_set_looper_enabled(dest_fd, TEST_LOOPER_ENABLE);
src = gbinder_servicemanager_new(SRC_DEV);
dest = gbinder_servicemanager_new(DEST_DEV);
@@ -387,7 +305,7 @@ test_basic_run(
/* Register the object and wait for completion */
GDEBUG("Registering object '%s' => %p", name, obj);
g_assert(gbinder_servicemanager_add_service(dest, name, &obj->parent,
g_assert(gbinder_servicemanager_add_service(dest, name, obj,
test_basic_add_cb, &test));
/* This loop quits after the name is added and notification is received */
@@ -398,25 +316,12 @@ test_basic_run(
gbinder_servicemanager_remove_handler(src, id);
/* Get a remote reference to the object created by the bridge */
br_src_obj = gbinder_servicemanager_get_service_sync(src, fqname, NULL);
g_assert(gbinder_remote_object_ref(br_src_obj)); /* autoreleased */
g_assert(!br_src_obj->dead);
/*
* This is a trick specific to test_binder simulation. We need to
* associate src_obj with the other side of the socket, so that the
* call goes like this:
*
* src_obj (src_priv) => (src) bridge (dest) => (dest_priv) => obj
*
* Note that the original src_obj gets autoreleased and doesn't need
* to be explicitly unreferenced.
*/
src_obj = gbinder_remote_object_new(src_priv_ipc,
br_src_obj->handle, REMOTE_OBJECT_CREATE_ALIVE);
src_obj = gbinder_servicemanager_get_service_sync(src, fqname, NULL);
g_assert(!src_obj->dead);
/* Make a call */
GDEBUG("Submitting a call");
/* src_client will hold a reference to src_obj */
src_client = gbinder_client_new(src_obj, TEST_IFACE);
req = gbinder_client_new_request(src_client);
gbinder_local_request_append_int32(req, TX_PARAM);
@@ -427,40 +332,38 @@ test_basic_run(
/* Wait for completion */
test_run(&test_opt, test.loop);
/* Kill the destination object and wait for auto-created object to die */
g_assert(!br_src_obj->dead);
id = gbinder_remote_object_add_death_handler(br_src_obj, test_basic_death,
/* Kill the objects and wait for one of them to die */
g_assert(!src_obj->dead);
id = gbinder_remote_object_add_death_handler(src_obj, test_basic_death,
test.loop);
h = test_binder_handle(dest_fd, &obj->parent);
g_assert_cmpint(h, > ,0); /* Zero is servicemanager */
GDEBUG("Killing destination object, handle %d", h);
gbinder_local_object_drop(&obj->parent);
test_binder_br_dead_binder(dest_fd, h);
g_assert(test_servicemanager_hidl_remove(dest_impl, fqname));
GDEBUG("Killing destination objects");
/*
* Need these BR_DEAD_BINDER because both servicemanagers and the
* bridge live inside the same process and reference the same objects.
* BR_DEAD_BINDER forces the bridge (proxy) to drop its reference.
*/
test_binder_br_dead_binder_obj(dest_fd, obj);
test_binder_br_dead_binder(src_fd, ANY_THREAD, src_obj->handle);
/* Wait for the auto-created object to die */
test_run(&test_opt, test.loop);
g_assert(br_src_obj->dead);
gbinder_remote_object_remove_handler(br_src_obj, id);
g_assert(src_obj->dead);
gbinder_remote_object_remove_handler(src_obj, id);
GDEBUG("Done");
gbinder_local_object_drop(obj);
gbinder_bridge_free(bridge);
gbinder_remote_object_unref(src_obj);
gbinder_remote_object_unref(br_src_obj);
test_servicemanager_hidl_free(test.src_impl);
test_servicemanager_hidl_free(dest_impl);
gbinder_servicemanager_unref(src);
gbinder_servicemanager_unref(dest);
gbinder_client_unref(src_client);
test_binder_unregister_objects(src_fd);
test_binder_unregister_objects(dest_fd);
gbinder_ipc_unref(src_ipc);
gbinder_ipc_unref(src_priv_ipc);
gbinder_ipc_unref(dest_ipc);
gbinder_ipc_unref(dest_priv_ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop);
test_config_deinit(&config);
g_main_loop_unref(test.loop);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -41,6 +41,7 @@
#include "gbinder_output_data.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_remote_reply.h"
#include "gbinder_writer.h"
#include <gutil_log.h>
@@ -54,7 +55,7 @@ test_client_new(
guint h,
const char* iface)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, h, TRUE);
GBinderClient* client = gbinder_client_new(obj, iface);
@@ -79,6 +80,7 @@ test_null(
g_assert(!gbinder_client_ref(NULL));
g_assert(!gbinder_client_interface(NULL));
g_assert(!gbinder_client_interface2(NULL, 0));
g_assert(!gbinder_client_rpc_header(NULL, 0));
gbinder_client_unref(NULL);
g_assert(!gbinder_client_new_request(NULL));
g_assert(!gbinder_client_new_request2(NULL, 0));
@@ -97,7 +99,7 @@ void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0, TRUE);
const char* iface = "foo";
@@ -112,6 +114,7 @@ test_basic(
gbinder_client_unref(client);
gbinder_remote_object_unref(obj);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -123,7 +126,7 @@ void
test_interfaces(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0, TRUE);
static const GBinderClientIfaceInfo ifaces[] = {
@@ -131,6 +134,11 @@ test_interfaces(
};
GBinderClient* client = gbinder_client_new2(obj, ifaces,
G_N_ELEMENTS(ifaces));
GBinderWriter writer;
GBinderLocalRequest* req;
GBytes* rpc_header;
gsize len;
const void* hdr;
g_assert(client);
g_assert_cmpstr(gbinder_client_interface(client), == ,"11");
@@ -138,12 +146,25 @@ test_interfaces(
g_assert_cmpstr(gbinder_client_interface2(client, 22), == ,"22");
g_assert_cmpstr(gbinder_client_interface2(client, 33), == ,"33");
g_assert(!gbinder_client_interface2(client, 34));
g_assert(!gbinder_client_rpc_header(client, 34));
g_assert(!gbinder_client_new_request2(client, 34));
/* Those fail to allocate default request for out-of-range codes: */
g_assert(!gbinder_client_transact_sync_reply(client, 34, NULL, NULL));
g_assert_cmpint(gbinder_client_transact_sync_oneway(client, 34, NULL),
== ,-EINVAL);
g_assert(!gbinder_client_transact(client, 34, 0, NULL, NULL, NULL, NULL));
/* Check the RPC header */
rpc_header = gbinder_client_rpc_header(client, 33);
req = gbinder_client_new_request2(client, 33);
g_assert(rpc_header);
g_assert(req);
gbinder_local_request_init_writer(req, &writer);
hdr = gbinder_writer_get_data(&writer, &len);
g_assert(hdr);
g_assert_cmpuint(len, == ,g_bytes_get_size(rpc_header));
g_assert(!memcmp(hdr, g_bytes_get_data(rpc_header, NULL), len));
gbinder_local_request_unref(req);
gbinder_client_unref(client);
/* Client with no interface info */
@@ -155,6 +176,7 @@ test_interfaces(
gbinder_remote_object_unref(obj);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -169,11 +191,12 @@ test_no_header(
GBinderClient* client = test_client_new(0, NULL);
int fd = gbinder_driver_fd(gbinder_client_ipc(client)->driver);
test_binder_br_transaction_complete(fd);
test_binder_ignore_dead_object(fd);
test_binder_br_transaction_complete(fd, THIS_THREAD);
g_assert(gbinder_client_transact_sync_oneway(client, 0, NULL) ==
GBINDER_STATUS_OK);
gbinder_client_unref(client);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -200,10 +223,9 @@ test_dead(
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, TEST_LOOPER_ENABLE);
gbinder_remote_object_add_death_handler(obj, test_dead_done, loop);
test_binder_br_dead_binder(fd, ANY_THREAD, handle);
test_run(&test_opt, loop);
g_assert(gbinder_remote_object_is_dead(obj));
@@ -212,7 +234,6 @@ test_dead(
g_assert(!gbinder_client_transact(client, 0, 0, NULL, NULL, NULL, NULL));
gbinder_client_unref(client);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -231,17 +252,18 @@ test_sync_oneway(
int fd = gbinder_driver_fd(gbinder_client_ipc(client)->driver);
g_assert(req);
test_binder_br_transaction_complete(fd);
test_binder_br_transaction_complete(fd, THIS_THREAD);
g_assert(gbinder_client_transact_sync_oneway(client, 0, req) ==
GBINDER_STATUS_OK);
gbinder_local_request_unref(req);
/* Same but using the internal (empty) request */
test_binder_br_transaction_complete(fd);
test_binder_br_transaction_complete(fd, THIS_THREAD);
g_assert(gbinder_client_transact_sync_oneway(client, 0, NULL) ==
GBINDER_STATUS_OK);
gbinder_client_unref(client);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -257,7 +279,8 @@ test_sync_reply_tx(
GBinderDriver* driver = gbinder_client_ipc(client)->driver;
int fd = gbinder_driver_fd(driver);
const GBinderIo* io = gbinder_driver_io(driver);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
const GBinderRpcProtocol* protocol = gbinder_driver_protocol(driver);
GBinderLocalReply* reply = gbinder_local_reply_new(io, protocol);
GBinderRemoteReply* tx_reply;
GBinderOutputData* data;
const guint32 handle = 0;
@@ -270,10 +293,11 @@ test_sync_reply_tx(
data = gbinder_local_reply_data(reply);
g_assert(data);
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);
test_binder_ignore_dead_object(fd);
test_binder_br_noop(fd, THIS_THREAD);
test_binder_br_transaction_complete(fd, THIS_THREAD);
test_binder_br_noop(fd, THIS_THREAD);
test_binder_br_reply(fd, THIS_THREAD, handle, code, data->bytes);
tx_reply = gbinder_client_transact_sync_reply(client, 0, req, &status);
g_assert(tx_reply);
@@ -302,6 +326,7 @@ test_sync_reply(
test_sync_reply_tx(client, NULL);
gbinder_client_unref(client);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -360,7 +385,8 @@ test_reply_tx(
GBinderDriver* driver = gbinder_client_ipc(client)->driver;
int fd = gbinder_driver_fd(driver);
const GBinderIo* io = gbinder_driver_io(driver);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
const GBinderRpcProtocol* protocol = gbinder_driver_protocol(driver);
GBinderLocalReply* reply = gbinder_local_reply_new(io, protocol);
GBinderOutputData* data;
const guint32 handle = 0;
const guint32 code = 1;
@@ -371,10 +397,11 @@ test_reply_tx(
data = gbinder_local_reply_data(reply);
g_assert(data);
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);
test_binder_ignore_dead_object(fd);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_transaction_complete(fd, TX_THREAD);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_reply(fd, TX_THREAD, handle, code, data->bytes);
id = gbinder_client_transact(client, 0, 0, req, done, destroy, loop);
g_assert(id);
@@ -402,6 +429,7 @@ test_reply(
test_reply_tx(client, NULL, done, destroy);
gbinder_client_unref(client);
test_binder_exit_wait(&test_opt, NULL);
}
static

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2020-2022 Jolla Ltd.
* Copyright (C) 2020-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -230,6 +230,8 @@ test_dirs(
char* file = g_build_filename(dir, "test.conf", NULL);
char* file1 = g_build_filename(subdir, "a.conf", NULL);
char* file2 = g_build_filename(subdir, "b.conf", NULL);
char* file3 = g_build_filename(subdir, "c.conf", NULL);
char* file4 = g_build_filename(subdir, "d.conf", NULL);
char* random_file = g_build_filename(subdir, "foo", NULL);
static const char garbage[] = "foo";
static const char config[] =
@@ -246,12 +248,24 @@ test_dirs(
"/dev/binder = aidl2\n"
"[ServiceManager]\n"
"/dev/binder = aidl2\n";
static const char config3[] =
"[Protocol]\n"
"/dev/binder3 = aidl3\n"
"[ServiceManager]\n"
"/dev/binder3 = aidl3\n";
static const char config4[] =
"[Protocol]\n"
"/dev/binder4 = aidl3\n"
"[ServiceManager]\n"
"/dev/binder4 = aidl4\n";
g_assert_cmpint(mkdir(subdir, 0700), == ,0);
g_assert_cmpint(mkdir(notafile, 0700), == ,0);
g_assert(g_file_set_contents(file, config, -1, NULL));
g_assert(g_file_set_contents(file1, config1, -1, NULL));
g_assert(g_file_set_contents(file2, config2, -1, NULL));
g_assert(g_file_set_contents(file3, config3, -1, NULL));
g_assert(g_file_set_contents(file4, config4, -1, NULL));
g_assert(g_file_set_contents(random_file, garbage, -1, NULL));
/* Reset the state */
@@ -263,9 +277,13 @@ test_dirs(
k = gbinder_config_get();
g_assert(k);
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder3",b), == ,"aidl3");
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b), == ,"aidl3");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hwbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder3",b),==,"aidl3");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4");
/* Remove the default file and try again */
gbinder_config_exit();
@@ -274,8 +292,12 @@ test_dirs(
g_assert(k);
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder3",b), == ,"aidl3");
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b), == ,"aidl3");
g_assert_cmpstr(test_value(k,"Protocol","/dev/hwbinder",b), == ,"hidl");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder3",b),==,"aidl3");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4");
/* Damage one of the files and try again */
gbinder_config_exit();
@@ -285,7 +307,11 @@ test_dirs(
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert(!test_value(k,"Protocol","/dev/hwbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder3",b), == ,"aidl3");
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b), == ,"aidl3");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder3",b),==,"aidl3");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4");
/* Disallow access to one of the files and try again */
gbinder_config_exit();
@@ -295,12 +321,28 @@ test_dirs(
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert(!test_value(k,"Protocol","/dev/hwbinder",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2");
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder3",b), == ,"aidl3");
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b), == ,"aidl3");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder3",b),==,"aidl3");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4");
/* Delete the remaining files and try again */
/* Leave only one file (file4) in the subdirectory */
gbinder_config_exit();
g_assert_cmpint(remove(file1), == ,0);
g_assert_cmpint(remove(file2), == ,0);
g_assert_cmpint(remove(file3), == ,0);
k = gbinder_config_get();
g_assert(k);
g_assert(!test_value(k,"Protocol","/dev/hbinder",b));
g_assert(!test_value(k,"Protocol","/dev/hwbinder",b));
g_assert(!test_value(k,"Protocol","/dev/binder3",b));
g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b),==,"aidl3");
g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4");
/* Delete the remaining file and try again */
gbinder_config_exit();
g_assert_cmpint(remove(file4), == ,0);
g_assert(!gbinder_config_get());
/* Undo all the damage */
@@ -312,6 +354,8 @@ test_dirs(
g_free(file);
g_free(file1);
g_free(file2);
g_free(file3);
g_free(file4);
g_free(random_file);
remove(notafile);
@@ -464,6 +508,34 @@ static const TestPresetsData test_presets_data [] = {
"[ServiceManager]\n"
"/dev/binder = aidl2\n"
"/dev/vndbinder = aidl2\n"
},{
"30",
"[General]\n"
"ApiLevel = 30",
"[General]\n"
"ApiLevel = 30\n"
"[Protocol]\n"
"/dev/binder = aidl3\n"
"/dev/vndbinder = aidl3\n"
"[ServiceManager]\n"
"/dev/binder = aidl3\n"
"/dev/vndbinder = aidl3\n"
},{
"31",
"[General]\n"
"ApiLevel = 31",
"[General]\n"
"ApiLevel = 31\n"
"[Protocol]\n"
"/dev/binder = aidl3\n"
"/dev/vndbinder = aidl3\n"
"[ServiceManager]\n"
"/dev/binder = aidl4\n"
"/dev/vndbinder = aidl4\n"
}
};

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -32,6 +32,7 @@
#include "test_binder.h"
#include "gbinder_config.h"
#include "gbinder_driver.h"
#include "gbinder_handler.h"
#include "gbinder_local_request_p.h"
@@ -81,6 +82,7 @@ test_basic(
g_assert(!gbinder_handler_transact(NULL, NULL, NULL, 0, 0, NULL));
g_assert(!gbinder_handler_can_loop(NULL));
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -97,11 +99,12 @@ test_noop(
g_assert(driver);
g_assert(fd >= 0);
test_binder_br_noop(fd);
test_binder_br_noop(fd, THIS_THREAD);
g_assert(gbinder_driver_poll(driver, NULL) == POLLIN);
g_assert(gbinder_driver_read(driver, NULL, NULL) == 0);
gbinder_driver_unref(driver);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -130,6 +133,7 @@ test_local_request(
g_assert(!memcmp(data->bytes->data, rpc_header, sizeof(rpc_header)));
gbinder_local_request_unref(req);
gbinder_driver_unref(driver);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -140,12 +144,31 @@ test_local_request(
int main(int argc, char* argv[])
{
const char* default_config_dir;
const char* default_config_file;
char* config_dir = g_dir_make_tmp("gbinder-test-driver-XXXXXX", NULL);
char* config_file = g_build_filename(config_dir, "test.conf", NULL);
int result;
/* Point gbinder_config_file to a non-existent file */
default_config_dir = gbinder_config_dir;
default_config_file = gbinder_config_file;
gbinder_config_dir = config_dir;
gbinder_config_file = config_file;
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "basic", test_basic);
g_test_add_func(TEST_PREFIX "noop", test_noop);
g_test_add_func(TEST_PREFIX "local_request", test_local_request);
test_init(&test_opt, argc, argv);
return g_test_run();
result = g_test_run();
gbinder_config_dir = default_config_dir;
gbinder_config_file = default_config_file;
remove(config_dir);
g_free(config_dir);
g_free(config_file);
return result;
}
/*

5
unit/unit_fmq/Makefile Normal file
View File

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

597
unit/unit_fmq/unit_fmq.c Normal file
View File

@@ -0,0 +1,597 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_common.h"
#include "gbinder_fmq_p.h"
#if GBINDER_FMQ_SUPPORTED
#include "gbinder_log.h"
#include <errno.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
static TestOpt test_opt;
typedef struct test_fmq_data {
const char* name;
gsize item_size;
gsize max_num_items;
gint type;
gint flags;
gint fd;
gsize buffer_size;
} TestFmqData;
/*==========================================================================*
* null
*==========================================================================*/
static const TestFmqData test_fmq_tests_null[] = {
{ "wrong_size", 0, 8,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE, 0, -1, 0 },
{ "wrong_count", sizeof(guint32), 0,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE, 0, -1, 0 },
{ "wrong_buffer_size", sizeof(guint32), 8,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE, 0, 1, 0 },
};
static
void
test_null(
gconstpointer test_data)
{
const TestFmqData* test = test_data;
GBinderFmq* fmq = gbinder_fmq_new(test->item_size, test->max_num_items,
test->type, test->flags, test->fd, test->buffer_size);
g_assert(!fmq);
g_assert(!gbinder_fmq_ref(fmq));
gbinder_fmq_unref(fmq);
g_assert(gbinder_fmq_available_to_read(fmq) == 0);
g_assert(gbinder_fmq_available_to_write(fmq) == 0);
g_assert(gbinder_fmq_available_to_read_contiguous(fmq) == 0);
g_assert(gbinder_fmq_available_to_write_contiguous(fmq) == 0);
g_assert(!gbinder_fmq_begin_read(fmq, 1));
g_assert(!gbinder_fmq_begin_read((GBinderFmq*)0x1, 0));
g_assert(!gbinder_fmq_begin_write(fmq, 1));
g_assert(!gbinder_fmq_begin_write((GBinderFmq*)0x1, 0));
g_assert(!gbinder_fmq_read(fmq, (void*)0x1, 1));
g_assert(!gbinder_fmq_read((GBinderFmq*)0x1, NULL, 1));
g_assert(!gbinder_fmq_read((GBinderFmq*)0x1, (void*)0x1, 0));
g_assert(!gbinder_fmq_write(fmq, (const void*)0x1, 1));
g_assert(!gbinder_fmq_write((GBinderFmq*)0x1, NULL, 1));
g_assert(!gbinder_fmq_write((GBinderFmq*)0x1, (const void*)0x1, 0));
g_assert(gbinder_fmq_wait_timeout(fmq, 0, (guint32*)0x1, 0) == -EINVAL);
g_assert(gbinder_fmq_wait_timeout((GBinderFmq*)0x1, 0, NULL, 0) == -EINVAL);
g_assert(gbinder_fmq_wait(fmq, 0, (guint32*)0x1) == -EINVAL);
g_assert(gbinder_fmq_wait((GBinderFmq*)0x1, 0, NULL) == -EINVAL);
g_assert(gbinder_fmq_wake(fmq, 0) == -EINVAL);
}
/*==========================================================================*
* read/write guint8
*==========================================================================*/
static const TestFmqData test_fmq_tests_read_write_guint8[] = {
{ "event_flag", sizeof(guint8), 8, GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0 },
{ "no_event_flag", sizeof(guint8), 8, GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
0, -1, 0 },
{ "no_reset", sizeof(guint8), 8, GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG |
GBINDER_FMQ_FLAG_NO_RESET_POINTERS, -1, 0 },
{ "unsync", sizeof(guint8), 8, GBINDER_FMQ_TYPE_UNSYNC_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0 },
{ "unsync_no_reset", sizeof(guint8), 8, GBINDER_FMQ_TYPE_UNSYNC_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG |
GBINDER_FMQ_FLAG_NO_RESET_POINTERS, -1, 0 },
};
static
void
test_read_write_guint8(
gconstpointer test_data)
{
const TestFmqData* test = test_data;
guint i;
guint8 in_data[test->max_num_items];
guint8 out_data[test->max_num_items];
GBinderFmq* fmq = gbinder_fmq_new(test->item_size, test->max_num_items,
test->type, test->flags, test->fd, test->buffer_size);
g_assert(fmq);
/* Intiailize input data with random numbers */
for (i = 0; i < test->max_num_items; ++i) {
in_data[i] = g_random_int() % G_MAXUINT8;
}
memset(out_data, 0, test->max_num_items);
/* Write data one value at a time */
for (i = 0; i < test->max_num_items; ++i) {
g_assert(gbinder_fmq_write(fmq, &in_data[i], 1));
g_assert(gbinder_fmq_available_to_read(fmq) == i + 1);
}
/* Try to write one item to full buffer
* only sync write fails if buffer is full */
if (test->type == GBINDER_FMQ_TYPE_SYNC_READ_WRITE) {
g_assert(!gbinder_fmq_write(fmq, &in_data[0], 1));
g_assert(gbinder_fmq_available_to_read(fmq) == test->max_num_items);
}
/* Read data one value at a time */
for (i = 0; i < test->max_num_items; ++i) {
g_assert(gbinder_fmq_read(fmq, &out_data, 1));
g_assert(out_data[0] == in_data[i]);
g_assert(gbinder_fmq_available_to_read(fmq) ==
test->max_num_items - i - 1);
}
/* Try to read when there is no data */
g_assert(!gbinder_fmq_read(fmq, &out_data, 1));
memset(out_data, 0, test->max_num_items);
/* Fill whole buffer with data */
g_assert(gbinder_fmq_write(fmq, in_data, test->max_num_items));
g_assert(gbinder_fmq_available_to_read(fmq) == test->max_num_items);
/* Read whole buffer */
g_assert(gbinder_fmq_read(fmq, &out_data, test->max_num_items));
g_assert(!memcmp(in_data, out_data, test->max_num_items * test->item_size));
memset(out_data, 0, test->max_num_items);
/* Try to write too many items */
g_assert(!gbinder_fmq_write(fmq, in_data, test->max_num_items + 1));
/* Overwrite unsync queue */
if (test->type == GBINDER_FMQ_TYPE_UNSYNC_WRITE) {
g_assert(gbinder_fmq_write(fmq, in_data, test->max_num_items));
g_assert(gbinder_fmq_write(fmq, in_data, 1));
/* Writing too much data to unsync queue causes read pointer to reset
* on next read */
g_assert(!gbinder_fmq_read(fmq, &out_data, 1));
g_assert(gbinder_fmq_available_to_read(fmq) == 0);
}
gbinder_fmq_unref(fmq);
}
/*==========================================================================*
* read/write gint64
*==========================================================================*/
static const TestFmqData test_fmq_tests_read_write_gint64[] = {
{ "event_flag", sizeof(gint64), 8, GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0 },
{ "no_event_flag", sizeof(gint64), 8, GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
0, -1, 0 },
{ "no_reset", sizeof(gint64), 8, GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG |
GBINDER_FMQ_FLAG_NO_RESET_POINTERS, -1, 0 },
{ "unsync", sizeof(gint64), 8, GBINDER_FMQ_TYPE_UNSYNC_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0 },
{ "unsync_no_reset", sizeof(guint64), 8, GBINDER_FMQ_TYPE_UNSYNC_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG |
GBINDER_FMQ_FLAG_NO_RESET_POINTERS, -1, 0 },
};
static
void
test_read_write_gint64(
gconstpointer test_data)
{
const TestFmqData* test = test_data;
guint i;
gint64 in_data[test->max_num_items];
gint64 out_data[test->max_num_items];
GBinderFmq* fmq = gbinder_fmq_new(test->item_size, test->max_num_items,
test->type, test->flags, test->fd, test->buffer_size);
g_assert(fmq);
/* Intiailize input data with random numbers */
for (i = 0; i < test->max_num_items; ++i) {
in_data[i] = g_random_int();
}
memset(out_data, 0, test->max_num_items);
/* Write data one value at a time */
for (i = 0; i < test->max_num_items; ++i) {
g_assert(gbinder_fmq_write(fmq, &in_data[i], 1));
g_assert(gbinder_fmq_available_to_read(fmq) == i + 1);
}
/* Try to write one item to full buffer
* only sync write fails if buffer is full */
if (test->type == GBINDER_FMQ_TYPE_SYNC_READ_WRITE) {
g_assert(!gbinder_fmq_write(fmq, &in_data[0], 1));
g_assert(gbinder_fmq_available_to_read(fmq) == test->max_num_items);
}
/* Read data one value at a time */
for (i = 0; i < test->max_num_items; ++i) {
g_assert(gbinder_fmq_read(fmq, &out_data, 1));
g_assert(out_data[0] == in_data[i]);
g_assert(gbinder_fmq_available_to_read(fmq) ==
test->max_num_items - i - 1);
}
/* Try to read when there is no data */
g_assert(!gbinder_fmq_read(fmq, &out_data, 1));
memset(out_data, 0, test->max_num_items);
/* Fill whole buffer with data */
g_assert(gbinder_fmq_write(fmq, in_data, test->max_num_items));
g_assert(gbinder_fmq_available_to_read(fmq) == test->max_num_items);
/* Read whole buffer */
g_assert(gbinder_fmq_read(fmq, &out_data, test->max_num_items));
g_assert(!memcmp(in_data, out_data, test->max_num_items * test->item_size));
memset(out_data, 0, test->max_num_items);
/* Try to write too many items */
g_assert(!gbinder_fmq_write(fmq, in_data, test->max_num_items + 1));
/* Overwrite unsync queue */
if (test->type == GBINDER_FMQ_TYPE_UNSYNC_WRITE) {
g_assert(gbinder_fmq_write(fmq, in_data, test->max_num_items));
g_assert(gbinder_fmq_write(fmq, in_data, 1));
/* Writing too much data to unsync queue causes read pointer to reset
* on next read */
g_assert(!gbinder_fmq_read(fmq, &out_data, 1));
g_assert(gbinder_fmq_available_to_read(fmq) == 0);
}
gbinder_fmq_unref(fmq);
}
/*==========================================================================*
* read/write counters
*==========================================================================*/
static
void
test_read_write_counters(
void)
{
gint max_num_items = 8;
gint write_count = 6;
gint64 in_data[max_num_items];
gint64 out_data[max_num_items];
guint i;
GBinderFmq* fmq = gbinder_fmq_new(sizeof(gint64), max_num_items,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0);
g_assert(fmq);
/* Intiailize input data with random numbers */
for (i = 0; i < max_num_items; ++i) {
in_data[i] = g_random_int();
}
memset(out_data, 0, max_num_items);
/* Write data one value at a time */
for (i = 0; i < write_count; ++i) {
g_assert(gbinder_fmq_write(fmq, &in_data[i], 1));
g_assert(gbinder_fmq_available_to_read(fmq) == i + 1);
g_assert(gbinder_fmq_available_to_write(fmq) ==
max_num_items - i - 1);
}
/* Read data one value at a time */
for (i = 0; i < 2; ++i) {
g_assert(gbinder_fmq_read(fmq, &out_data, 1));
g_assert(out_data[0] == in_data[i]);
g_assert(gbinder_fmq_available_to_read(fmq) ==
write_count - i - 1);
g_assert(gbinder_fmq_available_to_write(fmq) ==
max_num_items - write_count + i + 1);
g_assert(gbinder_fmq_available_to_write_contiguous(fmq) ==
max_num_items - write_count);
}
g_assert(gbinder_fmq_read(fmq, &out_data, 2));
g_assert(gbinder_fmq_available_to_read(fmq) == 2);
g_assert(gbinder_fmq_available_to_write(fmq) == 6);
g_assert(gbinder_fmq_available_to_write_contiguous(fmq) == 2);
g_assert(gbinder_fmq_write(fmq, in_data, 4));
g_assert(gbinder_fmq_available_to_read(fmq) == 6);
g_assert(gbinder_fmq_available_to_read_contiguous(fmq) == 4);
g_assert(gbinder_fmq_read(fmq, &out_data, 6));
g_assert(gbinder_fmq_available_to_read(fmq) == 0);
g_assert(gbinder_fmq_available_to_read_contiguous(fmq) == 0);
g_assert(gbinder_fmq_write(fmq, in_data, 6));
g_assert(gbinder_fmq_available_to_read(fmq) == 6);
g_assert(gbinder_fmq_available_to_read_contiguous(fmq) == 6);
g_assert(gbinder_fmq_available_to_write(fmq) == 2);
g_assert(gbinder_fmq_available_to_write_contiguous(fmq) == 2);
gbinder_fmq_unref(fmq);
}
/*==========================================================================*
* read/write external fd
*==========================================================================*/
static
void
test_read_write_external_fd(
void)
{
gint max_num_items = 8;
gint64 in_data[max_num_items];
gint64 out_data[max_num_items];
gsize item_size = sizeof(gint64);
guint i;
GBinderFmq* fmq;
/* Allocate shared memory */
int shmem_fd = syscall(__NR_memfd_create, "MessageQueue", MFD_CLOEXEC);
g_assert(shmem_fd >= 0);
g_assert(ftruncate(shmem_fd, max_num_items * item_size) >= 0);
fmq = gbinder_fmq_new(item_size, max_num_items,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE, GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG,
shmem_fd, max_num_items * item_size);
g_assert(fmq);
/* Intiailize input data with random numbers */
for (i = 0; i < max_num_items; ++i) {
in_data[i] = g_random_int();
}
memset(out_data, 0, max_num_items);
/* Write data one value at a time */
for (i = 0; i < max_num_items; ++i) {
g_assert(gbinder_fmq_write(fmq, &in_data[i], 1));
g_assert(gbinder_fmq_available_to_read(fmq) == i + 1);
}
/* Read data one value at a time */
for (i = 0; i < max_num_items; ++i) {
g_assert(gbinder_fmq_read(fmq, &out_data, 1));
g_assert(out_data[0] == in_data[i]);
g_assert(gbinder_fmq_available_to_read(fmq) == max_num_items - i - 1);
}
gbinder_fmq_unref(fmq);
}
/*==========================================================================*
* ref/unref
*==========================================================================*/
static
void
test_ref(
void)
{
GBinderFmq* fmq = gbinder_fmq_new(sizeof(gint64), 2,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0);
g_assert(fmq);
g_assert(gbinder_fmq_ref(fmq) == fmq);
gbinder_fmq_unref(fmq);
gbinder_fmq_unref(fmq);
}
/*==========================================================================*
* wait/wake
*==========================================================================*/
static
void
test_wait_wake(
void)
{
gint ms = 100;
guint32 state = 0;
int result = 0;
/* Queue with event flag */
GBinderFmq* fmq = gbinder_fmq_new(sizeof(gint64), 2,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0);
g_assert(fmq);
/* Wait until timeout */
g_assert_cmpint(gbinder_fmq_wait_timeout(fmq, 0x2, &state, ms), ==,
-ETIMEDOUT);
/* Invalid bit mask */
g_assert_cmpint(gbinder_fmq_wait_timeout(fmq, 0x0, &state, ms),==,-EINVAL);
/* Bit already set */
result = gbinder_fmq_wake(fmq, 0x4);
g_assert(result == 0 || result == -ENOSYS);
/* Only run wake/wait tests if FUTEX_WAKE_BITSET is supported */
if (result == 0) {
g_assert_cmpint(gbinder_fmq_wait(fmq, 0x4, &state),==,0);
g_assert_cmpuint(state,==,0x4);
/* Bit already set, wait with more generic bit mask */
state = 0;
g_assert_cmpint(gbinder_fmq_wake(fmq, 0x4),==,0);
g_assert_cmpint(gbinder_fmq_wait(fmq, 0xf, &state),==,0);
g_assert_cmpuint(state,==,0x4);
/* Bit already set, wait with different bit mask */
state = 0;
g_assert_cmpint(gbinder_fmq_wake(fmq, 0x4),==,0);
g_assert_cmpint(gbinder_fmq_wait_timeout(fmq, 0x2, &state, ms), ==,
-ETIMEDOUT);
g_assert_cmpint(gbinder_fmq_try_wait(fmq, 0x2, &state), == ,
-ETIMEDOUT);
}
gbinder_fmq_unref(fmq);
/* Queue without event flag */
fmq = gbinder_fmq_new(sizeof(gint64), 2, GBINDER_FMQ_TYPE_SYNC_READ_WRITE,
0, -1, 0);
g_assert(fmq);
g_assert_cmpint(gbinder_fmq_wait_timeout(fmq, 0x2, &state, ms),==,-ENOSYS);
g_assert_cmpint(gbinder_fmq_wake(fmq, 0x4),==,-ENOSYS);
gbinder_fmq_unref(fmq);
}
/*==========================================================================*
* zero copy
*==========================================================================*/
static
void
test_zero_copy(
void)
{
gint max_num_items = 8;
gint write_count = 2;
gint64 in_data[max_num_items];
gint64 out_data[max_num_items];
gsize item_size = sizeof(gint64);
guint i;
GBinderFmq* fmq = gbinder_fmq_new(item_size, max_num_items,
GBINDER_FMQ_TYPE_SYNC_READ_WRITE, GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG,
-1, 0);
const void *read_ptr;
void *write_ptr;
g_assert(fmq);
/* Intiailize input data with random numbers */
for (i = 0; i < max_num_items; ++i) {
in_data[i] = g_random_int();
}
memset(out_data, 0, max_num_items);
/* external write */
g_assert_nonnull((write_ptr = gbinder_fmq_begin_write(fmq, write_count)));
memcpy(write_ptr, in_data, write_count * item_size);
gbinder_fmq_end_write(fmq, write_count);
g_assert(gbinder_fmq_available_to_read(fmq) == write_count);
g_assert(gbinder_fmq_available_to_write(fmq) ==
(max_num_items - write_count));
/* external read */
g_assert_nonnull((read_ptr = gbinder_fmq_begin_read(fmq, write_count)));
memcpy(out_data, read_ptr, write_count * item_size);
gbinder_fmq_end_read(fmq, write_count);
g_assert(!memcmp(in_data, out_data, write_count * item_size));
gbinder_fmq_unref(fmq);
}
#endif /* GBINDER_FMQ_SUPPORTED */
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/fmq/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
#if GBINDER_FMQ_SUPPORTED
guint i;
int test_fd;
g_test_init(&argc, &argv, NULL);
test_init(&test_opt, argc, argv);
gbinder_log.level = gutil_log_default.level;
for (i = 0; i < G_N_ELEMENTS(test_fmq_tests_null); i++) {
const TestFmqData* test = test_fmq_tests_null + i;
char* path = g_strconcat(TEST_PREFIX, test->name, NULL);
g_test_add_data_func(path, test, test_null);
g_free(path);
}
/* Some test environments don't know how handle this syscall */
test_fd = syscall(__NR_memfd_create, "test", MFD_CLOEXEC);
if (test_fd < 0 && errno == ENOSYS) {
GINFO("Skipping tests that rely on memfd_create");
} else {
close(test_fd);
for (i = 0; i < G_N_ELEMENTS(test_fmq_tests_read_write_guint8); i++) {
const TestFmqData* test = test_fmq_tests_read_write_guint8 + i;
char* path = g_strconcat(TEST_("guint8/"), test->name, NULL);
g_test_add_data_func(path, test, test_read_write_guint8);
g_free(path);
}
for (i = 0; i < G_N_ELEMENTS(test_fmq_tests_read_write_gint64); i++) {
const TestFmqData* test = test_fmq_tests_read_write_gint64 + i;
char* path = g_strconcat(TEST_("gint64/"), test->name, NULL);
g_test_add_data_func(path, test, test_read_write_gint64);
g_free(path);
}
g_test_add_func(TEST_("read_write_counters"), test_read_write_counters);
g_test_add_func(TEST_("read_write_external_fd"),
test_read_write_external_fd);
g_test_add_func(TEST_("ref"), test_ref);
g_test_add_func(TEST_("wait_wake"), test_wait_wake);
g_test_add_func(TEST_("zero_copy"), test_zero_copy);
}
#else /* GBINDER_FMQ_SUPPORTED */
g_test_init(&argc, &argv, NULL);
#endif
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-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -70,6 +70,24 @@ test_quit_when_destroyed(
test_quit_later((GMainLoop*)loop);
}
static
GBinderLocalRequest*
test_local_request_new(
GBinderIpc* ipc)
{
return gbinder_local_request_new(gbinder_driver_io(ipc->driver),
gbinder_driver_protocol(ipc->driver), NULL);
}
static
GBinderLocalReply*
test_local_reply_new(
GBinderIpc* ipc)
{
return gbinder_local_reply_new(gbinder_driver_io(ipc->driver),
gbinder_driver_protocol(ipc->driver));
}
/*==========================================================================*
* null
*==========================================================================*/
@@ -79,26 +97,25 @@ void
test_null(
void)
{
GBinderIpc* null = NULL;
int status = INT_MAX;
g_assert(!gbinder_ipc_ref(null));
gbinder_ipc_unref(null);
g_assert(!gbinder_ipc_sync_main.sync_reply(null, 0, 0, NULL, NULL));
g_assert(!gbinder_ipc_sync_main.sync_reply(null, 0, 0, NULL, &status));
g_assert(!gbinder_ipc_ref(NULL));
gbinder_ipc_unref(NULL);
g_assert(!gbinder_ipc_sync_main.sync_reply(NULL, 0, 0, NULL, NULL));
g_assert(!gbinder_ipc_sync_main.sync_reply(NULL, 0, 0, NULL, &status));
g_assert_cmpint(status, == ,-EINVAL);
g_assert(!gbinder_ipc_sync_worker.sync_reply(null, 0, 0, NULL, NULL));
g_assert(!gbinder_ipc_sync_worker.sync_reply(null, 0, 0, NULL, &status));
g_assert(!gbinder_ipc_sync_worker.sync_reply(NULL, 0, 0, NULL, NULL));
g_assert(!gbinder_ipc_sync_worker.sync_reply(NULL, 0, 0, NULL, &status));
g_assert_cmpint(status, == ,-EINVAL);
g_assert_cmpint(gbinder_ipc_sync_main.sync_oneway(null, 0, 0, NULL), == ,
g_assert_cmpint(gbinder_ipc_sync_main.sync_oneway(NULL, 0, 0, NULL), == ,
-EINVAL);
g_assert_cmpint(gbinder_ipc_sync_worker.sync_oneway(null, 0, 0, NULL), == ,
g_assert_cmpint(gbinder_ipc_sync_worker.sync_oneway(NULL, 0, 0, NULL), == ,
-EINVAL);
g_assert(!gbinder_ipc_transact(null, 0, 0, 0, NULL, NULL, NULL, NULL));
g_assert(!gbinder_ipc_transact_custom(null, NULL, NULL, NULL, NULL));
g_assert(!gbinder_ipc_object_registry(null));
gbinder_ipc_looper_check(null);
gbinder_ipc_cancel(null, 0);
g_assert(!gbinder_ipc_transact(NULL, 0, 0, 0, NULL, NULL, NULL, NULL));
g_assert(!gbinder_ipc_transact_custom(NULL, NULL, NULL, NULL, NULL));
g_assert(!gbinder_ipc_object_registry(NULL));
gbinder_ipc_looper_check(NULL);
gbinder_ipc_cancel(NULL, 0);
g_assert(!gbinder_object_registry_ref(NULL));
gbinder_object_registry_unref(NULL);
@@ -120,13 +137,23 @@ test_basic_find_none(
return FALSE;
}
static
gboolean
test_basic_find(
GBinderLocalObject* obj,
void* user_data)
{
return obj == user_data;
}
static
void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderLocalObject* obj;
g_assert(ipc);
g_assert(ipc2);
@@ -136,18 +163,45 @@ test_basic(
g_assert(!gbinder_ipc_find_local_object(NULL, test_basic_find_none, NULL));
g_assert(!gbinder_ipc_find_local_object(ipc, test_basic_find_none, NULL));
obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
g_assert(obj);
g_assert(!gbinder_ipc_find_local_object(ipc, test_basic_find_none, NULL));
g_assert(gbinder_ipc_find_local_object(ipc, test_basic_find, obj) == obj);
gbinder_local_object_unref(obj); /* Above call added a reference */
gbinder_local_object_unref(obj);
/* Second gbinder_ipc_new returns the same (default) object */
g_assert(gbinder_ipc_new(NULL) == ipc);
g_assert(gbinder_ipc_new("") == ipc);
g_assert(gbinder_ipc_new(NULL, NULL) == ipc);
g_assert(gbinder_ipc_new("", NULL) == ipc);
gbinder_ipc_unref(ipc);
gbinder_ipc_unref(ipc);
gbinder_ipc_unref(ipc);
/* Invalid path */
g_assert(!gbinder_ipc_new("invalid path"));
g_assert(!gbinder_ipc_new("invalid path", NULL));
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* protocol
*==========================================================================*/
static
void
test_protocol(
void)
{
/* GBinderIpc objects are identified by device + protocol combination */
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, "aidl");
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, "hidl");
g_assert(ipc);
g_assert(ipc2);
g_assert(ipc != ipc2);
gbinder_ipc_unref(ipc);
gbinder_ipc_unref(ipc2);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
@@ -173,14 +227,13 @@ void
test_async_oneway(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
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);
test_binder_br_transaction_complete(fd, TX_THREAD);
id = gbinder_ipc_transact(ipc, 0, 1, GBINDER_TX_FLAG_ONEWAY,
req, test_async_oneway_done, NULL, loop);
g_assert(id);
@@ -200,16 +253,14 @@ void
test_sync_oneway(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
test_binder_br_transaction_complete(fd);
test_binder_br_transaction_complete(fd, THIS_THREAD);
g_assert_cmpint(gbinder_ipc_sync_main.sync_oneway(ipc, 0, 1, req), == ,0);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
@@ -222,13 +273,12 @@ void
test_sync_reply_ok_status(
int* status)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
GBinderLocalReply* reply = test_local_reply_new(ipc);
GBinderRemoteReply* tx_reply;
GBinderOutputData* data;
const int fd = gbinder_driver_fd(ipc->driver);
const guint32 handle = 0;
const guint32 code = 1;
const char* result_in = "foo";
@@ -238,10 +288,10 @@ test_sync_reply_ok_status(
data = gbinder_local_reply_data(reply);
g_assert(data);
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);
test_binder_br_noop(fd, THIS_THREAD);
test_binder_br_transaction_complete(fd, THIS_THREAD);
test_binder_br_noop(fd, THIS_THREAD);
test_binder_br_reply(fd, THIS_THREAD, handle, code, data->bytes);
tx_reply = gbinder_ipc_sync_main.sync_reply(ipc, handle, code, req, status);
g_assert(tx_reply);
@@ -254,7 +304,6 @@ test_sync_reply_ok_status(
gbinder_local_request_unref(req);
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
@@ -279,36 +328,36 @@ void
test_sync_reply_error(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
const guint32 handle = 0;
const guint32 code = 1;
const gint expected_status = (-EINVAL);
const gint unexpected_status = GBINDER_STATUS_FAILED;
int status = INT_MAX;
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply_status(fd, expected_status);
test_binder_ignore_dead_object(fd);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_transaction_complete(fd, TX_THREAD);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_reply_status(fd, TX_THREAD, expected_status);
g_assert(!gbinder_ipc_sync_main.sync_reply(ipc,handle,code,req,&status));
g_assert_cmpint(status, == ,expected_status);
/* GBINDER_STATUS_FAILED gets replaced with -EFAULT */
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply_status(fd, unexpected_status);
test_binder_ignore_dead_object(fd);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_transaction_complete(fd, TX_THREAD);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_reply_status(fd, TX_THREAD, unexpected_status);
g_assert(!gbinder_ipc_sync_main.sync_reply(ipc,handle,code,req,&status));
g_assert_cmpint(status, == ,-EFAULT);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
@@ -348,14 +397,13 @@ void
test_transact_ok(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
GBinderLocalReply* reply = test_local_reply_new(ipc);
GBinderOutputData* data;
const guint32 handle = 0;
const guint32 code = 1;
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
@@ -363,10 +411,10 @@ test_transact_ok(
data = gbinder_local_reply_data(reply);
g_assert(data);
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);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_transaction_complete(fd, TX_THREAD);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_reply(fd, TX_THREAD, handle, code, data->bytes);
id = gbinder_ipc_transact(ipc, handle, code, 0, req,
test_transact_ok_done, test_transact_ok_destroy, loop);
@@ -379,7 +427,6 @@ test_transact_ok(
gbinder_local_request_unref(req);
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -407,15 +454,14 @@ void
test_transact_dead(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
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_noop(fd);
test_binder_br_dead_reply(fd);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_dead_reply(fd, TX_THREAD);
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_dead_done,
NULL, loop);
@@ -427,7 +473,6 @@ test_transact_dead(
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -455,15 +500,14 @@ void
test_transact_failed(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
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_noop(fd);
test_binder_br_failed_reply(fd);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_failed_reply(fd, TX_THREAD);
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_failed_done,
NULL, loop);
@@ -475,7 +519,6 @@ test_transact_failed(
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -505,15 +548,14 @@ void
test_transact_status(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
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_noop(fd);
test_binder_br_reply_status(fd, EXPECTED_STATUS);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_reply_status(fd, TX_THREAD, EXPECTED_STATUS);
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_status_done,
NULL, loop);
@@ -525,7 +567,6 @@ test_transact_status(
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -548,7 +589,7 @@ void
test_transact_custom(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id = gbinder_ipc_transact_custom(ipc, NULL,
test_transact_custom_done, NULL, loop);
@@ -580,7 +621,7 @@ void
test_transact_custom2(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id = gbinder_ipc_transact_custom(ipc, NULL, NULL,
test_transact_custom_destroy, loop);
@@ -613,7 +654,7 @@ void
test_transact_custom3(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
/* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_custom3_exec,
@@ -623,7 +664,6 @@ test_transact_custom3(
test_run(&test_opt, loop);
/* Reference to GBinderIpc is released by test_transact_custom3_exec */
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -663,7 +703,7 @@ void
test_transact_cancel(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel_exec,
test_transact_cancel_done, test_transact_cancel_destroy, loop);
@@ -673,7 +713,6 @@ test_transact_cancel(
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -709,7 +748,7 @@ void
test_transact_cancel2(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
/* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel2_exec,
@@ -719,7 +758,6 @@ test_transact_cancel2(
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -759,8 +797,7 @@ void
test_transact_2way_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
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);
@@ -771,9 +808,9 @@ test_transact_2way_run(
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_2way_incoming_proc, &incoming_call);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderLocalRequest* incoming_req = gbinder_local_request_new(io, NULL);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderLocalRequest* req = test_local_request_new(ipc);
GBinderLocalRequest* incoming_req = test_local_request_new(ipc);
GBinderLocalReply* reply = test_local_reply_new(ipc);
GBinderWriter writer;
/* Prepare reply */
@@ -784,12 +821,13 @@ test_transact_2way_run(
prot->write_rpc_header(&writer, "test");
gbinder_writer_append_string8(&writer, "message");
test_binder_br_transaction(fd, obj, 2,
test_binder_ignore_dead_object(fd);
test_binder_br_transaction(fd, TX_THREAD, obj, 2,
gbinder_local_request_data(req)->bytes);
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_noop(fd);
test_binder_br_reply(fd, handle, code,
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_transaction_complete(fd, TX_THREAD);
test_binder_br_noop(fd, TX_THREAD);
test_binder_br_reply(fd, TX_THREAD, handle, code,
gbinder_local_reply_data(reply)->bytes);
/* NB. Reusing test_transact_ok_done and test_transact_ok_destroy */
@@ -808,7 +846,6 @@ test_transact_2way_run(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -844,14 +881,10 @@ void
test_transact_unhandled_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderDriver* driver = ipc->driver;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalRequest* req = gbinder_driver_local_request_new_ping(driver);
int fd = gbinder_driver_fd(driver);
test_binder_set_passthrough(fd, TRUE);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
g_assert(gbinder_ipc_transact(ipc, 1 /* Non-existent object */,
gbinder_driver_protocol(driver)->ping_tx, 0, req,
@@ -860,7 +893,6 @@ test_transact_unhandled_run(
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -905,8 +937,7 @@ void
test_transact_incoming_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
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);
@@ -914,8 +945,8 @@ test_transact_incoming_run(
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_incoming_proc, loop);
GBinderLocalRequest* ping = gbinder_local_request_new(io, NULL);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderLocalRequest* ping = test_local_request_new(ipc);
GBinderLocalRequest* req = test_local_request_new(ipc);
GBinderWriter writer;
gbinder_local_request_init_writer(ping, &writer);
@@ -925,13 +956,12 @@ test_transact_incoming_run(
prot->write_rpc_header(&writer, "test");
gbinder_writer_append_string8(&writer, "message");
test_binder_br_transaction(fd, obj, prot->ping_tx,
test_binder_br_transaction(fd, LOOPER_THREAD, obj, prot->ping_tx,
gbinder_local_request_data(ping)->bytes);
test_binder_br_transaction_complete(fd); /* For reply */
test_binder_br_transaction(fd, obj, 1,
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
test_binder_br_transaction(fd, LOOPER_THREAD, obj, 1,
gbinder_local_request_data(req)->bytes);
test_binder_br_transaction_complete(fd); /* For reply */
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */
@@ -943,7 +973,6 @@ test_transact_incoming_run(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -986,8 +1015,7 @@ void
test_transact_status_reply_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
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);
@@ -995,7 +1023,7 @@ test_transact_status_reply_run(
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_status_reply_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
GBinderOutputData* data;
GBinderWriter writer;
@@ -1004,9 +1032,8 @@ test_transact_status_reply_run(
gbinder_writer_append_string8(&writer, "message");
data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes);
test_binder_br_transaction_complete(fd); /* For reply */
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE_ONE);
test_binder_br_transaction(fd, LOOPER_THREAD, obj, 1, data->bytes);
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */
@@ -1017,7 +1044,6 @@ test_transact_status_reply_run(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -1103,8 +1129,7 @@ void
test_transact_async_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
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);
@@ -1112,7 +1137,7 @@ test_transact_async_run(
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);
GBinderLocalRequest* req = test_local_request_new(ipc);
GBinderOutputData* data;
GBinderWriter writer;
@@ -1121,9 +1146,8 @@ test_transact_async_run(
gbinder_writer_append_string8(&writer, "message");
data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes);
test_binder_br_transaction_complete(fd); /* For reply */
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE_ONE);
test_binder_br_transaction(fd, LOOPER_THREAD, obj, 1, data->bytes);
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */
@@ -1134,7 +1158,6 @@ test_transact_async_run(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -1186,8 +1209,7 @@ void
test_transact_async_sync_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
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);
@@ -1195,7 +1217,7 @@ test_transact_async_sync_run(
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);
GBinderLocalRequest* req = test_local_request_new(ipc);
GBinderOutputData* data;
GBinderWriter writer;
@@ -1204,9 +1226,8 @@ test_transact_async_sync_run(
gbinder_writer_append_string8(&writer, "message");
data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes);
test_binder_br_transaction_complete(fd); /* For reply */
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE_ONE);
test_binder_br_transaction(fd, LOOPER_THREAD, obj, 1, data->bytes);
test_binder_br_transaction_complete(fd, LOOPER_THREAD); /* For reply */
test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */
@@ -1217,7 +1238,6 @@ test_transact_async_sync_run(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -1250,7 +1270,7 @@ void
test_drop_remote_refs_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -1258,8 +1278,7 @@ test_drop_remote_refs_run(
gulong id = gbinder_local_object_add_strong_refs_changed_handler(obj,
test_drop_remote_refs_cb, loop);
test_binder_br_acquire(fd, obj);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_br_acquire(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 1);
@@ -1301,14 +1320,13 @@ void
test_cancel_on_exit(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalRequest* req = test_local_request_new(ipc);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
/* This transaction will be cancelled by gbinder_ipc_exit */
test_binder_br_transaction_complete(fd);
test_binder_br_transaction_complete(fd, TX_THREAD);
gbinder_ipc_transact(ipc, 0, 1, GBINDER_TX_FLAG_ONEWAY,
req, test_cancel_on_exit_not_reached, NULL, NULL);
@@ -1334,6 +1352,7 @@ int main(int argc, char* argv[])
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("protocol"), test_protocol);
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);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -33,6 +33,7 @@
#include "test_binder.h"
#include "gbinder_buffer_p.h"
#include "gbinder_config.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_local_object_p.h"
@@ -152,7 +153,7 @@ test_basic(
{
const char* const ifaces_foo[] = { "foo", NULL };
const char* const ifaces_bar[] = { "bar", NULL };
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderLocalObject* foo;
GBinderLocalObject* bar;
@@ -187,6 +188,7 @@ test_basic(
g_assert(gbinder_local_object_ref(bar) == bar);
gbinder_local_object_drop(bar);
gbinder_local_object_unref(bar);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -201,7 +203,7 @@ test_ping(
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -232,6 +234,7 @@ test_ping(
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -247,7 +250,7 @@ test_interface(
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "x", NULL };
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -281,6 +284,7 @@ test_interface(
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -296,7 +300,7 @@ test_hidl_ping(
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -331,6 +335,7 @@ test_hidl_ping(
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -346,7 +351,7 @@ test_get_descriptor(
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -384,6 +389,7 @@ test_get_descriptor(
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -402,7 +408,7 @@ test_descriptor_chain(
const char* dev = GBINDER_DEFAULT_HWBINDER;
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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);
@@ -435,6 +441,7 @@ test_descriptor_chain(
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -476,7 +483,7 @@ test_custom_iface(
int count = 0, status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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,
@@ -545,6 +552,7 @@ test_custom_iface(
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -583,7 +591,7 @@ test_reply_status(
int count = 0, status = 0;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev);
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,
@@ -602,6 +610,7 @@ test_reply_status(
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_remote_request_unref(req);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -624,7 +633,7 @@ void
test_increfs_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -633,16 +642,15 @@ test_increfs_run(
test_increfs_cb, loop);
/* 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, TEST_LOOPER_ENABLE);
test_binder_br_increfs(fd, ANY_THREAD, ipc);
test_binder_br_increfs(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->weak_refs == 1);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -675,7 +683,7 @@ void
test_decrefs_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -684,17 +692,16 @@ test_decrefs_run(
test_decrefs_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_decrefs(fd, ipc);
test_binder_br_increfs(fd, obj);
test_binder_br_decrefs(fd, obj);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_br_decrefs(fd, ANY_THREAD, ipc);
test_binder_br_increfs(fd, ANY_THREAD, obj);
test_binder_br_decrefs(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->weak_refs == 0);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -726,7 +733,7 @@ void
test_acquire_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
@@ -735,16 +742,15 @@ test_acquire_run(
test_acquire_cb, loop);
/* 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, TEST_LOOPER_ENABLE);
test_binder_br_acquire(fd, ANY_THREAD, ipc);
test_binder_br_acquire(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 1);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -777,7 +783,7 @@ void
test_release_run(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, 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);
@@ -785,17 +791,16 @@ test_release_run(
test_release_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_release(fd, ipc);
test_binder_br_acquire(fd, obj);
test_binder_br_release(fd, obj);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_br_release(fd, ANY_THREAD, ipc);
test_binder_br_acquire(fd, ANY_THREAD, obj);
test_binder_br_release(fd, ANY_THREAD, obj);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 0);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -815,6 +820,18 @@ test_release(
int main(int argc, char* argv[])
{
const char* default_config_dir;
const char* default_config_file;
char* config_dir = g_dir_make_tmp("gbinder-test-local-object-XXXXXX", NULL);
char* config_file = g_build_filename(config_dir, "test.conf", NULL);
int result;
/* Point gbinder_config_file to a non-existent file */
default_config_dir = gbinder_config_dir;
default_config_file = gbinder_config_file;
gbinder_config_dir = config_dir;
gbinder_config_file = config_file;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
g_type_init();
G_GNUC_END_IGNORE_DEPRECATIONS;
@@ -833,7 +850,14 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_PREFIX "acquire", test_acquire);
g_test_add_func(TEST_PREFIX "release", test_release);
test_init(&test_opt, argc, argv);
return g_test_run();
result = g_test_run();
gbinder_config_dir = default_config_dir;
gbinder_config_file = default_config_file;
remove(config_dir);
g_free(config_dir);
g_free(config_file);
return result;
}
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -36,6 +36,7 @@
#include "gbinder_local_object.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_output_data.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_buffer_p.h"
#include "gbinder_driver.h"
#include "gbinder_writer.h"
@@ -46,11 +47,6 @@
static TestOpt test_opt;
#define BUFFER_OBJECT_SIZE_32 (24)
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
#define BINDER_OBJECT_SIZE_32 (16)
#define BINDER_OBJECT_SIZE_64 (GBINDER_MAX_BINDER_OBJECT_SIZE)
static
void
test_int_inc(
@@ -70,6 +66,14 @@ test_buffer_from_bytes(
return gbinder_buffer_new(driver, bytes->data, bytes->len, NULL);
}
static
GBinderLocalReply*
test_local_reply_new()
{
return gbinder_local_reply_new(&gbinder_io_32,
gbinder_rpc_protocol_for_device(NULL));
}
/*==========================================================================*
* null
*==========================================================================*/
@@ -82,7 +86,10 @@ test_null(
GBinderWriter writer;
int count = 0;
g_assert(!gbinder_local_reply_new(NULL));
g_assert(!gbinder_local_reply_new(NULL, NULL));
g_assert(!gbinder_local_reply_new(&gbinder_io_32, NULL));
g_assert(!gbinder_local_reply_new(NULL,
gbinder_rpc_protocol_for_device(NULL)));
g_assert(!gbinder_local_reply_ref(NULL));
gbinder_local_reply_unref(NULL);
gbinder_local_reply_init_writer(NULL, NULL);
@@ -106,6 +113,7 @@ test_null(
g_assert(!gbinder_local_reply_append_hidl_string_vec(NULL, NULL, 0));
g_assert(!gbinder_local_reply_append_local_object(NULL, NULL));
g_assert(!gbinder_local_reply_append_remote_object(NULL, NULL));
g_assert(!gbinder_local_reply_append_fd(NULL, 0));
}
/*==========================================================================*
@@ -117,7 +125,7 @@ void
test_cleanup(
void)
{
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
int count = 0;
gbinder_local_reply_cleanup(reply, NULL, &count);
@@ -140,7 +148,7 @@ test_bool(
{
static const guint8 output_true[] = { 0x01, 0x00, 0x00, 0x00 };
static const guint8 output_false[] = { 0x00, 0x00, 0x00, 0x00 };
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
gbinder_local_reply_append_bool(reply, FALSE);
@@ -151,7 +159,7 @@ test_bool(
g_assert(!memcmp(data->bytes->data, output_false, data->bytes->len));
gbinder_local_reply_unref(reply);
reply = gbinder_local_reply_new(&gbinder_io_32);
reply = test_local_reply_new();
gbinder_local_reply_append_bool(reply, TRUE);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
@@ -160,7 +168,7 @@ test_bool(
g_assert(!memcmp(data->bytes->data, output_true, data->bytes->len));
gbinder_local_reply_unref(reply);
reply = gbinder_local_reply_new(&gbinder_io_32);
reply = test_local_reply_new();
gbinder_local_reply_append_bool(reply, 42);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
@@ -170,6 +178,31 @@ test_bool(
gbinder_local_reply_unref(reply);
}
/*==========================================================================*
* fd
*==========================================================================*/
static
void
test_fd(
void)
{
const gint32 fd = 1;
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
GUtilIntArray* offsets;
g_assert(gbinder_local_reply_append_fd(reply, fd));
data = gbinder_local_reply_data(reply);
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_reply_unref(reply);
}
/*==========================================================================*
* int32
*==========================================================================*/
@@ -180,7 +213,7 @@ test_int32(
void)
{
const guint32 value = 1234567;
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
GBinderWriter writer;
@@ -195,7 +228,7 @@ test_int32(
gbinder_local_reply_unref(reply);
/* Same with writer */
reply = gbinder_local_reply_new(&gbinder_io_32);
reply = test_local_reply_new();
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, value);
data = gbinder_local_reply_data(reply);
@@ -216,7 +249,7 @@ test_int64(
void)
{
const guint64 value = 123456789;
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
gbinder_local_reply_append_int64(reply, value);
@@ -238,7 +271,7 @@ test_float(
void)
{
const gfloat value = 123456789;
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
gbinder_local_reply_append_float(reply, value);
@@ -260,7 +293,7 @@ test_double(
void)
{
const gdouble value = 123456789;
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
gbinder_local_reply_append_double(reply, value);
@@ -284,7 +317,7 @@ test_string8(
/* The size of the string gets aligned at 4-byte boundary */
static const char input[] = "test";
static const guint8 output[] = { 't', 'e', 's', 't', 0, 0, 0, 0 };
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
gbinder_local_reply_append_string8(reply, input);
@@ -296,7 +329,7 @@ test_string8(
gbinder_local_reply_unref(reply);
/* NULL string doesn't get encoded at all (should it be?) */
reply = gbinder_local_reply_new(&gbinder_io_32);
reply = test_local_reply_new();
gbinder_local_reply_append_string8(reply, NULL);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
@@ -320,7 +353,7 @@ test_string16(
TEST_INT16_BYTES('x'), 0x00, 0x00
};
const gint32 null_output = -1;
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
gbinder_local_reply_append_string16(reply, input);
@@ -332,7 +365,7 @@ test_string16(
gbinder_local_reply_unref(reply);
/* NULL string gets encoded as -1 */
reply = gbinder_local_reply_new(&gbinder_io_32);
reply = test_local_reply_new();
gbinder_local_reply_append_string16(reply, NULL);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
@@ -351,7 +384,7 @@ void
test_hidl_string(
void)
{
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
GUtilIntArray* offsets;
@@ -374,7 +407,7 @@ void
test_hidl_string_vec(
void)
{
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
GUtilIntArray* offsets;
@@ -400,7 +433,7 @@ test_local_object(
GBinderLocalReply* reply;
GBinderOutputData* data;
GUtilIntArray* offsets;
GBinderIpc* ipc = gbinder_ipc_new(NULL);
GBinderIpc* ipc = gbinder_ipc_new(NULL, NULL);
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
@@ -410,22 +443,22 @@ test_local_object(
data = gbinder_local_reply_data(reply);
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_64);
g_assert_cmpuint(offsets->count, == ,1);
g_assert_cmpuint(offsets->data[0], == ,0);
g_assert_cmpuint(gbinder_output_data_buffers_size(data), == ,0);
g_assert_cmpuint(data->bytes->len, == ,BINDER_OBJECT_SIZE_64);
gbinder_local_reply_unref(reply);
/* Append NULL object (with 32-bit I/O module) */
reply = gbinder_local_reply_new(&gbinder_io_32);
reply = test_local_reply_new();
gbinder_local_reply_append_local_object(reply, NULL);
data = gbinder_local_reply_data(reply);
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);
g_assert_cmpuint(offsets->count, == ,1);
g_assert_cmpuint(offsets->data[0], == ,0);
g_assert_cmpuint(gbinder_output_data_buffers_size(data), == ,0);
g_assert_cmpuint(data->bytes->len, == ,BINDER_OBJECT_SIZE_32);
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
}
@@ -439,7 +472,7 @@ void
test_remote_object(
void)
{
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderLocalReply* reply = test_local_reply_new();
GBinderOutputData* data;
GUtilIntArray* offsets;
@@ -468,7 +501,8 @@ test_remote_reply(
static const guint8 output[] = { 't', 'e', 's', 't', 0, 0, 0, 0 };
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
const GBinderIo* io = gbinder_driver_io(driver);
GBinderLocalReply* req = gbinder_local_reply_new(io);
GBinderLocalReply* req = gbinder_local_reply_new(io,
gbinder_rpc_protocol_for_device(NULL));
GBinderLocalReply* req2;
GBinderOutputData* data2;
const GByteArray* bytes;
@@ -480,7 +514,7 @@ test_remote_reply(
/* Copy flat structures (no binder objects) */
buffer = test_buffer_from_bytes(driver, bytes);
req2 = gbinder_local_reply_new(io);
req2 = gbinder_local_reply_new(io, gbinder_rpc_protocol_for_device(NULL));
g_assert(gbinder_local_reply_set_contents(req2, buffer, NULL) == req2);
gbinder_buffer_free(buffer);
@@ -511,6 +545,7 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_PREFIX "null", test_null);
g_test_add_func(TEST_PREFIX "cleanup", test_cleanup);
g_test_add_func(TEST_PREFIX "bool", test_bool);
g_test_add_func(TEST_PREFIX "fd", test_fd);
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);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -35,6 +35,7 @@
#include "gbinder_local_request_p.h"
#include "gbinder_output_data.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_buffer_p.h"
#include "gbinder_driver.h"
#include "gbinder_writer.h"
@@ -44,11 +45,6 @@
static TestOpt test_opt;
#define BUFFER_OBJECT_SIZE_32 (24)
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
#define BINDER_OBJECT_SIZE_32 (16)
#define BINDER_OBJECT_SIZE_64 (GBINDER_MAX_BINDER_OBJECT_SIZE)
static
void
test_int_inc(
@@ -80,6 +76,14 @@ test_buffer_from_bytes_and_objects(
return gbinder_buffer_new(driver, bytes->data, bytes->len, objects);
}
static
GBinderLocalRequest*
test_local_request_new()
{
return gbinder_local_request_new(&gbinder_io_32,
gbinder_rpc_protocol_for_device(NULL), NULL);
}
/*==========================================================================*
* null
*==========================================================================*/
@@ -92,7 +96,10 @@ test_null(
GBinderWriter writer;
int count = 0;
g_assert(!gbinder_local_request_new(NULL, NULL));
g_assert(!gbinder_local_request_new(NULL, NULL, NULL));
g_assert(!gbinder_local_request_new(&gbinder_io_32, NULL, NULL));
g_assert(!gbinder_local_request_new(NULL,
gbinder_rpc_protocol_for_device(NULL), NULL));
g_assert(!gbinder_local_request_ref(NULL));
g_assert(!gbinder_local_request_new_from_data(NULL, NULL));
gbinder_local_request_unref(NULL);
@@ -125,7 +132,7 @@ void
test_cleanup(
void)
{
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
int count = 0;
gbinder_local_request_cleanup(req, NULL, &count);
@@ -149,7 +156,7 @@ test_init_data(
const guint8 init_data[] = { 0x01, 0x02, 0x03, 0x04 };
GBytes* init_bytes = g_bytes_new_static(init_data, sizeof(init_data));
GBinderLocalRequest* req = gbinder_local_request_new
(&gbinder_io_32, init_bytes);
(&gbinder_io_32, gbinder_rpc_protocol_for_device(NULL), init_bytes);
GBinderOutputData* data;
data = gbinder_local_request_data(req);
@@ -161,7 +168,7 @@ test_init_data(
gbinder_local_request_unref(req);
gbinder_local_request_unref(req);
req = gbinder_local_request_new(&gbinder_io_32, NULL);
req = test_local_request_new();
data = gbinder_local_request_data(req);
g_assert(data->bytes);
g_assert(!data->bytes->len);
@@ -181,7 +188,7 @@ test_bool(
{
static const guint8 output_true[] = { 0x01, 0x00, 0x00, 0x00 };
static const guint8 output_false[] = { 0x00, 0x00, 0x00, 0x00 };
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
gbinder_local_request_append_bool(req, FALSE);
@@ -192,7 +199,7 @@ test_bool(
g_assert(!memcmp(data->bytes->data, output_false, data->bytes->len));
gbinder_local_request_unref(req);
req = gbinder_local_request_new(&gbinder_io_32, NULL);
req = test_local_request_new();
gbinder_local_request_append_bool(req, TRUE);
data = gbinder_local_request_data(req);
g_assert(!gbinder_output_data_offsets(data));
@@ -201,7 +208,7 @@ test_bool(
g_assert(!memcmp(data->bytes->data, output_true, data->bytes->len));
gbinder_local_request_unref(req);
req = gbinder_local_request_new(&gbinder_io_32, NULL);
req = test_local_request_new();
gbinder_local_request_append_bool(req, 42);
data = gbinder_local_request_data(req);
g_assert(!gbinder_output_data_offsets(data));
@@ -221,7 +228,7 @@ test_int32(
void)
{
const guint32 value = 1234567;
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
gbinder_local_request_append_int32(req, value);
@@ -243,7 +250,7 @@ test_int64(
void)
{
const guint64 value = 123456789;
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
gbinder_local_request_append_int64(req, value);
@@ -265,7 +272,7 @@ test_float(
void)
{
const gfloat value = 123456789;
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
gbinder_local_request_append_float(req, value);
@@ -287,7 +294,7 @@ test_double(
void)
{
const gdouble value = 123456789;
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
gbinder_local_request_append_double(req, value);
@@ -311,7 +318,7 @@ test_string8(
/* The size of the string gets aligned at 4-byte boundary */
static const char input[] = "test";
static const guint8 output[] = { 't', 'e', 's', 't', 0, 0, 0, 0 };
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
gbinder_local_request_append_string8(req, input);
@@ -323,7 +330,7 @@ test_string8(
gbinder_local_request_unref(req);
/* NULL string doesn't get encoded at all (should it be?) */
req = gbinder_local_request_new(&gbinder_io_32, NULL);
req = test_local_request_new();
gbinder_local_request_append_string8(req, NULL);
data = gbinder_local_request_data(req);
g_assert(!gbinder_output_data_offsets(data));
@@ -347,7 +354,7 @@ test_string16(
TEST_INT16_BYTES('x'), 0x00, 0x00
};
const gint32 null_output = -1;
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
gbinder_local_request_append_string16(req, input);
@@ -359,7 +366,7 @@ test_string16(
gbinder_local_request_unref(req);
/* NULL string gets encoded as -1 */
req = gbinder_local_request_new(&gbinder_io_32, NULL);
req = test_local_request_new();
gbinder_local_request_append_string16(req, NULL);
data = gbinder_local_request_data(req);
g_assert(!gbinder_output_data_offsets(data));
@@ -378,7 +385,7 @@ void
test_hidl_string(
void)
{
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
GUtilIntArray* offsets;
@@ -401,7 +408,7 @@ void
test_hidl_string_vec(
void)
{
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
GUtilIntArray* offsets;
@@ -424,7 +431,7 @@ void
test_local_object(
void)
{
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
GUtilIntArray* offsets;
@@ -448,7 +455,7 @@ void
test_remote_object(
void)
{
GBinderLocalRequest* req = gbinder_local_request_new(&gbinder_io_32, NULL);
GBinderLocalRequest* req = test_local_request_new();
GBinderOutputData* data;
GUtilIntArray* offsets;
@@ -477,7 +484,8 @@ test_remote_request(
static const guint8 output[] = { 't', 'e', 's', 't', 0, 0, 0, 0 };
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
const GBinderIo* io = gbinder_driver_io(driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
const GBinderRpcProtocol* protocol = gbinder_driver_protocol(driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, protocol, NULL);
GBinderLocalRequest* req2;
GBinderOutputData* data2;
const GByteArray* bytes;
@@ -549,7 +557,8 @@ test_remote_request_obj(
{
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
const GBinderIo* io = gbinder_driver_io(driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
const GBinderRpcProtocol* protocol = gbinder_driver_protocol(driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, protocol, NULL);
GBinderLocalRequest* req2;
GBinderOutputData* data;
GUtilIntArray* offsets;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -49,6 +49,7 @@ static const char TMP_DIR_TEMPLATE[] = "gbinder-test-protocol-XXXXXX";
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
#define UNSET_WORK_SOURCE (-1)
#define BINDER_SYS_HEADER GBINDER_FOURCC('S', 'Y', 'S', 'T')
typedef struct test_data {
const char* name;
@@ -80,6 +81,15 @@ static const guint8 test_header_aidl2 [] = {
TEST_INT16_BYTES('o'), 0x00, 0x00
};
static const guint8 test_header_aidl3 [] = {
TEST_INT32_BYTES(BINDER_RPC_FLAGS),
TEST_INT32_BYTES(UNSET_WORK_SOURCE),
TEST_INT32_BYTES(BINDER_SYS_HEADER),
TEST_INT32_BYTES(3),
TEST_INT16_BYTES('f'), TEST_INT16_BYTES('o'),
TEST_INT16_BYTES('o'), 0x00, 0x00
};
static const guint8 test_header_hidl [] = {
'f', 'o', 'o', 0x00
};
@@ -97,6 +107,14 @@ static const TestHeaderData test_header_tests[] = {
test_header_aidl2, 5 }, /* Short packet */
{ "aidl2/short/3", "adl2", GBINDER_DEFAULT_BINDER, NULL,
test_header_aidl2, 9 }, /* Short packet */
{ "aidl3/ok", "aidl3", GBINDER_DEFAULT_BINDER, "foo",
TEST_ARRAY_AND_SIZE(test_header_aidl3) },
{ "aidl3/short/1", "aidl3", GBINDER_DEFAULT_BINDER, NULL,
test_header_aidl3, 1 }, /* Short packet */
{ "aidl3/short/2", "aidl3", GBINDER_DEFAULT_BINDER, NULL,
test_header_aidl3, 5 }, /* Short packet */
{ "aidl3/short/3", "adl3", GBINDER_DEFAULT_BINDER, NULL,
test_header_aidl3, 9 }, /* Short packet */
{ "hidl/ok", "hidl", GBINDER_DEFAULT_HWBINDER, "foo",
TEST_ARRAY_AND_SIZE(test_header_hidl) },
{ "hidl/short", "hidl", GBINDER_DEFAULT_HWBINDER, NULL,
@@ -166,6 +184,9 @@ test_device(
void)
{
const GBinderRpcProtocol* p;
TestConfig config;
test_config_init(&config, "");
p = gbinder_rpc_protocol_for_device(NULL);
g_assert(p);
@@ -178,6 +199,8 @@ test_device(
p = gbinder_rpc_protocol_for_device(GBINDER_DEFAULT_HWBINDER);
g_assert(p);
g_assert_cmpstr(p->name, == ,"hidl");
test_config_cleanup(&config);
}
/*==========================================================================*
@@ -348,6 +371,7 @@ test_no_header2(
static const TestData test_no_header_data[] = {
{ "aidl", "aidl", GBINDER_DEFAULT_BINDER },
{ "aidl2", "aidl2", GBINDER_DEFAULT_BINDER },
{ "aidl3", "aidl3", GBINDER_DEFAULT_BINDER },
};
/*==========================================================================*
@@ -369,7 +393,8 @@ test_write_header(
test_config_init2(&config, test->dev, test->prot);
prot = gbinder_rpc_protocol_for_device(test->dev);
req = gbinder_local_request_new(&gbinder_io_32, NULL);
req = gbinder_local_request_new(&gbinder_io_32,
gbinder_rpc_protocol_for_device(NULL), NULL);
gbinder_local_request_init_writer(req, &writer);
prot->write_rpc_header(&writer, test->iface);
data = gbinder_local_request_data(req);

View File

@@ -1,6 +1,7 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2023 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -50,9 +51,7 @@
static TestOpt test_opt;
#define DEV "/dev/xbinder"
#define DEV_PRIV DEV "-private"
#define DEV2 "/dev/ybinder"
#define DEV2_PRIV DEV2 "-private"
enum test_tx_codes {
TX_CODE = GBINDER_FIRST_CALL_TRANSACTION,
@@ -190,38 +189,28 @@ test_basic_run(
GBinderLocalObject* obj;
GBinderProxyObject* proxy;
GBinderRemoteObject* remote_obj;
GBinderRemoteObject* remote_proxy;
GBinderClient* proxy_client;
GBinderClient* client;
GBinderIpc* ipc_obj;
GBinderIpc* ipc_proxy;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd_obj, fd_proxy, n = 0;
test_config_init(&config, NULL);
ipc_proxy = gbinder_ipc_new(DEV);
ipc_obj = gbinder_ipc_new(DEV_PRIV);
ipc_proxy = gbinder_ipc_new(DEV, NULL);
ipc_obj = gbinder_ipc_new(DEV2, NULL);
fd_proxy = gbinder_driver_fd(ipc_proxy->driver);
fd_obj = gbinder_driver_fd(ipc_obj->driver);
obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_basic_cb, &n);
remote_obj = gbinder_remote_object_new(ipc_proxy,
remote_obj = gbinder_remote_object_new(ipc_obj,
test_binder_register_object(fd_obj, obj, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
/* remote_proxy(DEV_PRIV) => proxy (DEV) => obj (DEV) => DEV_PRIV */
g_assert(!gbinder_proxy_object_new(NULL, remote_obj));
g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj)));
remote_proxy = gbinder_remote_object_new(ipc_obj,
test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE);
test_binder_set_passthrough(fd_obj, TRUE);
test_binder_set_passthrough(fd_proxy, TRUE);
test_binder_set_looper_enabled(fd_obj, TEST_LOOPER_ENABLE);
test_binder_set_looper_enabled(fd_proxy, TEST_LOOPER_ENABLE);
client = gbinder_client_new(proxy->remote, TEST_IFACE);
/* Perform a transaction via proxy */
g_assert(gbinder_client_transact(proxy_client, TX_CODE, 0, NULL,
g_assert(gbinder_client_transact(client, TX_CODE, 0, NULL,
test_basic_reply, NULL, loop));
test_run(&test_opt, loop);
@@ -232,11 +221,9 @@ test_basic_run(
gbinder_local_object_drop(obj);
gbinder_local_object_drop(&proxy->parent);
gbinder_remote_object_unref(remote_obj);
gbinder_remote_object_unref(remote_proxy);
gbinder_client_unref(proxy_client);
gbinder_client_unref(client);
gbinder_ipc_unref(ipc_obj);
gbinder_ipc_unref(ipc_proxy);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
test_config_deinit(&config);
g_main_loop_unref(loop);
@@ -303,6 +290,19 @@ test_param_cb(
}
}
static
void
test_param_canceled(
GBinderClient* client,
GBinderRemoteReply* reply,
int status,
void* unused)
{
g_assert(!reply);
g_assert_cmpint(status, == ,-ECANCELED);
GDEBUG("Transaction cancelled");
}
static
void
test_param_reply(
@@ -311,35 +311,19 @@ test_param_reply(
int status,
void* loop)
{
/*
* Due to limitations of our binder simulation, the result can be
* delivered to a wrong thread. As a result, we only known that one
* of the callbacks get NULL result and one gets NULL loop, but we
* don't really know which one gets what, i.e. we have to be ready
* for any combination of these parameters.
*
* It's too difficult to fix (without writing almost a full-blown
* binder implementation), let's just live with it for now :/
*/
if (reply) {
GBinderReader reader;
gint32 result = 0;
GBinderReader reader;
gint32 result = 0;
GDEBUG("Reply received");
g_assert(reply);
g_assert_cmpint(status, == ,0);
GDEBUG("Reply received");
/* Make sure that result got delivered intact */
gbinder_remote_reply_init_reader(reply, &reader);
g_assert(gbinder_reader_read_int32(&reader, &result));
g_assert(gbinder_reader_at_end(&reader));
g_assert_cmpint(result, == ,TX_RESULT);
} else {
/* The cancelled one */
GDEBUG("Transaction cancelled");
}
if (loop) {
g_main_loop_quit((GMainLoop*)loop);
}
/* Make sure that result got delivered intact */
gbinder_remote_reply_init_reader(reply, &reader);
g_assert(gbinder_reader_read_int32(&reader, &result));
g_assert(gbinder_reader_at_end(&reader));
g_assert_cmpint(result, == ,TX_RESULT);
g_main_loop_quit((GMainLoop*)loop);
}
static
@@ -351,54 +335,40 @@ test_param_run(
GBinderLocalObject* obj;
GBinderProxyObject* proxy;
GBinderRemoteObject* remote_obj;
GBinderRemoteObject* remote_proxy;
GBinderClient* proxy_client;
GBinderClient* client;
GBinderLocalRequest* req;
GBinderIpc* ipc_obj;
GBinderIpc* ipc_remote_obj;
GBinderIpc* ipc_proxy;
GBinderIpc* ipc_remote_proxy;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd_obj, fd_proxy, n = 0;
test_config_init(&config, NULL);
ipc_obj = gbinder_ipc_new(DEV);
ipc_remote_obj = gbinder_ipc_new(DEV_PRIV);
ipc_proxy = gbinder_ipc_new(DEV2);
ipc_remote_proxy = gbinder_ipc_new(DEV2_PRIV);
ipc_proxy = gbinder_ipc_new(DEV2, NULL);
ipc_obj = gbinder_ipc_new(DEV, NULL);
fd_proxy = gbinder_driver_fd(ipc_proxy->driver);
fd_obj = gbinder_driver_fd(ipc_obj->driver);
obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_param_cb, &n);
remote_obj = gbinder_remote_object_new(ipc_remote_obj,
remote_obj = gbinder_remote_object_new(ipc_obj,
test_binder_register_object(fd_obj, obj, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
/* remote_proxy(DEV2_PRIV) => proxy (DEV2) => obj (DEV) => DEV_PRIV */
g_assert(!gbinder_proxy_object_new(NULL, remote_obj));
g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj)));
remote_proxy = gbinder_remote_object_new(ipc_remote_proxy,
test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE);
test_binder_set_passthrough(fd_obj, TRUE);
test_binder_set_passthrough(fd_proxy, TRUE);
test_binder_set_looper_enabled(fd_obj, TEST_LOOPER_ENABLE);
test_binder_set_looper_enabled(fd_proxy, TEST_LOOPER_ENABLE);
client = gbinder_client_new(proxy->remote, TEST_IFACE);
/*
* Perform two transactions via proxy. First one never gets completed
* and eventually is cancelled, and the second one is replied to.
*/
req = gbinder_client_new_request(proxy_client);
req = gbinder_client_new_request(client);
gbinder_local_request_append_int32(req, TX_PARAM_DONT_REPLY);
gbinder_client_transact(proxy_client, TX_CODE, 0, req, test_param_reply,
gbinder_client_transact(client, TX_CODE, 0, req, test_param_canceled,
NULL, NULL);
gbinder_local_request_unref(req);
req = gbinder_client_new_request(proxy_client);
req = gbinder_client_new_request(client);
gbinder_local_request_append_int32(req, TX_PARAM_REPLY);
g_assert(gbinder_client_transact(proxy_client, TX_CODE, 0, req,
g_assert(gbinder_client_transact(client, TX_CODE, 0, req,
test_param_reply, NULL, loop));
gbinder_local_request_unref(req);
@@ -412,13 +382,9 @@ test_param_run(
gbinder_local_object_drop(obj);
gbinder_local_object_drop(&proxy->parent);
gbinder_remote_object_unref(remote_obj);
gbinder_remote_object_unref(remote_proxy);
gbinder_client_unref(proxy_client);
gbinder_client_unref(client);
gbinder_ipc_unref(ipc_obj);
gbinder_ipc_unref(ipc_remote_obj);
gbinder_ipc_unref(ipc_proxy);
gbinder_ipc_unref(ipc_remote_proxy);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
test_config_deinit(&config);
g_main_loop_unref(loop);
@@ -438,7 +404,7 @@ test_param(
typedef struct test_obj_data {
GMainLoop* loop;
GBinderLocalObject* tmp_proxy;
GBinderLocalObject* obj2;
gboolean obj_call_handled;
gboolean obj_call_finished;
gboolean obj2_call_handled;
@@ -539,9 +505,9 @@ test_obj_cb(
g_assert(gbinder_reader_at_end(&reader));
/* Make sure temporary proxy won't get destroyed too early */
test->tmp_proxy = test_binder_object(gbinder_driver_fd(obj->ipc->driver),
test->obj2 = test_binder_object(gbinder_driver_fd(obj->ipc->driver),
obj2->handle);
g_assert(test->tmp_proxy);
g_assert(test->obj2);
/* Call remote object */
client2 = gbinder_client_new(obj2, TEST_IFACE2);
@@ -597,8 +563,7 @@ test_obj_run(
GBinderLocalObject* obj2;
GBinderProxyObject* proxy;
GBinderRemoteObject* remote_obj;
GBinderRemoteObject* remote_proxy;
GBinderClient* proxy_client;
GBinderClient* client;
GBinderIpc* ipc_obj;
GBinderIpc* ipc_proxy;
GBinderLocalRequest* req;
@@ -608,35 +573,29 @@ test_obj_run(
memset(&test, 0, sizeof(test));
test.loop = g_main_loop_new(NULL, FALSE);
ipc_proxy = gbinder_ipc_new(DEV);
ipc_obj = gbinder_ipc_new(DEV_PRIV);
ipc_proxy = gbinder_ipc_new(DEV2, NULL);
ipc_obj = gbinder_ipc_new(DEV, NULL);
fd_proxy = gbinder_driver_fd(ipc_proxy->driver);
fd_obj = gbinder_driver_fd(ipc_obj->driver);
obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_obj_cb, &test);
obj2 = gbinder_local_object_new(ipc_obj, TEST_IFACES2, test_obj2_cb, &test);
remote_obj = gbinder_remote_object_new(ipc_proxy,
GDEBUG("obj %p", obj);
remote_obj = gbinder_remote_object_new(ipc_obj,
test_binder_register_object(fd_obj, obj, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
/* remote_proxy(DEV_PRIV) => proxy (DEV) => obj (DEV) => DEV_PRIV */
g_assert(!gbinder_proxy_object_new(NULL, remote_obj));
g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj)));
remote_proxy = gbinder_remote_object_new(ipc_obj,
test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE),
REMOTE_OBJECT_CREATE_ALIVE);
proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE);
test_binder_set_passthrough(fd_obj, TRUE);
test_binder_set_passthrough(fd_proxy, TRUE);
test_binder_set_looper_enabled(fd_obj, TEST_LOOPER_ENABLE);
test_binder_set_looper_enabled(fd_proxy, TEST_LOOPER_ENABLE);
GDEBUG("proxy %p", proxy);
client = gbinder_client_new(proxy->remote, TEST_IFACE);
/* Pass object reference via proxy */
req = gbinder_client_new_request(proxy_client);
obj2 = gbinder_local_object_new(ipc_obj, TEST_IFACES2, test_obj2_cb, &test);
GDEBUG("obj2 %p", obj2);
req = gbinder_client_new_request(client);
gbinder_local_request_append_int32(req, TX_PARAM1);
gbinder_local_request_append_local_object(req, obj2);
gbinder_local_request_append_int32(req, TX_PARAM2);
gbinder_client_transact(proxy_client, TX_CODE, 0, req, test_obj_reply,
gbinder_client_transact(client, TX_CODE, 0, req, test_obj_reply,
NULL, &test);
gbinder_local_request_unref(req);
@@ -646,20 +605,19 @@ test_obj_run(
g_assert(test.obj_call_finished);
g_assert(test.obj2_call_handled);
g_assert(test.obj2_call_finished);
g_assert(test.tmp_proxy);
gbinder_local_object_unref(test.tmp_proxy);
g_assert(test.obj2);
gbinder_local_object_unref(test.obj2);
test_binder_unregister_objects(fd_obj);
test_binder_unregister_objects(fd_proxy);
gbinder_local_object_drop(obj);
gbinder_local_object_drop(obj2);
gbinder_local_object_drop(&proxy->parent);
gbinder_remote_object_unref(remote_obj);
gbinder_remote_object_unref(remote_proxy);
gbinder_client_unref(proxy_client);
gbinder_client_unref(client);
gbinder_ipc_unref(ipc_obj);
gbinder_ipc_unref(ipc_proxy);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop);
test_config_deinit(&config);
g_main_loop_unref(test.loop);

View File

@@ -1,6 +1,7 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2023 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -31,6 +32,7 @@
*/
#include "test_common.h"
#include "test_binder.h"
#include "gbinder_buffer_p.h"
#include "gbinder_driver.h"
@@ -39,6 +41,8 @@
#include "gbinder_remote_object_p.h"
#include "gbinder_io.h"
#include <gutil_misc.h>
#include <unistd.h>
#include <fcntl.h>
@@ -57,14 +61,46 @@ typedef struct binder_buffer_object_64 {
} BinderObject64;
#define BINDER_TYPE_(c1,c2,c3) GBINDER_FOURCC(c1,c2,c3,0x85)
#define BINDER_TYPE_HANDLE BINDER_TYPE_('s','h','*')
#define BINDER_TYPE_PTR BINDER_TYPE_('p','t','*')
#define BINDER_TYPE_FD BINDER_TYPE_('f', 'd', '*')
#define BINDER_BUFFER_FLAG_HAS_PARENT 0x01
#define BINDER_FLAG_ACCEPTS_FDS 0x100
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
G_STATIC_ASSERT(sizeof(BinderObject64) == BUFFER_OBJECT_SIZE_64);
static
void
test_init_reader(
GBinderDriver* driver,
GBinderReaderData* data,
GBinderReader* reader,
const void* bytes,
gsize size)
{
data->buffer = gbinder_buffer_new(driver, gutil_memdup(bytes, size),
size, NULL);
gbinder_reader_init(reader, data, 0, size);
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
GBinderReader reader;
/* NULL const pointers are tolerated */
g_assert(gbinder_reader_at_end(NULL));
g_assert(!gbinder_reader_bytes_read(NULL));
g_assert(!gbinder_reader_bytes_remaining(NULL));
g_assert(!gbinder_reader_get_data(NULL, NULL));
gbinder_reader_copy(&reader, NULL);
g_assert(gbinder_reader_at_end(&reader));
}
/*==========================================================================*
* empty
*==========================================================================*/
@@ -76,14 +112,19 @@ test_empty(
{
GBinderReader reader;
gsize count = 1, elemsize = 1;
gsize len;
gsize size = 1;
gbinder_reader_init(&reader, NULL, 0, 0);
g_assert(gbinder_reader_at_end(&reader));
g_assert(!gbinder_reader_get_data(&reader, NULL));
g_assert(!gbinder_reader_get_data(&reader, &size));
g_assert(!size);
g_assert(!gbinder_reader_bytes_read(&reader));
g_assert(!gbinder_reader_bytes_remaining(&reader));
g_assert(!gbinder_reader_read_byte(&reader, NULL));
g_assert(!gbinder_reader_read_bool(&reader, NULL));
g_assert(!gbinder_reader_read_int8(&reader, NULL));
g_assert(!gbinder_reader_read_int16(&reader, NULL));
g_assert(!gbinder_reader_read_int32(&reader, NULL));
g_assert(!gbinder_reader_read_uint32(&reader, NULL));
g_assert(!gbinder_reader_read_int64(&reader, NULL));
@@ -93,6 +134,7 @@ test_empty(
g_assert(!gbinder_reader_read_object(&reader));
g_assert(!gbinder_reader_read_nullable_object(&reader, NULL));
g_assert(!gbinder_reader_read_buffer(&reader));
g_assert(!gbinder_reader_read_parcelable(&reader, NULL));
g_assert(!gbinder_reader_read_hidl_struct1(&reader, 1));
g_assert(!gbinder_reader_read_hidl_vec(&reader, NULL, NULL));
g_assert(!gbinder_reader_read_hidl_vec(&reader, &count, &elemsize));
@@ -107,7 +149,7 @@ test_empty(
g_assert(!gbinder_reader_read_string8(&reader));
g_assert(!gbinder_reader_read_string16(&reader));
g_assert(!gbinder_reader_skip_string16(&reader));
g_assert(!gbinder_reader_read_byte_array(&reader, &len));
g_assert(!gbinder_reader_read_byte_array(&reader, &size));
}
/*==========================================================================*
@@ -133,7 +175,7 @@ test_byte(
gbinder_reader_init(&reader, &data, 0, sizeof(in));
g_assert(gbinder_reader_read_byte(&reader, &out));
g_assert(gbinder_reader_at_end(&reader));
g_assert(in == out);
g_assert_cmpuint(in, == ,out);
gbinder_reader_init(&reader, &data, 0, sizeof(in));
g_assert(gbinder_reader_read_byte(&reader, NULL));
@@ -152,8 +194,8 @@ void
test_bool(
void)
{
const guint8 in_true[4] = { 0x01, 0xff, 0xff, 0xff };
const guint8 in_false[4] = { 0x00, 0xff, 0xff, 0xff };
const guint8 in_true[] = { TEST_INT8_BYTES_4(TRUE) };
const guint8 in_false[] = { TEST_INT8_BYTES_4(FALSE) };
gboolean out = FALSE;
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderReader reader;
@@ -172,7 +214,7 @@ test_bool(
gbinder_reader_init(&reader, &data, 0, data.buffer->size);
g_assert(gbinder_reader_read_bool(&reader, &out));
g_assert(gbinder_reader_at_end(&reader));
g_assert(out == TRUE);
g_assert_cmpuint(out, == ,TRUE);
/* false */
gbinder_buffer_free(data.buffer);
@@ -192,6 +234,108 @@ test_bool(
gbinder_driver_unref(driver);
}
/*==========================================================================*
* int8
*==========================================================================*/
static
void
test_int8(
void)
{
const guint8 in = 0x2a;
const guint8 in4[] = { 0x2a, 0x00, 0x00, 0x00 };
guint8 out1 = 0;
gint8 out2 = 0;
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderReader reader;
GBinderReaderData data;
g_assert(driver);
memset(&data, 0, sizeof(data));
/* Not enough data */
data.buffer = gbinder_buffer_new(driver, g_memdup(&in, sizeof(in)),
sizeof(in), NULL);
gbinder_reader_init(&reader, &data, 0, sizeof(in));
g_assert(!gbinder_reader_read_uint8(&reader, &out1));
g_assert(!gbinder_reader_at_end(&reader));
gbinder_buffer_free(data.buffer);
/* Enough data */
data.buffer = gbinder_buffer_new(driver, g_memdup(in4, sizeof(in4)),
sizeof(in4), NULL);
gbinder_reader_init(&reader, &data, 0, sizeof(in4));
g_assert(gbinder_reader_read_uint8(&reader, &out1));
g_assert(gbinder_reader_at_end(&reader));
g_assert_cmpuint(in, == ,out1);
gbinder_reader_init(&reader, &data, 0, sizeof(in4));
g_assert(gbinder_reader_read_int8(&reader, &out2));
g_assert(gbinder_reader_at_end(&reader));
g_assert_cmpint(in, == ,out2);
gbinder_reader_init(&reader, &data, 0, sizeof(in4));
g_assert(gbinder_reader_read_int8(&reader, NULL));
g_assert(gbinder_reader_at_end(&reader));
gbinder_buffer_free(data.buffer);
gbinder_driver_unref(driver);
}
/*==========================================================================*
* int16
*==========================================================================*/
static
void
test_int16(
void)
{
const guint16 in = 42;
const guint8 in4[] = { TEST_INT16_BYTES(42), 0x00, 0x00 };
guint16 out1 = 0;
gint16 out2 = 0;
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderReader reader;
GBinderReaderData data;
g_assert(driver);
memset(&data, 0, sizeof(data));
/* Not enough data */
data.buffer = gbinder_buffer_new(driver, g_memdup(&in, sizeof(in)),
sizeof(in), NULL);
gbinder_reader_init(&reader, &data, 0, sizeof(in));
g_assert(!gbinder_reader_read_uint16(&reader, &out1));
g_assert(!gbinder_reader_at_end(&reader));
gbinder_buffer_free(data.buffer);
/* Enough data */
data.buffer = gbinder_buffer_new(driver, g_memdup(in4, sizeof(in4)),
sizeof(in4), NULL);
gbinder_reader_init(&reader, &data, 0, sizeof(in4));
g_assert(gbinder_reader_read_uint16(&reader, &out1));
g_assert(gbinder_reader_at_end(&reader));
g_assert_cmpuint(in, == ,out1);
gbinder_reader_init(&reader, &data, 0, sizeof(in4));
g_assert(gbinder_reader_read_int16(&reader, &out2));
g_assert(gbinder_reader_at_end(&reader));
g_assert_cmpint(in, == ,out2);
gbinder_reader_init(&reader, &data, 0, sizeof(in4));
g_assert(gbinder_reader_read_int16(&reader, NULL));
g_assert(gbinder_reader_at_end(&reader));
gbinder_buffer_free(data.buffer);
gbinder_driver_unref(driver);
}
/*==========================================================================*
* int32
*==========================================================================*/
@@ -624,7 +768,7 @@ test_hidl_struct(
gconstpointer test_data)
{
const TestHidlStruct* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data;
@@ -644,6 +788,7 @@ test_hidl_struct(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -828,7 +973,7 @@ test_hidl_vec(
gconstpointer test_data)
{
const TestHidlVec* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data;
@@ -879,6 +1024,7 @@ test_hidl_vec(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -934,7 +1080,7 @@ test_hidl_string_err(
gconstpointer test_data)
{
const TestHidlStringErr* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data;
@@ -960,6 +1106,7 @@ test_hidl_string_err(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
static
@@ -968,7 +1115,7 @@ test_hidl_string_err_skip(
gconstpointer test_data)
{
const TestHidlStringErr* test = test_data;
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(test->in, test->in_size), test->in_size, NULL);
GBinderReaderData data;
@@ -994,6 +1141,7 @@ test_hidl_string_err_skip(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1013,7 +1161,7 @@ test_fd_ok(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1037,6 +1185,7 @@ test_fd_ok(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1053,7 +1202,7 @@ test_fd_shortbuf(
TEST_INT32_BYTES(BINDER_TYPE_FD),
TEST_INT32_BYTES(0x7f | BINDER_FLAG_ACCEPTS_FDS)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1068,6 +1217,7 @@ test_fd_shortbuf(
g_assert(gbinder_reader_read_fd(&reader) < 0);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1087,7 +1237,7 @@ test_fd_badtype(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1111,6 +1261,7 @@ test_fd_badtype(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1130,7 +1281,7 @@ test_dupfd_ok(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1158,6 +1309,7 @@ test_dupfd_ok(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1177,7 +1329,7 @@ test_dupfd_badtype(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1201,6 +1353,7 @@ test_dupfd_badtype(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1220,7 +1373,7 @@ test_dupfd_badfd(
TEST_INT32_BYTES(fd), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderReaderData data;
@@ -1244,6 +1397,7 @@ test_dupfd_badfd(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1259,7 +1413,7 @@ test_hidl_string(
guint bufcount,
const char* result)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver, g_memdup(input, size),
size, NULL);
GBinderRemoteObject* obj = NULL;
@@ -1284,6 +1438,7 @@ test_hidl_string(
gbinder_remote_object_unref(obj);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
static
@@ -1530,7 +1685,7 @@ test_buffer(
TEST_INT64_BYTES(0), TEST_INT64_BYTES(0),
TEST_INT64_BYTES(0), TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL;
@@ -1562,6 +1717,99 @@ test_buffer(
gbinder_remote_object_unref(obj);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
* parcelable
*==========================================================================*/
static
void
test_parcelable(
void)
{
const guint8 input_null_header[] = {
TEST_INT32_BYTES(0)
};
const guint8 input_broken_header[] = {
TEST_INT32_BYTES(1),
TEST_INT32_BYTES(1)
};
const guint8 input_non_null_header[] = {
TEST_INT32_BYTES(1),
/* Size must be size of itself + payload */
TEST_INT32_BYTES(sizeof(gint32) * 3)
};
const guint8 input_non_null_payload[] = {
TEST_INT32_BYTES(10),
TEST_INT32_BYTES(20)
};
gpointer in;
gsize in_size, out_size;
const void* out = 0;
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderReader reader;
GBinderReaderData data;
g_assert(driver);
memset(&data, 0, sizeof(data));
/* Missing payload */
test_init_reader(driver, &data, &reader,
TEST_ARRAY_AND_SIZE(input_non_null_header));
out = gbinder_reader_read_parcelable(&reader, &out_size);
g_assert(!out);
g_assert_cmpuint(out_size, == ,0);
gbinder_buffer_free(data.buffer);
/* Broken headers */
test_init_reader(driver, &data, &reader, input_broken_header, 4);
out = gbinder_reader_read_parcelable(&reader, &out_size);
g_assert(!out);
g_assert_cmpuint(out_size, == ,0);
gbinder_buffer_free(data.buffer);
test_init_reader(driver, &data, &reader,
TEST_ARRAY_AND_SIZE(input_broken_header));
out = gbinder_reader_read_parcelable(&reader, &out_size);
g_assert(!out);
g_assert_cmpuint(out_size, == ,0);
gbinder_buffer_free(data.buffer);
/* Null */
test_init_reader(driver, &data, &reader,
TEST_ARRAY_AND_SIZE(input_null_header));
gbinder_reader_init(&reader, &data, 0, sizeof(input_null_header));
out = gbinder_reader_read_parcelable(&reader, &out_size);
g_assert(!out);
g_assert_cmpuint(out_size, == ,0);
g_assert(gbinder_reader_at_end(&reader));
gbinder_buffer_free(data.buffer);
/* Non-null */
in_size = sizeof(input_non_null_header) + sizeof(input_non_null_payload);
in = g_malloc(in_size);
memcpy(in, &input_non_null_header, sizeof(input_non_null_header));
memcpy(in + sizeof(input_non_null_header), &input_non_null_payload,
sizeof(input_non_null_payload));
data.buffer = gbinder_buffer_new(driver, in, in_size, NULL);
gbinder_reader_init(&reader, &data, 0, in_size);
out = gbinder_reader_read_parcelable(&reader, &out_size);
g_assert(memcmp(&input_non_null_payload, out,
sizeof(input_non_null_payload)) == 0);
g_assert_cmpuint(out_size, == ,sizeof(input_non_null_payload));
g_assert(gbinder_reader_at_end(&reader));
/* And verify NULL tolerance for the size parameter */
gbinder_reader_init(&reader, &data, 0, in_size);
out = gbinder_reader_read_parcelable(&reader, NULL);
g_assert(memcmp(&input_non_null_payload, out,
sizeof(input_non_null_payload)) == 0);
gbinder_buffer_free(data.buffer);
gbinder_driver_unref(driver);
}
/*==========================================================================*
@@ -1576,9 +1824,10 @@ test_object(
/* Using 64-bit I/O */
static const guint8 input[] = {
TEST_INT32_BYTES(BINDER_TYPE_HANDLE), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(1 /* handle*/), TEST_INT64_BYTES(0)
TEST_INT32_BYTES(1 /* handle*/), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL;
@@ -1596,12 +1845,13 @@ test_object(
g_assert(gbinder_reader_read_nullable_object(&reader, &obj));
g_assert(obj);
g_assert(obj->handle == 1);
g_assert_cmpuint(obj->handle, == ,1);
g_free(data.objects);
gbinder_remote_object_unref(obj);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1636,7 +1886,7 @@ test_object_invalid(
TEST_INT32_BYTES(42 /* invalid type */), TEST_INT32_BYTES(0),
TEST_INT64_BYTES(1 /* handle*/), TEST_INT64_BYTES(0)
};
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(input, sizeof(input)), sizeof(input), NULL);
GBinderRemoteObject* obj = NULL;
@@ -1658,6 +1908,7 @@ test_object_invalid(
g_free(data.objects);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1670,7 +1921,7 @@ test_vec(
void)
{
/* Using 64-bit I/O */
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderReaderData data;
GBinderReader reader;
BinderObject64 obj;
@@ -1710,6 +1961,7 @@ test_vec(
g_free(data.objects);
gbinder_buffer_free(data.buffer);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -1723,7 +1975,7 @@ test_hidl_string_vec(
gsize size,
const char* const* result)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver, g_memdup(input, size),
size, NULL);
GBinderRemoteObject* obj = NULL;
@@ -1746,8 +1998,7 @@ test_hidl_string_vec(
data.objects[i] = NULL;
gbinder_reader_init(&reader, &data, 0, buf->size);
out = gbinder_reader_read_hidl_string_vec(&reader)
;
out = gbinder_reader_read_hidl_string_vec(&reader);
if (out) {
const guint n = g_strv_length(out);
@@ -1765,6 +2016,7 @@ test_hidl_string_vec(
gbinder_remote_object_unref(obj);
gbinder_buffer_free(buf);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
static
@@ -1864,7 +2116,6 @@ test_hidl_string_vec2(
TEST_INT64_BYTES(2),
TEST_INT64_BYTES(sizeof(GBinderHidlString) +
GBINDER_HIDL_STRING_BUFFER_OFFSET)
};
static const char* const result[] = { str1, str2, NULL };
@@ -1990,7 +2241,6 @@ test_hidl_string_vec5(
TEST_INT64_BYTES(sizeof(str2)),
TEST_INT64_BYTES(2),
TEST_INT64_BYTES(GBINDER_HIDL_STRING_BUFFER_OFFSET)
};
test_hidl_string_vec(TEST_ARRAY_AND_SIZE(input), NULL);
@@ -2098,9 +2348,9 @@ test_copy(
gint32 in_len2 = sizeof(in_data2) - 1;
const void* out_data = NULL;
gsize out_len = 0;
void* tmp;
guint8* ptr;
gsize tmp_len = 2 * sizeof(guint32) + in_len1 + in_len2;
void* buf;
gsize buf_len = 2 * sizeof(guint32) + in_len1 + in_len2;
GBinderDriver* driver;
GBinderReader reader;
@@ -2109,7 +2359,7 @@ test_copy(
/* test for data */
g_assert((driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER, NULL)));
ptr = tmp = g_malloc0(tmp_len);
ptr = buf = g_malloc0(buf_len);
memcpy(ptr, &in_len1, sizeof(in_len1));
ptr += sizeof(in_len1);
memcpy(ptr, in_data1, in_len1);
@@ -2119,28 +2369,40 @@ test_copy(
memcpy(ptr, in_data2, in_len2);
memset(&data, 0, sizeof(data));
data.buffer = gbinder_buffer_new(driver, tmp, tmp_len, NULL);
gbinder_reader_init(&reader, &data, 0, tmp_len);
data.buffer = gbinder_buffer_new(driver, buf, buf_len, NULL);
gbinder_reader_init(&reader, &data, 0, buf_len);
/* Read the first array */
g_assert((out_data = gbinder_reader_read_byte_array(&reader, &out_len)));
g_assert((gsize)in_len1 == out_len);
g_assert_cmpuint(in_len1, == ,out_len);
g_assert(memcmp(in_data1, out_data, in_len1) == 0);
/* Fetch raw data */
g_assert((out_data = gbinder_reader_get_data(&reader, &out_len)));
g_assert(out_data == gbinder_reader_get_data(&reader, NULL));
g_assert_cmpuint(out_len, == ,buf_len);
g_assert(memcmp(out_data, buf, buf_len) == 0);
/* Copy the reader */
gbinder_reader_copy(&reader2, &reader);
/* Read both and compare the output */
g_assert((out_data = gbinder_reader_read_byte_array(&reader, &out_len)));
g_assert(gbinder_reader_at_end(&reader));
g_assert((gsize)in_len2 == out_len);
g_assert_cmpuint(in_len1, == ,out_len);
g_assert(memcmp(in_data2, out_data, in_len2) == 0);
g_assert((out_data = gbinder_reader_read_byte_array(&reader2, &out_len)));
g_assert(gbinder_reader_at_end(&reader2));
g_assert((gsize)in_len2 == out_len);
g_assert_cmpuint(in_len2, == ,out_len);
g_assert(memcmp(in_data2, out_data, in_len2) == 0);
/* Fetch raw data from the copied reader */
g_assert((out_data = gbinder_reader_get_data(&reader2, &out_len)));
g_assert(out_data == gbinder_reader_get_data(&reader2, NULL));
g_assert_cmpuint(out_len, == ,buf_len);
g_assert(memcmp(out_data, buf, buf_len) == 0);
gbinder_buffer_free(data.buffer);
gbinder_driver_unref(driver);
}
@@ -2161,9 +2423,12 @@ int main(int argc, char* argv[])
G_GNUC_END_IGNORE_DEPRECATIONS;
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("empty"), test_empty);
g_test_add_func(TEST_("byte"), test_byte);
g_test_add_func(TEST_("bool"), test_bool);
g_test_add_func(TEST_("int8"), test_int8);
g_test_add_func(TEST_("int16"), test_int16);
g_test_add_func(TEST_("int32"), test_int32);
g_test_add_func(TEST_("int64"), test_int64);
g_test_add_func(TEST_("float"), test_float);
@@ -2232,6 +2497,7 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_("hidl_string/6"), test_hidl_string6);
g_test_add_func(TEST_("hidl_string/7"), test_hidl_string7);
g_test_add_func(TEST_("buffer"), test_buffer);
g_test_add_func(TEST_("parcelable"), test_parcelable);
g_test_add_func(TEST_("object/valid"), test_object);
g_test_add_func(TEST_("object/invalid"), test_object_invalid);
g_test_add_func(TEST_("object/no_reg"), test_object_no_reg);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -68,7 +68,7 @@ void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj1 = gbinder_object_registry_get_remote(reg,1,TRUE);
GBinderRemoteObject* obj2 = gbinder_object_registry_get_remote(reg,2,TRUE);
@@ -89,6 +89,7 @@ test_basic(
gbinder_remote_object_unref(obj1);
gbinder_remote_object_unref(obj2);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -112,15 +113,14 @@ test_dead_run(
{
const guint h = 1;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, h, TRUE);
gulong id = gbinder_remote_object_add_death_handler
(obj, test_dead_done, loop);
test_binder_br_dead_binder(fd, h);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_br_dead_binder(fd, ANY_THREAD, h);
test_run(&test_opt, loop);
g_assert(gbinder_remote_object_is_dead(obj));
@@ -128,7 +128,7 @@ test_dead_run(
gbinder_remote_object_remove_handler(obj, 0); /* has no effect */
gbinder_remote_object_unref(obj);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -31,6 +31,7 @@
*/
#include "test_common.h"
#include "test_binder.h"
#include "gbinder_buffer_p.h"
#include "gbinder_driver.h"
@@ -44,9 +45,6 @@
static TestOpt test_opt;
#define BINDER_TYPE_BINDER GBINDER_FOURCC('s', 'b', '*', 0x85)
#define BINDER_OBJECT_SIZE_64 (GBINDER_MAX_BINDER_OBJECT_SIZE)
/*==========================================================================*
* Dummy GBinderObjectRegistry functions
*==========================================================================*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -31,8 +31,10 @@
*/
#include "test_common.h"
#include "test_binder.h"
#include "gbinder_buffer_p.h"
#include "gbinder_config.h"
#include "gbinder_driver.h"
#include "gbinder_reader.h"
#include "gbinder_remote_request_p.h"
@@ -58,9 +60,6 @@ static TestOpt test_opt;
#define HIDL_RPC_HEADER \
'f', 'o', 'o', 0x00
#define BINDER_TYPE_BINDER GBINDER_FOURCC('s', 'b', '*', 0x85)
#define BINDER_OBJECT_SIZE_64 (GBINDER_MAX_BINDER_OBJECT_SIZE)
/*==========================================================================*
* null
*==========================================================================*/
@@ -369,6 +368,18 @@ test_to_local(
int main(int argc, char* argv[])
{
const char* default_config_dir;
const char* default_config_file;
char* conf_dir = g_dir_make_tmp("gbinder-test-remote-request-XXXXXX", NULL);
char* conf_file = g_build_filename(conf_dir, "test.conf", NULL);
int result;
/* Point gbinder_config_file to a non-existent file */
default_config_dir = gbinder_config_dir;
default_config_file = gbinder_config_file;
gbinder_config_dir = conf_dir;
gbinder_config_file = conf_file;
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "null", test_null);
g_test_add_func(TEST_PREFIX "basic", test_basic);
@@ -378,7 +389,14 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_PREFIX "string16", test_string16);
g_test_add_func(TEST_PREFIX "to_local", test_to_local);
test_init(&test_opt, argc, argv);
return g_test_run();
result = g_test_run();
gbinder_config_dir = default_config_dir;
gbinder_config_file = default_config_file;
remove(conf_dir);
g_free(conf_dir);
g_free(conf_file);
return result;
}
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -133,9 +133,9 @@ test_setup_ping(
{
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);
test_binder_br_noop(fd, THIS_THREAD);
test_binder_br_transaction_complete(fd, THIS_THREAD);
test_binder_br_reply(fd, THIS_THREAD, 0, 0, NULL);
}
/*==========================================================================*
@@ -386,8 +386,25 @@ gbinder_servicemanager_aidl_get_type()
GType
gbinder_servicemanager_aidl2_get_type()
{
/* Avoid pulling in gbinder_servicemanager_aidl2 object */
return TEST_TYPE_DEFSERVICEMANAGER;
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl2 */
g_assert_not_reached();
return 0;
}
GType
gbinder_servicemanager_aidl3_get_type()
{
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl3 */
g_assert_not_reached();
return 0;
}
GType
gbinder_servicemanager_aidl4_get_type()
{
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl4 */
g_assert_not_reached();
return 0;
}
/*==========================================================================*
@@ -400,9 +417,10 @@ test_null(
void)
{
g_assert(!gbinder_servicemanager_new(NULL));
g_assert(!gbinder_servicemanager_new_with_type(0, NULL));
g_assert(!gbinder_servicemanager_new_with_type(0, NULL, NULL));
g_assert(!gbinder_servicemanager_new_local_object(NULL, NULL, NULL, NULL));
g_assert(!gbinder_servicemanager_ref(NULL));
g_assert(!gbinder_servicemanager_device(NULL));
g_assert(!gbinder_servicemanager_is_present(NULL));
g_assert(!gbinder_servicemanager_wait(NULL, 0));
g_assert(!gbinder_servicemanager_list(NULL, NULL, NULL));
@@ -432,14 +450,15 @@ test_invalid(
{
int status = 0;
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderServiceManager* sm;
gulong id = 0;
test_setup_ping(ipc);
g_assert(!gbinder_servicemanager_new2(GBINDER_DEFAULT_HWBINDER, "a", NULL));
sm = gbinder_servicemanager_new(dev);
g_assert(!gbinder_servicemanager_new_with_type(GBINDER_TYPE_LOCAL_OBJECT,
NULL));
NULL, NULL));
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
g_assert(!gbinder_servicemanager_list(sm, NULL, NULL));
g_assert(!gbinder_servicemanager_get_service(sm, "foo", NULL, NULL));
@@ -465,6 +484,7 @@ test_invalid(
gbinder_servicemanager_remove_handlers(sm, &id, 0);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -477,7 +497,7 @@ test_basic(
void)
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderServiceManager* sm;
GBinderLocalObject* obj;
@@ -487,13 +507,14 @@ test_basic(
obj = gbinder_servicemanager_new_local_object(sm, "foo.bar",
test_transact_func, NULL);
g_assert(obj);
g_assert_cmpstr(gbinder_servicemanager_device(sm), == ,dev);
gbinder_local_object_unref(obj);
g_assert(gbinder_servicemanager_ref(sm) == sm);
gbinder_servicemanager_unref(sm);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -507,7 +528,7 @@ test_legacy(
{
const char* otherdev = "/dev/otherbinder";
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderServiceManager* sm;
/* Reset the state */
@@ -528,7 +549,7 @@ test_legacy(
gbinder_ipc_unref(ipc);
/* Legacy default */
ipc = gbinder_ipc_new(otherdev);
ipc = gbinder_ipc_new(otherdev, NULL);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(otherdev);
g_assert(TEST_IS_DEFSERVICEMANAGER(sm));
@@ -536,7 +557,7 @@ test_legacy(
gbinder_ipc_unref(ipc);
gbinder_servicemanager_exit();
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -571,7 +592,7 @@ test_config(
gbinder_config_file = file;
/* Unknown device instantiates the default */
ipc = gbinder_ipc_new(strange_name);
ipc = gbinder_ipc_new(strange_name, NULL);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(strange_name);
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
@@ -579,7 +600,7 @@ test_config(
gbinder_ipc_unref(ipc);
/* This one was redefined */
ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(GBINDER_DEFAULT_BINDER);
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
@@ -587,7 +608,7 @@ test_config(
gbinder_ipc_unref(ipc);
/* This one was not (since name was invalid) */
ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
ipc = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER, NULL);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(GBINDER_DEFAULT_HWBINDER);
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
@@ -595,17 +616,26 @@ test_config(
gbinder_ipc_unref(ipc);
/* This one points to legacy manager */
ipc = gbinder_ipc_new(legacy_name);
ipc = gbinder_ipc_new(legacy_name, NULL);
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(legacy_name);
g_assert(TEST_IS_DEFSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
/* Overwrite the legacy manager with "hidl" */
ipc = gbinder_ipc_new(legacy_name, "hidl");
test_setup_ping(ipc);
sm = gbinder_servicemanager_new2(legacy_name, "hidl", "hidl");
g_assert(TEST_IS_HWSERVICEMANAGER(sm));
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
/* Clear the state */
gbinder_servicemanager_exit();
gbinder_config_exit();
gbinder_config_file = NULL;
test_binder_exit_wait(&test_opt, NULL);
remove(file);
remove(dir);
@@ -623,12 +653,12 @@ test_not_present(
void)
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderServiceManager* sm;
/* This makes presence detection PING fail */
test_binder_br_reply_status(fd, -1);
test_binder_br_reply_status(fd, THIS_THREAD, -1);
sm = gbinder_servicemanager_new(dev);
g_assert(sm);
@@ -636,6 +666,7 @@ test_not_present(
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -648,7 +679,7 @@ test_wait(
void)
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
const glong forever = (test_opt.flags & TEST_FLAG_DEBUG) ?
(TEST_TIMEOUT_SEC * 1000) : -1;
@@ -657,7 +688,7 @@ test_wait(
int count = 0;
/* This makes presence detection PING fail */
test_binder_br_reply_status(fd, -1);
test_binder_br_reply_status(fd, THIS_THREAD, -1);
sm = gbinder_servicemanager_new(dev);
g_assert(sm);
@@ -668,13 +699,13 @@ test_wait(
g_assert(id);
/* Make this wait fail */
test_binder_br_reply_status(fd, -1);
test_binder_br_reply_status(fd, THIS_THREAD, -1);
g_assert(!gbinder_servicemanager_wait(sm, 0));
/* This makes presence detection PING succeed */
test_binder_br_noop(fd);
test_binder_br_transaction_complete(fd);
test_binder_br_reply(fd, 0, 0, NULL);
test_binder_br_noop(fd, THIS_THREAD);
test_binder_br_transaction_complete(fd, THIS_THREAD);
test_binder_br_reply(fd, THIS_THREAD, 0, 0, NULL);
g_assert(gbinder_servicemanager_wait(sm, forever));
/* The next check succeeds too (without any I/O ) */
@@ -686,7 +717,7 @@ test_wait(
gbinder_servicemanager_remove_handler(sm, id);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -699,14 +730,14 @@ test_wait_long(
void)
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderServiceManager* sm;
gulong id;
int count = 0;
/* This makes presence detection PING fail */
test_binder_br_reply_status(fd, -1);
test_binder_br_reply_status(fd, THIS_THREAD, -1);
sm = gbinder_servicemanager_new(dev);
g_assert(sm);
@@ -717,10 +748,10 @@ test_wait_long(
g_assert(id);
/* Make the first presence detection PING fail and second succeed */
test_binder_br_reply_status(fd, -1);
test_binder_br_reply_status_later(fd, -1);
test_binder_br_transaction_complete_later(fd);
test_binder_br_reply_later(fd, 0, 0, NULL);
test_binder_br_reply_status(fd, THIS_THREAD, -1);
test_binder_br_reply_status(fd, TX_THREAD, -1);
test_binder_br_transaction_complete(fd, TX_THREAD);
test_binder_br_reply(fd, TX_THREAD, 0, 0, NULL);
g_assert(gbinder_servicemanager_wait(sm, TEST_TIMEOUT_SEC * 1000));
/* The next check succeeds too (without any I/O ) */
@@ -732,7 +763,7 @@ test_wait_long(
gbinder_servicemanager_remove_handler(sm, id);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -745,7 +776,7 @@ test_wait_async(
void)
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
@@ -753,7 +784,7 @@ test_wait_async(
int count = 0;
/* This makes presence detection PING fail */
test_binder_br_reply_status(fd, -1);
test_binder_br_reply_status(fd, THIS_THREAD, -1);
sm = gbinder_servicemanager_new(dev);
g_assert(sm);
@@ -766,9 +797,9 @@ test_wait_async(
g_assert(id[1]);
/* Make the first presence detection PING fail and second succeed */
test_binder_br_reply_status(fd, -1);
test_binder_br_transaction_complete_later(fd);
test_binder_br_reply_later(fd, 0, 0, NULL);
test_binder_br_reply_status(fd, THIS_THREAD, -1);
test_binder_br_transaction_complete(fd, TX_THREAD);
test_binder_br_reply(fd, TX_THREAD, 0, 0, NULL);
test_run(&test_opt, loop);
/* The listener must have been invoked exactly once */
@@ -776,7 +807,7 @@ test_wait_async(
gbinder_servicemanager_remove_all_handlers(sm, id);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -789,7 +820,7 @@ void
test_death_run()
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
@@ -810,9 +841,8 @@ test_death_run()
g_assert(id[1]);
g_assert(id[2]);
/* Generate death notification (need looper for that) */
test_binder_br_dead_binder(fd, 0);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
/* Generate death notification */
test_binder_br_dead_binder(fd, ANY_THREAD, 0);
test_run(&test_opt, loop);
/* No registrations must have occured */
@@ -824,7 +854,6 @@ test_death_run()
gbinder_servicemanager_remove_all_handlers(sm, id);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -852,11 +881,10 @@ test_reanimate_quit(
} else {
const int fd = gbinder_driver_fd(sm->client->remote->ipc->driver);
/* Disable looper and reanimate the object */
/* Reanimate the object */
GDEBUG("Reanimating...");
test_binder_set_looper_enabled(fd, TEST_LOOPER_DISABLE);
test_binder_br_transaction_complete(fd);
test_binder_br_reply(fd, 0, 0, NULL);
test_binder_br_transaction_complete(fd, THIS_THREAD);
test_binder_br_reply(fd, THIS_THREAD, 0, 0, NULL);
}
}
@@ -866,7 +894,7 @@ test_reanimate(
void)
{
const char* dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
@@ -889,9 +917,8 @@ test_reanimate(
g_assert(id[1]);
g_assert(id[2]);
/* Generate death notification (need looper for that) */
test_binder_br_dead_binder(fd, 0);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
/* Generate death notification */
test_binder_br_dead_binder(fd, ANY_THREAD, 0);
test_run(&test_opt, loop);
/* No registrations must have occured */
@@ -904,7 +931,6 @@ test_reanimate(
gbinder_servicemanager_remove_all_handlers(sm, id);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -921,9 +947,9 @@ test_reuse(
const char* binder_dev = GBINDER_DEFAULT_BINDER;
const char* vndbinder_dev = "/dev/vpnbinder";
const char* hwbinder_dev = GBINDER_DEFAULT_HWBINDER;
GBinderIpc* binder_ipc = gbinder_ipc_new(binder_dev);
GBinderIpc* vndbinder_ipc = gbinder_ipc_new(vndbinder_dev);
GBinderIpc* hwbinder_ipc = gbinder_ipc_new(hwbinder_dev);
GBinderIpc* binder_ipc = gbinder_ipc_new(binder_dev, NULL);
GBinderIpc* vndbinder_ipc = gbinder_ipc_new(vndbinder_dev, NULL);
GBinderIpc* hwbinder_ipc = gbinder_ipc_new(hwbinder_dev, NULL);
GBinderServiceManager* m1;
GBinderServiceManager* m2;
GBinderServiceManager* vnd1;
@@ -963,7 +989,7 @@ test_reuse(
gbinder_ipc_unref(binder_ipc);
gbinder_ipc_unref(vndbinder_ipc);
gbinder_ipc_unref(hwbinder_ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -976,7 +1002,7 @@ test_notify_type(
GType t,
const char* dev)
{
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderServiceManager* sm;
TestHwServiceManager* test;
const char* name = "foo";
@@ -984,7 +1010,7 @@ test_notify_type(
gulong id1, id2;
test_setup_ping(ipc);
sm = gbinder_servicemanager_new_with_type(t, NULL);
sm = gbinder_servicemanager_new_with_type(t, NULL, NULL);
test = TEST_SERVICEMANAGER2(sm, t);
id1 = gbinder_servicemanager_add_registration_handler(sm, name,
test_registration_func_inc, &count);
@@ -1008,7 +1034,7 @@ test_notify_type(
gbinder_servicemanager_remove_handler(sm, id2);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
}
static
@@ -1044,7 +1070,7 @@ test_list(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
TestHwServiceManager* test;
@@ -1066,7 +1092,7 @@ test_list(
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -1093,7 +1119,7 @@ test_get(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
TestHwServiceManager* test;
@@ -1130,7 +1156,7 @@ test_get(
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -1155,7 +1181,7 @@ test_add(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServiceManager* sm;
TestHwServiceManager* test;
@@ -1178,7 +1204,7 @@ test_add(
gbinder_local_object_unref(obj);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2020-2021 Jolla Ltd.
* Copyright (C) 2020-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2020-2022 Jolla Ltd.
* Copyright (C) 2020-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -50,14 +50,32 @@ static TestOpt test_opt;
GType
gbinder_servicemanager_hidl_get_type()
{
/* Avoid pulling in gbinder_servicemanager_hidl object */
/* Dummy function to avoid pulling in gbinder_servicemanager_hidl */
g_assert_not_reached();
return 0;
}
GType
gbinder_servicemanager_aidl2_get_type()
{
/* Avoid pulling in gbinder_servicemanager_aidl2 object */
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl2 */
g_assert_not_reached();
return 0;
}
GType
gbinder_servicemanager_aidl3_get_type()
{
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl3 */
g_assert_not_reached();
return 0;
}
GType
gbinder_servicemanager_aidl4_get_type()
{
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl4 */
g_assert_not_reached();
return 0;
}
@@ -80,7 +98,6 @@ typedef GBinderLocalObjectClass ServiceManagerAidlClass;
typedef struct service_manager_aidl {
GBinderLocalObject parent;
GHashTable* objects;
gboolean handle_on_looper_thread;
} ServiceManagerAidl;
#define SERVICE_MANAGER_AIDL_TYPE (service_manager_aidl_get_type())
@@ -167,18 +184,15 @@ servicemanager_aidl_handler(
static
ServiceManagerAidl*
servicemanager_aidl_new(
const char* dev,
gboolean handle_on_looper_thread)
const char* dev)
{
ServiceManagerAidl* self = g_object_new(SERVICE_MANAGER_AIDL_TYPE, NULL);
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(self);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
self->handle_on_looper_thread = handle_on_looper_thread;
gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces,
servicemanager_aidl_handler, self);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_register_object(fd, obj, SVCMGR_HANDLE);
gbinder_ipc_register_local_object(ipc, obj);
gbinder_ipc_unref(ipc);
@@ -193,41 +207,6 @@ servicemanager_aidl_free(
gbinder_local_object_drop(GBINDER_LOCAL_OBJECT(self));
}
static
GBINDER_LOCAL_TRANSACTION_SUPPORT
service_manager_aidl_can_handle_transaction(
GBinderLocalObject* object,
const char* iface,
guint code)
{
ServiceManagerAidl* self = SERVICE_MANAGER_AIDL(object);
if (self->handle_on_looper_thread && !g_strcmp0(SVCMGR_IFACE, iface)) {
return GBINDER_LOCAL_TRANSACTION_LOOPER;
} else {
return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl_parent_class)->
can_handle_transaction(object, iface, code);
}
}
static
GBinderLocalReply*
service_manager_aidl_handle_looper_transaction(
GBinderLocalObject* object,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
if (!g_strcmp0(gbinder_remote_request_interface(req), SVCMGR_IFACE)) {
return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl_parent_class)->
handle_transaction(object, req, code, flags, status);
} else {
return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl_parent_class)->
handle_looper_transaction(object, req, code, flags, status);
}
}
static
void
service_manager_aidl_finalize(
@@ -253,14 +232,7 @@ void
service_manager_aidl_class_init(
ServiceManagerAidlClass* klass)
{
GObjectClass* object = G_OBJECT_CLASS(klass);
GBinderLocalObjectClass* local_object = GBINDER_LOCAL_OBJECT_CLASS(klass);
object->finalize = service_manager_aidl_finalize;
local_object->can_handle_transaction =
service_manager_aidl_can_handle_transaction;
local_object->handle_looper_transaction =
service_manager_aidl_handle_looper_transaction;
G_OBJECT_CLASS(klass)->finalize = service_manager_aidl_finalize;
}
/*==========================================================================*
@@ -311,9 +283,8 @@ void
test_get_run()
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
GBinderIpc* ipc = gbinder_ipc_new(dev);
ServiceManagerAidl* smsvc = servicemanager_aidl_new(other_dev, FALSE);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
ServiceManagerAidl* smsvc = servicemanager_aidl_new(dev);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
const char* name = "name";
@@ -322,7 +293,6 @@ test_get_run()
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
sm = gbinder_servicemanager_new(dev);
/* Query the object (it's not there yet) and wait for completion */
@@ -351,7 +321,6 @@ test_get_run()
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -393,9 +362,8 @@ void
test_list_run()
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
GBinderIpc* ipc = gbinder_ipc_new(dev);
ServiceManagerAidl* smsvc = servicemanager_aidl_new(other_dev, FALSE);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
ServiceManagerAidl* smsvc = servicemanager_aidl_new(dev);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
const char* name = "name";
@@ -407,7 +375,6 @@ test_list_run()
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
sm = gbinder_servicemanager_new(dev);
/* Request the list and wait for completion */
@@ -437,7 +404,6 @@ test_list_run()
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop);
g_strfreev(test.list);
@@ -472,9 +438,8 @@ void
test_notify_run()
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
GBinderIpc* ipc = gbinder_ipc_new(dev);
ServiceManagerAidl* svc = servicemanager_aidl_new(other_dev, FALSE);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
ServiceManagerAidl* svc = servicemanager_aidl_new(dev);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
const char* name = "name";
@@ -484,7 +449,6 @@ test_notify_run()
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
sm = gbinder_servicemanager_new(dev);
gbinder_ipc_set_max_threads(ipc, 1);
@@ -508,7 +472,6 @@ test_notify_run()
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -529,9 +492,8 @@ void
test_notify2_run()
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
GBinderIpc* ipc = gbinder_ipc_new(dev);
ServiceManagerAidl* smsvc = servicemanager_aidl_new(other_dev, TRUE);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
ServiceManagerAidl* smsvc = servicemanager_aidl_new(dev);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderServiceManager* sm;
@@ -542,7 +504,6 @@ test_notify2_run()
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
sm = gbinder_servicemanager_new(dev);
gbinder_ipc_set_max_threads(ipc, 1);
@@ -575,7 +536,6 @@ test_notify2_run()
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2020-2021 Jolla Ltd.
* Copyright (C) 2020-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2020-2022 Jolla Ltd.
* Copyright (C) 2020-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -53,7 +53,8 @@ static const char TMP_DIR_TEMPLATE[] =
GType
gbinder_servicemanager_hidl_get_type()
{
/* Avoid pulling in gbinder_servicemanager_hidl object */
/* Dummy function to avoid pulling in gbinder_servicemanager_hidl */
g_assert_not_reached();
return 0;
}
@@ -76,7 +77,6 @@ typedef GBinderLocalObjectClass ServiceManagerAidl2Class;
typedef struct service_manager_aidl2 {
GBinderLocalObject parent;
GHashTable* objects;
gboolean handle_on_looper_thread;
} ServiceManagerAidl2;
#define SERVICE_MANAGER_AIDL2_TYPE (service_manager_aidl2_get_type())
@@ -169,59 +169,21 @@ servicemanager_aidl2_handler(
static
ServiceManagerAidl2*
servicemanager_aidl2_new(
const char* dev,
gboolean handle_on_looper_thread)
const char* dev)
{
ServiceManagerAidl2* self = g_object_new(SERVICE_MANAGER_AIDL2_TYPE, NULL);
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(self);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
self->handle_on_looper_thread = handle_on_looper_thread;
gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces,
servicemanager_aidl2_handler, self);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_register_object(fd, obj, SVCMGR_HANDLE);
gbinder_ipc_register_local_object(ipc, obj);
gbinder_ipc_unref(ipc);
return self;
}
static
GBINDER_LOCAL_TRANSACTION_SUPPORT
service_manager_aidl2_can_handle_transaction(
GBinderLocalObject* object,
const char* iface,
guint code)
{
ServiceManagerAidl2* self = SERVICE_MANAGER_AIDL2(object);
if (self->handle_on_looper_thread && !g_strcmp0(SVCMGR_IFACE, iface)) {
return GBINDER_LOCAL_TRANSACTION_LOOPER;
} else {
return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl2_parent_class)->
can_handle_transaction(object, iface, code);
}
}
static
GBinderLocalReply*
service_manager_aidl2_handle_looper_transaction(
GBinderLocalObject* object,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
if (!g_strcmp0(gbinder_remote_request_interface(req), SVCMGR_IFACE)) {
return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl2_parent_class)->
handle_transaction(object, req, code, flags, status);
} else {
return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl2_parent_class)->
handle_looper_transaction(object, req, code, flags, status);
}
}
static
void
service_manager_aidl2_finalize(
@@ -247,14 +209,7 @@ void
service_manager_aidl2_class_init(
ServiceManagerAidl2Class* klass)
{
GObjectClass* object = G_OBJECT_CLASS(klass);
GBinderLocalObjectClass* local_object = GBINDER_LOCAL_OBJECT_CLASS(klass);
object->finalize = service_manager_aidl2_finalize;
local_object->can_handle_transaction =
service_manager_aidl2_can_handle_transaction;
local_object->handle_looper_transaction =
service_manager_aidl2_handle_looper_transaction;
G_OBJECT_CLASS(klass)->finalize = service_manager_aidl2_finalize;
}
/*==========================================================================*
@@ -270,6 +225,7 @@ typedef struct test_context {
GBinderLocalObject* object;
ServiceManagerAidl2* service;
GBinderServiceManager* client;
GMainLoop* loop;
int fd;
} TestContext;
@@ -279,11 +235,6 @@ test_context_init(
TestContext* test)
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* other_dev = GBINDER_DEFAULT_BINDER "-private";
/*
* Also set defaults so that both /dev/binder and /dev/binder-private
* use the same protocol.
*/
const char* config =
"[Protocol]\n"
"Default = aidl2\n"
@@ -304,16 +255,13 @@ test_context_init(
gbinder_config_dir = test->config_subdir; /* Doesn't exist */
gbinder_config_file = test->config_file;
ipc = gbinder_ipc_new(dev);
ipc = gbinder_ipc_new(dev, NULL);
test->fd = gbinder_driver_fd(ipc->driver);
test->object = gbinder_local_object_new(ipc, NULL, NULL, NULL);
/* Set up binder simulator */
test_binder_register_object(test->fd, test->object, AUTO_HANDLE);
test_binder_set_passthrough(test->fd, TRUE);
test->service = servicemanager_aidl2_new(other_dev, TRUE);
test->service = servicemanager_aidl2_new(dev);
test->client = gbinder_servicemanager_new(dev);
test->loop = g_main_loop_new(NULL, FALSE);
gbinder_ipc_unref(ipc);
}
@@ -322,22 +270,47 @@ void
test_context_deinit(
TestContext* test)
{
test_binder_unregister_objects(test->fd);
test_binder_br_dead_binder_obj(test->fd, test->object);
gbinder_local_object_unref(test->object);
gbinder_local_object_drop(GBINDER_LOCAL_OBJECT(test->service));
gbinder_servicemanager_unref(test->client);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, NULL);
test_binder_exit_wait(&test_opt, test->loop);
remove(test->config_file);
remove(test->config_dir);
g_free(test->config_file);
g_free(test->config_subdir);
g_free(test->config_dir);
g_main_loop_unref(test->loop);
gbinder_config_dir = test->default_config_dir;
gbinder_config_file = test->default_config_file;
gbinder_config_exit();
}
static
void
test_context_wait_ref_cb(
GBinderLocalObject* obj,
void* user_data)
{
GDEBUG("strong_refs %d", obj->strong_refs);
if (obj->strong_refs > 0) {
test_quit_later((GMainLoop*)user_data);
}
}
static
void
test_context_wait_ref(
TestContext* test)
{
/* Wait until the object gets referenced by servicemanager */
gulong id = gbinder_local_object_add_strong_refs_changed_handler
(test->object, test_context_wait_ref_cb, test->loop);
test_run(&test_opt, test->loop);
gbinder_local_object_remove_handler(test->object, id);
}
/*==========================================================================*
* get
*==========================================================================*/
@@ -366,12 +339,16 @@ test_get_run()
g_assert_cmpuint(g_hash_table_size(test.service->objects), == ,1);
g_assert(g_hash_table_contains(test.service->objects, name));
/* Wait until the object gets referenced by servicemanager */
test_context_wait_ref(&test);
/* Query the object (this time it must be there) */
GDEBUG("Querying '%s' again", name);
g_assert(gbinder_servicemanager_get_service_sync(test.client, name,
&status));
g_assert_cmpint(status, == ,GBINDER_STATUS_OK);
GDEBUG("Done");
test_context_deinit(&test);
}
@@ -409,6 +386,9 @@ test_list_run()
g_assert_cmpint(gbinder_servicemanager_add_service_sync(test.client,
name, test.object), == ,GBINDER_STATUS_OK);
/* Wait until the object gets referenced by servicemanager */
test_context_wait_ref(&test);
/* Request the list again */
list = gbinder_servicemanager_list_sync(test.client);
@@ -417,6 +397,7 @@ test_list_run()
g_assert_cmpstr(list[0], == ,name);
g_strfreev(list);
GDEBUG("Done");
test_context_deinit(&test);
}

View File

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

View File

@@ -0,0 +1,444 @@
/*
* Copyright (C) 2020-2022 Jolla Ltd.
* Copyright (C) 2020-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_binder.h"
#include "gbinder_driver.h"
#include "gbinder_config.h"
#include "gbinder_ipc.h"
#include "gbinder_reader.h"
#include "gbinder_servicemanager_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply.h"
#include "gbinder_remote_request.h"
#include "gbinder_remote_object.h"
#include "gbinder_writer.h"
#include <gutil_strv.h>
#include <gutil_log.h>
static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] =
"gbinder-test-servicemanager_aidl3-XXXXXX";
GType
gbinder_servicemanager_hidl_get_type()
{
/* Dummy function to avoid pulling in gbinder_servicemanager_hidl */
g_assert_not_reached();
return 0;
}
/*==========================================================================*
* Test service manager
*==========================================================================*/
#define SVCMGR_HANDLE (0)
static const char SVCMGR_IFACE[] = "android.os.IServiceManager";
enum servicemanager_aidl_tx {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
const char* const servicemanager_aidl_ifaces[] = { SVCMGR_IFACE, NULL };
typedef GBinderLocalObjectClass ServiceManagerAidl3Class;
typedef struct service_manager_aidl3 {
GBinderLocalObject parent;
GHashTable* objects;
} ServiceManagerAidl3;
#define SERVICE_MANAGER_AIDL3_TYPE (service_manager_aidl3_get_type())
#define SERVICE_MANAGER_AIDL3(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
SERVICE_MANAGER_AIDL3_TYPE, ServiceManagerAidl3))
G_DEFINE_TYPE(ServiceManagerAidl3, service_manager_aidl3, \
GBINDER_TYPE_LOCAL_OBJECT)
static
GBinderLocalReply*
servicemanager_aidl3_handler(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
ServiceManagerAidl3* self = user_data;
GBinderLocalReply* reply = NULL;
GBinderReader reader;
GBinderRemoteObject* remote_obj;
guint32 allow_isolated, dumpsys_priority;
char* str;
g_assert(!flags);
GDEBUG("%s %u", gbinder_remote_request_interface(req), code);
g_assert_cmpstr(gbinder_remote_request_interface(req), == ,SVCMGR_IFACE);
*status = -1;
switch (code) {
case GET_SERVICE_TRANSACTION:
case CHECK_SERVICE_TRANSACTION:
gbinder_remote_request_init_reader(req, &reader);
str = gbinder_reader_read_string16(&reader);
if (str) {
GBinderWriter writer;
remote_obj = g_hash_table_lookup(self->objects, str);
reply = gbinder_local_object_new_reply(obj);
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_remote_object(&writer, remote_obj);
if (remote_obj) {
GDEBUG("Found name '%s' => %p", str, remote_obj);
} else {
GDEBUG("Name '%s' not found", str);
}
g_free(str);
}
break;
case ADD_SERVICE_TRANSACTION:
gbinder_remote_request_init_reader(req, &reader);
str = gbinder_reader_read_string16(&reader);
remote_obj = gbinder_reader_read_object(&reader);
if (str && remote_obj &&
gbinder_reader_read_uint32(&reader, &allow_isolated) &&
gbinder_reader_read_uint32(&reader, &dumpsys_priority)) {
GDEBUG("Adding '%s'", str);
g_hash_table_replace(self->objects, str, remote_obj);
remote_obj = NULL;
str = NULL;
reply = gbinder_local_object_new_reply(obj);
*status = GBINDER_STATUS_OK;
}
g_free(str);
gbinder_remote_object_unref(remote_obj);
break;
case LIST_SERVICES_TRANSACTION:
gbinder_remote_request_init_reader(req, &reader);
if (gbinder_reader_read_uint32(&reader, &dumpsys_priority)) {
if (g_hash_table_size(self->objects) == 1) {
GList* keys = g_hash_table_get_keys(self->objects);
GList* l = g_list_nth(keys, 0);
gint32 srv_size = 1;
GBinderWriter writer;
reply = gbinder_local_object_new_reply(obj);
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_int32(&writer, srv_size);
gbinder_writer_append_string16(&writer, l->data);
g_list_free(keys);
*status = GBINDER_STATUS_OK;
} else {
GDEBUG("Incorrect number of services %u",
g_hash_table_size(self->objects));
}
}
break;
default:
GDEBUG("Unhandled command %u", code);
break;
}
return reply;
}
static
ServiceManagerAidl3*
servicemanager_aidl3_new(
const char* dev)
{
ServiceManagerAidl3* self = g_object_new(SERVICE_MANAGER_AIDL3_TYPE, NULL);
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(self);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces,
servicemanager_aidl3_handler, self);
test_binder_register_object(fd, obj, SVCMGR_HANDLE);
gbinder_ipc_register_local_object(ipc, obj);
gbinder_ipc_unref(ipc);
return self;
}
static
void
service_manager_aidl3_finalize(
GObject* object)
{
ServiceManagerAidl3* self = SERVICE_MANAGER_AIDL3(object);
g_hash_table_destroy(self->objects);
G_OBJECT_CLASS(service_manager_aidl3_parent_class)->finalize(object);
}
static
void
service_manager_aidl3_init(
ServiceManagerAidl3* self)
{
self->objects = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify) gbinder_remote_object_unref);
}
static
void
service_manager_aidl3_class_init(
ServiceManagerAidl3Class* klass)
{
G_OBJECT_CLASS(klass)->finalize = service_manager_aidl3_finalize;
}
/*==========================================================================*
* Test context
*==========================================================================*/
typedef struct test_context {
const char* default_config_dir;
const char* default_config_file;
char* config_dir;
char* config_subdir;
char* config_file;
GBinderLocalObject* object;
ServiceManagerAidl3* service;
GBinderServiceManager* client;
GMainLoop* loop;
int fd;
} TestContext;
static
void
test_context_init(
TestContext* test)
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* config =
"[Protocol]\n"
"Default = aidl3\n"
"/dev/binder = aidl3\n"
"[ServiceManager]\n"
"Default = aidl3\n"
"/dev/binder = aidl3\n";
GBinderIpc* ipc;
memset(test, 0, sizeof(*test));
test->default_config_dir = gbinder_config_dir;
test->default_config_file = gbinder_config_file;
test->config_dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
test->config_subdir = g_build_filename(test->config_dir, "d", NULL);
test->config_file = g_build_filename(test->config_dir, "test.conf", NULL);
g_assert(g_file_set_contents(test->config_file, config, -1, NULL));
GDEBUG("Config file %s", test->config_file);
gbinder_config_dir = test->config_subdir; /* Doesn't exist */
gbinder_config_file = test->config_file;
ipc = gbinder_ipc_new(dev, NULL);
test->fd = gbinder_driver_fd(ipc->driver);
test->object = gbinder_local_object_new(ipc, NULL, NULL, NULL);
test_binder_register_object(test->fd, test->object, AUTO_HANDLE);
test->service = servicemanager_aidl3_new(dev);
test->client = gbinder_servicemanager_new(dev);
test->loop = g_main_loop_new(NULL, FALSE);
gbinder_ipc_unref(ipc);
}
static
void
test_context_deinit(
TestContext* test)
{
test_binder_br_dead_binder_obj(test->fd, test->object);
gbinder_local_object_unref(test->object);
gbinder_local_object_drop(GBINDER_LOCAL_OBJECT(test->service));
gbinder_servicemanager_unref(test->client);
test_binder_exit_wait(&test_opt, test->loop);
remove(test->config_file);
remove(test->config_dir);
g_free(test->config_file);
g_free(test->config_subdir);
g_free(test->config_dir);
g_main_loop_unref(test->loop);
gbinder_config_dir = test->default_config_dir;
gbinder_config_file = test->default_config_file;
gbinder_config_exit();
}
static
void
test_context_wait_ref_cb(
GBinderLocalObject* obj,
void* user_data)
{
GDEBUG("strong_refs %d", obj->strong_refs);
if (obj->strong_refs > 0) {
test_quit_later((GMainLoop*)user_data);
}
}
static
void
test_context_wait_ref(
TestContext* test)
{
/* Wait until the object gets referenced by servicemanager */
gulong id = gbinder_local_object_add_strong_refs_changed_handler
(test->object, test_context_wait_ref_cb, test->loop);
test_run(&test_opt, test->loop);
gbinder_local_object_remove_handler(test->object, id);
}
/*==========================================================================*
* get
*==========================================================================*/
static
void
test_get_run()
{
TestContext test;
const char* name = "name";
int status = -1;
test_context_init(&test);
/* Query the object (it's not there yet) */
GDEBUG("Querying '%s'", name);
g_assert(!gbinder_servicemanager_get_service_sync(test.client,
name, &status));
g_assert_cmpint(status, == ,GBINDER_STATUS_OK);
/* Register object */
GDEBUG("Registering object '%s' => %p", name, test.object);
g_assert_cmpint(gbinder_servicemanager_add_service_sync(test.client,
name, test.object), == ,GBINDER_STATUS_OK);
g_assert_cmpuint(g_hash_table_size(test.service->objects), == ,1);
g_assert(g_hash_table_contains(test.service->objects, name));
/* Wait until the object gets referenced by servicemanager */
test_context_wait_ref(&test);
/* Query the object (this time it must be there) */
GDEBUG("Querying '%s' again", name);
g_assert(gbinder_servicemanager_get_service_sync(test.client, name,
&status));
g_assert_cmpint(status, == ,GBINDER_STATUS_OK);
GDEBUG("Done");
test_context_deinit(&test);
}
static
void
test_get()
{
test_run_in_context(&test_opt, test_get_run);
}
/*==========================================================================*
* list
*==========================================================================*/
static
void
test_list_run()
{
TestContext test;
const char* name = "name";
char** list;
test_context_init(&test);
/* Request the list */
list = gbinder_servicemanager_list_sync(test.client);
/* There's nothing there yet */
g_assert(list);
g_assert(!list[0]);
g_strfreev(list);
/* Register object */
GDEBUG("Registering object '%s' => %p", name, test.object);
g_assert_cmpint(gbinder_servicemanager_add_service_sync(test.client,
name, test.object), == ,GBINDER_STATUS_OK);
/* Wait until the object gets referenced by servicemanager */
test_context_wait_ref(&test);
/* Request the list again */
list = gbinder_servicemanager_list_sync(test.client);
/* Now the name must be there */
g_assert_cmpuint(gutil_strv_length(list), == ,1);
g_assert_cmpstr(list[0], == ,name);
g_strfreev(list);
GDEBUG("Done");
test_context_deinit(&test);
}
static
void
test_list()
{
test_run_in_context(&test_opt, test_list_run);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_(t) "/servicemanager_aidl3/" t
int main(int argc, char* argv[])
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
g_type_init();
G_GNUC_END_IGNORE_DEPRECATIONS;
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("get"), test_get);
g_test_add_func(TEST_("list"), test_list);
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_servicemanager_aidl4
include ../common/Makefile

View File

@@ -0,0 +1,449 @@
/*
* Copyright (C) 2020-2022 Jolla Ltd.
* Copyright (C) 2020-2022 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2023 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_binder.h"
#include "gbinder_driver.h"
#include "gbinder_config.h"
#include "gbinder_ipc.h"
#include "gbinder_reader.h"
#include "gbinder_servicemanager_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply.h"
#include "gbinder_remote_request.h"
#include "gbinder_remote_object.h"
#include "gbinder_writer.h"
#include <gutil_strv.h>
#include <gutil_log.h>
static TestOpt test_opt;
static const char TMP_DIR_TEMPLATE[] =
"gbinder-test-servicemanager_aidl4-XXXXXX";
GType
gbinder_servicemanager_hidl_get_type()
{
/* Dummy function to avoid pulling in gbinder_servicemanager_hidl */
g_assert_not_reached();
return 0;
}
/*==========================================================================*
* Test service manager
*==========================================================================*/
#define SVCMGR_HANDLE (0)
static const char SVCMGR_IFACE[] = "android.os.IServiceManager";
enum servicemanager_aidl_tx {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
const char* const servicemanager_aidl_ifaces[] = { SVCMGR_IFACE, NULL };
typedef GBinderLocalObjectClass ServiceManagerAidl4Class;
typedef struct service_manager_aidl4 {
GBinderLocalObject parent;
GHashTable* objects;
} ServiceManagerAidl4;
#define SERVICE_MANAGER_AIDL4_TYPE (service_manager_aidl4_get_type())
#define SERVICE_MANAGER_AIDL4(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
SERVICE_MANAGER_AIDL4_TYPE, ServiceManagerAidl4))
G_DEFINE_TYPE(ServiceManagerAidl4, service_manager_aidl4, \
GBINDER_TYPE_LOCAL_OBJECT)
static
GBinderLocalReply*
servicemanager_aidl4_handler(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
ServiceManagerAidl4* self = user_data;
GBinderLocalReply* reply = NULL;
GBinderReader reader;
GBinderRemoteObject* remote_obj;
guint32 allow_isolated, dumpsys_priority;
char* str;
g_assert(!flags);
GDEBUG("%s %u", gbinder_remote_request_interface(req), code);
g_assert_cmpstr(gbinder_remote_request_interface(req), == ,SVCMGR_IFACE);
*status = -1;
switch (code) {
case GET_SERVICE_TRANSACTION:
case CHECK_SERVICE_TRANSACTION:
gbinder_remote_request_init_reader(req, &reader);
str = gbinder_reader_read_string16(&reader);
if (str) {
reply = gbinder_local_object_new_reply(obj);
remote_obj = g_hash_table_lookup(self->objects, str);
if (str) {
GBinderWriter writer;
remote_obj = g_hash_table_lookup(self->objects, str);
reply = gbinder_local_object_new_reply(obj);
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_remote_object(&writer, remote_obj);
if (remote_obj) {
GDEBUG("Found name '%s' => %p", str, remote_obj);
} else {
GDEBUG("Name '%s' not found", str);
}
g_free(str);
}
}
break;
case ADD_SERVICE_TRANSACTION:
gbinder_remote_request_init_reader(req, &reader);
str = gbinder_reader_read_string16(&reader);
remote_obj = gbinder_reader_read_object(&reader);
if (str && remote_obj &&
/* This field should be eventually handled at lower level. */
gbinder_reader_read_uint32(&reader, NULL) &&
gbinder_reader_read_uint32(&reader, &allow_isolated) &&
gbinder_reader_read_uint32(&reader, &dumpsys_priority)) {
GDEBUG("Adding '%s'", str);
g_hash_table_replace(self->objects, str, remote_obj);
remote_obj = NULL;
str = NULL;
reply = gbinder_local_object_new_reply(obj);
*status = GBINDER_STATUS_OK;
}
g_free(str);
gbinder_remote_object_unref(remote_obj);
break;
case LIST_SERVICES_TRANSACTION:
gbinder_remote_request_init_reader(req, &reader);
if (gbinder_reader_read_uint32(&reader, &dumpsys_priority)) {
if (g_hash_table_size(self->objects) == 1) {
GList* keys = g_hash_table_get_keys(self->objects);
GList* l = g_list_nth(keys, 0);
gint32 srv_size = 1;
GBinderWriter writer;
reply = gbinder_local_object_new_reply(obj);
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_int32(&writer, srv_size);
gbinder_writer_append_string16(&writer, l->data);
g_list_free(keys);
*status = GBINDER_STATUS_OK;
} else {
GDEBUG("Incorrect number of services %u",
g_hash_table_size(self->objects));
}
}
break;
default:
GDEBUG("Unhandled command %u", code);
break;
}
return reply;
}
static
ServiceManagerAidl4*
servicemanager_aidl4_new(
const char* dev)
{
ServiceManagerAidl4* self = g_object_new(SERVICE_MANAGER_AIDL4_TYPE, NULL);
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(self);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces,
servicemanager_aidl4_handler, self);
test_binder_register_object(fd, obj, SVCMGR_HANDLE);
gbinder_ipc_register_local_object(ipc, obj);
gbinder_ipc_unref(ipc);
return self;
}
static
void
service_manager_aidl4_finalize(
GObject* object)
{
ServiceManagerAidl4* self = SERVICE_MANAGER_AIDL4(object);
g_hash_table_destroy(self->objects);
G_OBJECT_CLASS(service_manager_aidl4_parent_class)->finalize(object);
}
static
void
service_manager_aidl4_init(
ServiceManagerAidl4* self)
{
self->objects = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify) gbinder_remote_object_unref);
}
static
void
service_manager_aidl4_class_init(
ServiceManagerAidl4Class* klass)
{
G_OBJECT_CLASS(klass)->finalize = service_manager_aidl4_finalize;
}
/*==========================================================================*
* Test context
*==========================================================================*/
typedef struct test_context {
const char* default_config_dir;
const char* default_config_file;
char* config_dir;
char* config_subdir;
char* config_file;
GBinderLocalObject* object;
ServiceManagerAidl4* service;
GBinderServiceManager* client;
GMainLoop* loop;
int fd;
} TestContext;
static
void
test_context_init(
TestContext* test)
{
const char* dev = GBINDER_DEFAULT_BINDER;
const char* config =
"[Protocol]\n"
"Default = aidl3\n"
"/dev/binder = aidl3\n"
"[ServiceManager]\n"
"Default = aidl4\n"
"/dev/binder = aidl4\n";
GBinderIpc* ipc;
memset(test, 0, sizeof(*test));
test->default_config_dir = gbinder_config_dir;
test->default_config_file = gbinder_config_file;
test->config_dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL);
test->config_subdir = g_build_filename(test->config_dir, "d", NULL);
test->config_file = g_build_filename(test->config_dir, "test.conf", NULL);
g_assert(g_file_set_contents(test->config_file, config, -1, NULL));
GDEBUG("Config file %s", test->config_file);
gbinder_config_dir = test->config_subdir; /* Doesn't exist */
gbinder_config_file = test->config_file;
ipc = gbinder_ipc_new(dev, NULL);
test->fd = gbinder_driver_fd(ipc->driver);
test->object = gbinder_local_object_new(ipc, NULL, NULL, NULL);
test_binder_register_object(test->fd, test->object, AUTO_HANDLE);
test->service = servicemanager_aidl4_new(dev);
test->client = gbinder_servicemanager_new(dev);
test->loop = g_main_loop_new(NULL, FALSE);
gbinder_ipc_unref(ipc);
}
static
void
test_context_deinit(
TestContext* test)
{
test_binder_unregister_objects(test->fd);
gbinder_local_object_unref(test->object);
gbinder_local_object_drop(GBINDER_LOCAL_OBJECT(test->service));
gbinder_servicemanager_unref(test->client);
test_binder_exit_wait(&test_opt, test->loop);
remove(test->config_file);
remove(test->config_dir);
g_free(test->config_file);
g_free(test->config_subdir);
g_free(test->config_dir);
g_main_loop_unref(test->loop);
gbinder_config_dir = test->default_config_dir;
gbinder_config_file = test->default_config_file;
gbinder_config_exit();
}
static
void
test_context_wait_ref_cb(
GBinderLocalObject* obj,
void* user_data)
{
GDEBUG("strong_refs %d", obj->strong_refs);
if (obj->strong_refs > 0) {
test_quit_later((GMainLoop*)user_data);
}
}
static
void
test_context_wait_ref(
TestContext* test)
{
/* Wait until the object gets referenced by servicemanager */
gulong id = gbinder_local_object_add_strong_refs_changed_handler
(test->object, test_context_wait_ref_cb, test->loop);
test_run(&test_opt, test->loop);
gbinder_local_object_remove_handler(test->object, id);
}
/*==========================================================================*
* get
*==========================================================================*/
static
void
test_get_run()
{
TestContext test;
const char* name = "name";
int status = -1;
test_context_init(&test);
/* Query the object (it's not there yet) */
GDEBUG("Querying '%s'", name);
g_assert(!gbinder_servicemanager_get_service_sync(test.client,
name, &status));
g_assert_cmpint(status, == ,GBINDER_STATUS_OK);
/* Register object */
GDEBUG("Registering object '%s' => %p", name, test.object);
g_assert_cmpint(gbinder_servicemanager_add_service_sync(test.client,
name, test.object), == ,GBINDER_STATUS_OK);
g_assert_cmpuint(g_hash_table_size(test.service->objects), == ,1);
g_assert(g_hash_table_contains(test.service->objects, name));
/* Wait until the object gets referenced by servicemanager */
test_context_wait_ref(&test);
/* Query the object (this time it must be there) */
GDEBUG("Querying '%s' again", name);
g_assert(gbinder_servicemanager_get_service_sync(test.client, name,
&status));
g_assert_cmpint(status, == ,GBINDER_STATUS_OK);
test_context_deinit(&test);
}
static
void
test_get()
{
test_run_in_context(&test_opt, test_get_run);
}
/*==========================================================================*
* list
*==========================================================================*/
static
void
test_list_run()
{
TestContext test;
const char* name = "name";
char** list;
test_context_init(&test);
/* Request the list */
list = gbinder_servicemanager_list_sync(test.client);
/* There's nothing there yet */
g_assert(list);
g_assert(!list[0]);
g_strfreev(list);
/* Register object */
GDEBUG("Registering object '%s' => %p", name, test.object);
g_assert_cmpint(gbinder_servicemanager_add_service_sync(test.client,
name, test.object), == ,GBINDER_STATUS_OK);
/* Wait until the object gets referenced by servicemanager */
test_context_wait_ref(&test);
/* Request the list again */
list = gbinder_servicemanager_list_sync(test.client);
/* Now the name must be there */
g_assert_cmpuint(gutil_strv_length(list), == ,1);
g_assert_cmpstr(list[0], == ,name);
g_strfreev(list);
test_context_deinit(&test);
}
static
void
test_list()
{
test_run_in_context(&test_opt, test_list_run);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_(t) "/servicemanager_aidl4/" t
int main(int argc, char* argv[])
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
g_type_init();
G_GNUC_END_IGNORE_DEPRECATIONS;
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("get"), test_get);
g_test_add_func(TEST_("list"), test_list);
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) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -43,15 +43,13 @@
#include <gutil_strv.h>
static TestOpt test_opt;
#define MAIN_DEV GBINDER_DEFAULT_HWBINDER
#define OTHER_DEV GBINDER_DEFAULT_HWBINDER "-private"
#define DEV GBINDER_DEFAULT_HWBINDER
static const char TMP_DIR_TEMPLATE[] = "gbinder-test-svcmgr-hidl-XXXXXX";
static const char DEFAULT_CONFIG_DATA[] =
"[Protocol]\n"
MAIN_DEV " = hidl\n"
OTHER_DEV " = hidl\n"
DEV " = hidl\n"
"[ServiceManager]\n"
MAIN_DEV " = hidl\n";
DEV " = hidl\n";
typedef struct test_config {
char* dir;
@@ -61,14 +59,32 @@ typedef struct test_config {
GType
gbinder_servicemanager_aidl_get_type()
{
/* Avoid pulling in gbinder_servicemanager_aidl object */
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl */
g_assert_not_reached();
return 0;
}
GType
gbinder_servicemanager_aidl2_get_type()
{
/* Avoid pulling in gbinder_servicemanager_aidl2 object */
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl2 */
g_assert_not_reached();
return 0;
}
GType
gbinder_servicemanager_aidl3_get_type()
{
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl3 */
g_assert_not_reached();
return 0;
}
GType
gbinder_servicemanager_aidl4_get_type()
{
/* Dummy function to avoid pulling in gbinder_servicemanager_aidl4 */
g_assert_not_reached();
return 0;
}
@@ -112,11 +128,10 @@ TestServiceManagerHidl*
test_servicemanager_impl_new(
const char* dev)
{
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
TestServiceManagerHidl* sm = test_servicemanager_hidl_new(ipc);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
test_binder_register_object(fd, GBINDER_LOCAL_OBJECT(sm),
GBINDER_SERVICEMANAGER_HANDLE);
gbinder_ipc_unref(ipc);
@@ -181,16 +196,14 @@ test_get_run()
const char* name = "android.hidl.base@1.0::IBase/test";
test_config_init(&config, NULL);
ipc = gbinder_ipc_new(MAIN_DEV);
smsvc = test_servicemanager_impl_new(OTHER_DEV);
ipc = gbinder_ipc_new(DEV, NULL);
smsvc = test_servicemanager_impl_new(DEV);
obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
fd = gbinder_driver_fd(ipc->driver);
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
sm = gbinder_servicemanager_new(MAIN_DEV);
sm = gbinder_servicemanager_new(DEV);
/* This one fails because of unexpected name format */
g_assert(!gbinder_servicemanager_get_service_sync(sm, "test", NULL));
@@ -215,13 +228,11 @@ test_get_run()
g_assert(gbinder_servicemanager_get_service(sm, name, test_get_cb, loop));
test_run(&test_opt, loop);
test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj);
test_servicemanager_hidl_free(smsvc);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
test_config_deinit(&config);
g_main_loop_unref(loop);
@@ -276,16 +287,14 @@ test_list_run()
test.loop = g_main_loop_new(NULL, FALSE);
test_config_init(&config, NULL);
ipc = gbinder_ipc_new(MAIN_DEV);
smsvc = test_servicemanager_impl_new(OTHER_DEV);
ipc = gbinder_ipc_new(DEV, NULL);
smsvc = test_servicemanager_impl_new(DEV);
obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
fd = gbinder_driver_fd(ipc->driver);
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
sm = gbinder_servicemanager_new(MAIN_DEV);
sm = gbinder_servicemanager_new(DEV);
/* Request the list and wait for completion */
g_assert(gbinder_servicemanager_list(sm, test_list_cb, &test));
@@ -308,13 +317,11 @@ test_list_run()
g_assert_cmpuint(gutil_strv_length(test.list), == ,1);
g_assert_cmpstr(test.list[0], == ,name);
test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj);
test_servicemanager_hidl_free(smsvc);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop);
test_config_deinit(&config);
@@ -404,16 +411,14 @@ test_notify_run()
test.loop = g_main_loop_new(NULL, FALSE);
test_config_init(&config, NULL);
ipc = gbinder_ipc_new(MAIN_DEV);
test.smsvc = test_servicemanager_impl_new(OTHER_DEV);
ipc = gbinder_ipc_new(DEV, NULL);
test.smsvc = test_servicemanager_impl_new(DEV);
obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
fd = gbinder_driver_fd(ipc->driver);
/* Set up binder simulator */
test_binder_register_object(fd, obj, AUTO_HANDLE);
test_binder_set_passthrough(fd, TRUE);
test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE);
sm = gbinder_servicemanager_new(MAIN_DEV);
sm = gbinder_servicemanager_new(DEV);
/* This one fails because of invalid names */
g_assert(!gbinder_servicemanager_add_registration_handler(sm, NULL,
@@ -437,13 +442,11 @@ test_notify_run()
test_run(&test_opt, test.loop);
gbinder_servicemanager_remove_handler(sm, id);
test_binder_unregister_objects(fd);
gbinder_local_object_unref(obj);
test_servicemanager_hidl_free(test.smsvc);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, test.loop);
test_config_deinit(&config);
g_main_loop_unref(test.loop);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2019-2021 Jolla Ltd.
* Copyright (C) 2019-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2019-2022 Jolla Ltd.
* Copyright (C) 2019-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -62,9 +62,9 @@ test_setup_ping(
{
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);
test_binder_br_noop(fd, THIS_THREAD);
test_binder_br_transaction_complete(fd, THIS_THREAD);
test_binder_br_reply(fd, THIS_THREAD, 0, 0, NULL);
}
/*==========================================================================*
@@ -145,7 +145,7 @@ test_servicemanager_add_service(
}
} else {
test_binder_br_dead_binder(gbinder_driver_fd(obj->ipc->driver),
GBINDER_SERVICEMANAGER_HANDLE);
ANY_THREAD, GBINDER_SERVICEMANAGER_HANDLE);
}
}
}
@@ -234,6 +234,18 @@ gbinder_servicemanager_aidl2_get_type()
return TEST_TYPE_SERVICEMANAGER;
}
GType
gbinder_servicemanager_aidl3_get_type()
{
return TEST_TYPE_SERVICEMANAGER;
}
GType
gbinder_servicemanager_aidl4_get_type()
{
return TEST_TYPE_SERVICEMANAGER;
}
GType
gbinder_servicemanager_hidl_get_type()
{
@@ -250,7 +262,7 @@ test_null(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderServiceManager* sm;
test_setup_ping(ipc);
@@ -277,7 +289,7 @@ test_basic(
const char* obj_name = "test";
const char* dev = GBINDER_DEFAULT_BINDER;
const char* const ifaces[] = { "interface", NULL };
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj;
GBinderServiceManager* sm;
@@ -299,7 +311,7 @@ test_basic(
gbinder_local_object_unref(obj);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -315,7 +327,7 @@ test_present(
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
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;
@@ -333,8 +345,7 @@ test_present(
g_assert_cmpstr(sn->name, == ,obj_name);
/* Immediately generate death notification (need looper for that) */
test_binder_br_dead_binder(fd, GBINDER_SERVICEMANAGER_HANDLE);
test_binder_set_looper_enabled(fd, TRUE);
test_binder_br_dead_binder(fd, ANY_THREAD, GBINDER_SERVICEMANAGER_HANDLE);
id = gbinder_servicemanager_add_presence_handler(sm, test_quit, loop);
test_run(&test_opt, loop);
@@ -343,7 +354,6 @@ test_present(
gbinder_servicemanager_remove_handler(sm, id);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -376,7 +386,7 @@ test_not_present(
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
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;
@@ -385,7 +395,7 @@ test_not_present(
gulong id;
/* This makes presence detection PING fail */
test_binder_br_reply_status(fd, -1);
test_binder_br_reply_status(fd, THIS_THREAD, -1);
sm = gbinder_servicemanager_new(dev);
g_assert(!gbinder_servicemanager_is_present(sm));
id = gbinder_servicemanager_add_presence_handler(sm, test_quit, loop);
@@ -396,8 +406,8 @@ test_not_present(
g_assert_cmpstr(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_binder_br_transaction_complete(fd, THIS_THREAD);
test_binder_br_reply(fd, THIS_THREAD, 0, 0, NULL);
test_run(&test_opt, loop);
gbinder_servicename_unref(sn);
@@ -405,7 +415,7 @@ test_not_present(
gbinder_servicemanager_remove_handler(sm, id);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -421,8 +431,7 @@ test_retry(
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj;
GBinderServiceManager* sm;
@@ -438,8 +447,6 @@ test_retry(
g_assert(sn);
g_assert_cmpstr(sn->name, == ,obj_name);
/* Need looper for death notifications */
test_binder_set_looper_enabled(fd, TRUE);
id = gbinder_servicemanager_add_presence_handler(sm, test_quit, loop);
test_run(&test_opt, loop);
@@ -448,7 +455,7 @@ test_retry(
gbinder_servicemanager_remove_handler(sm, id);
gbinder_servicemanager_unref(sm);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -464,7 +471,7 @@ test_cancel(
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
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;
@@ -488,9 +495,8 @@ test_cancel(
g_assert(sn);
g_assert_cmpstr(sn->name, == ,obj_name);
/* Immediately generate death notification (need looper for that) */
test_binder_br_dead_binder(fd, GBINDER_SERVICEMANAGER_HANDLE);
test_binder_set_looper_enabled(fd, TRUE);
/* Immediately generate death notification */
test_binder_br_dead_binder(fd, ANY_THREAD, GBINDER_SERVICEMANAGER_HANDLE);
id = gbinder_servicemanager_add_presence_handler(sm, test_quit, loop);
test_run(&test_opt, loop);
@@ -507,7 +513,6 @@ test_cancel(
g_mutex_unlock(&test->mutex);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -52,9 +52,9 @@ test_setup_ping(
{
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);
test_binder_br_noop(fd, THIS_THREAD);
test_binder_br_transaction_complete(fd, THIS_THREAD);
test_binder_br_reply(fd, THIS_THREAD, 0, 0, NULL);
}
/*==========================================================================*
@@ -200,6 +200,18 @@ gbinder_servicemanager_aidl2_get_type()
return TEST_TYPE_SERVICEMANAGER;
}
GType
gbinder_servicemanager_aidl3_get_type()
{
return TEST_TYPE_SERVICEMANAGER;
}
GType
gbinder_servicemanager_aidl4_get_type()
{
return TEST_TYPE_SERVICEMANAGER;
}
GType
gbinder_servicemanager_hidl_get_type()
{
@@ -233,7 +245,7 @@ test_basic(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderServicePoll* weakptr = NULL;
GBinderServiceManager* manager;
GBinderServicePoll* poll;
@@ -256,6 +268,7 @@ test_basic(
gbinder_servicemanager_unref(manager);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, NULL);
}
/*==========================================================================*
@@ -309,7 +322,7 @@ test_notify1(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServicePoll* weakptr = NULL;
GBinderServiceManager* manager;
@@ -340,6 +353,7 @@ test_notify1(
g_assert(!weakptr);
gbinder_servicemanager_unref(manager);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -383,7 +397,7 @@ test_notify2(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServicePoll* weakptr = NULL;
GBinderServiceManager* manager;
@@ -418,6 +432,7 @@ test_notify2(
g_assert(!weakptr);
gbinder_servicemanager_unref(manager);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}
@@ -442,7 +457,7 @@ test_already_there(
void)
{
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderServicePoll* weakptr = NULL;
GBinderServiceManager* manager;
@@ -466,6 +481,7 @@ test_already_there(
g_assert(!weakptr);
gbinder_servicemanager_unref(manager);
gbinder_ipc_unref(ipc);
test_binder_exit_wait(&test_opt, loop);
g_main_loop_unref(loop);
}

Some files were not shown because too many files have changed in this diff Show More