Compare commits

..

256 Commits

Author SHA1 Message Date
2778ec3a88 debug logs 2025-10-18 13:49:55 +08:00
6697470380 debian files 2025-10-17 23:30:56 +08:00
Ratchanan Srirattanamet
a9dfd6e453 writer: don't write object offset for NULL binder object
Writing offset will trigger the kernel-side code to transform the flat
binder object into the handle form, which (in my understanding) is not
a valid operation for a NULL binder object. Meanwhile, the receiving
side will create a corresponding Binder object from such handle,
tripping the stability check as it will no longer accept UNDECLARED.

OTOH, if the offset is not written, then the receiving side will receive
the flat binder object as-is, with type BINDER and pointer NULL, which
will be interpreted as NULL binder. This is also what Android's
Parcel.cpp does [1][2].

IMO, this is sort of a hack. Binder kernel driver should handle the NULL
binder internally, and not relying on the sender doing the correct
thing. Meanwhile, the receiver should always reject a flat binder object
of type BINDER. But that's how Android work, so... 🤷

[1]: https://github.com/LineageOS/android_frameworks_native/blob/lineage-19.1/libs/binder/Parcel.cpp#L1327-L1332
[2]: https://github.com/LineageOS/android_frameworks_native/blob/lineage-19.1/libs/binder/Parcel.cpp#L2023-L2029

Origin: vendor
Forwarded: https://github.com/mer-hybris/libgbinder/pull/135
2025-10-17 23:29:53 +08:00
Ratchanan Srirattanamet
2439ff878d use BINDER_TYPE_BINDER for NULL local object
3 reasons:
- This is what encode_remote_object() does. I see no reason a NULL local
  object should be encoded differently than a NULL remote object.
- This is what Parcel.cpp does when flattening a NULL binder [1]. This
  is contrary to what is said in PR #99 [2]; I'm not sure why PR #99
  said it uses BINDER_TYPE_HANDLE.
- More importantly, BINDER_TYPE_HANDLE number 0 does NOT represent a
  NULL binder. According to the comment at [3], handle number 0 actually
  represent the context manager. So, by sending BINDER_TYPE_HANDLE
  number 0, we're sending context manager, not a NULL binder.

[1]: https://android.googlesource.com/platform/frameworks/native/+/refs/tags/android-14.0.0_r1/libs/binder/Parcel.cpp#277
[2]: https://github.com/mer-hybris/libgbinder/pull/99
[3]: https://android.googlesource.com/platform/frameworks/native/+/refs/tags/android-14.0.0_r1/libs/binder/ProcessState.cpp#336

Origin: vendor
Bug-UBports: https://gitlab.com/ubports/development/core/packaging/libgbinder/-/merge_requests/9#note_2138653925
Forwarded: https://github.com/mer-hybris/libgbinder/pull/135
2025-10-17 23:29:52 +08:00
Ratchanan Srirattanamet
8c65520173 uses aidl3 servicemanager on API level 31 & 32
Nikita (@NotKit) noticed that the change in commit f227ae4291
("[gbinder] All binder objects need stability field in Android 11.
JB#58951") has made the aidl4 servicemanager variant redundant. In fact,
using aidl4 variant will cause an extra stability field to be sent on
the wire (luckily it has not caused any problem).

I've tried using aidl3 variant on Volla Phone X23 which runs Halium 12
(API level 32), and service registration still work, which seems to
validate this theory. Thus, stop using aidl4 servicemanager variant on
any of the API level-based config, as it no longer correspond to any of
Android versions.

Note that this commit doesn't outright remove aidl4 variant, as doing so
would break configurations which explicitly request its use. This commit
doesn't doesn't alias the aidl4 variant to aidl3 variant either.
Manually requesting a certain variant could mean some unusual setup;
aliasing aidl4 to aidl3 could break such setup.

Origin: vendor
Forwarded: https://github.com/mer-hybris/libgbinder/pull/133
2025-10-17 23:29:52 +08:00
Ratchanan Srirattanamet
e3764d7002 correct stability field wire format on Android 12
On Android 12, the wire format of stability field is changed to also
include so-called "Binder wire format version", which starts at 1 [1].
A 32-bit-sized struct is re-interpreted into a 32-bit integer, with a
layout which makes it incompatible with the old version. Interestingly,
they reverted this idea in Android 13 [2], which makes the wire format
of the stability field the same as Android 11 again (as far as I know).

Add a new RPC protocol variant 'aidl4' to account for this difference.
Use this protocol on API level 31 through 32 and use 'aidl3' from API
level 33 onwards. The only difference from 'aidl3' is `finish_flatten_
binder()` function.

Interestingly, there is also a 16-bit-sized struct variant of the field
too [3]. However, to the best of my knowledge, this version is not used
in any of the released Android versions.

[1]: 89ddfc5f8c
[2]: 16a4106cb7
[3]: 14e4cfae36

Origin: vendor
Forwarded: https://github.com/mer-hybris/libgbinder/pull/133
2025-10-17 23:29:52 +08:00
Slava Monich
624bfa843d Version 1.1.40 2024-07-18 05:35:00 +03:00
Slava Monich
6d71a0649c [gbinder] Housekeeping 2024-07-18 05:32:36 +03:00
Slava Monich
c31cd7e964 Acknowledge Nikita's contribution 2024-07-18 05:08:47 +03:00
Slava Monich
c1db86e734 Merge pull request #130 from mer-hybris/aidl-stability
Make stability field of local object configurable
2024-07-18 05:04:50 +03:00
Nikita Ukhrenkov
bfb95f2bf5 [gbinder] Make stability field of local object configurable. JB#61912
AIDL HALs require stability field value to be set to VINTF as
opposed to the default SYSTEM, so expose a way to let the caller
set the value to used by finish_flatten_binder per local object.
2024-07-15 18:42:20 +03:00
Slava Monich
6f4c69d58a Merge pull request #131 from monich/unit_conf
Make more unit tests independent on system config
2024-07-15 17:29:17 +03:00
Slava Monich
c6b09a10d4 [unit] Make more unit tests independent on system config. JB#42956
System gbinder config shouldn't break unit tests.
2024-07-14 06:15:19 +03:00
Slava Monich
545f5bc28d Version 1.1.39 2024-05-05 20:09:11 +03:00
Slava Monich
78e006f1cf Acknowledge Martin's contribution 2024-05-05 20:08:23 +03:00
Slava Monich
3c9cc1711a [spec] Cleaned up macro syntax 2024-04-30 20:25:43 +03:00
Slava Monich
71aa3acc08 [spec] Restore compatibility with rpm < 4.12 (again) 2024-04-30 02:42:25 +03:00
Slava Monich
eee26c5e98 [spec] Restore compatibility with rpm < 4.12 2024-04-30 02:18:18 +03:00
Slava Monich
736a29aa4c Merge pull request #128 from mer-hybris/jb61933
Utilize make_build macro
2024-04-29 19:54:51 +03:00
Martin Kampas
0d7105edbe [gbinder] Utilize make_build macro. JB#61933
Allow the build system to override the way make is invoked.

Cannot use make_install equally as that does not allow to pass
additional arguments to make.
2024-04-16 13:36:50 +02:00
Slava Monich
4420c7b2ae Merge pull request #126 from mer-hybris/jb61912
Eliminate defects found by Coverity
2024-04-12 04:51:00 +03:00
Martin Kampas
52726a07b0 [gbinder] Add model file for Coverity. JB#61912
Eliminate false positive. Help Coverity see there is no resource leak
(CID 444479).
2024-04-11 12:59:39 +02:00
Martin Kampas
12b9fd49ad [gbinder] Avoid double-checked locking in gbinder_ipc_looper_check. JB#61912
Data race condition detected by Coverity (CID 444481, CID 444483).

According to Slava the effect of this particular optimization is
negligible, so let's simply drop it to make Coverity happy.
2024-04-11 12:57:13 +02:00
Martin Kampas
e75959e389 [gbinder] Explicitly ignore return value. JB#61912
Recognized by Coverity (CID 444485) that this is the single call to
gbinder_driver_write out of the total of 9, where the return value is
not checked.

This change is implemented just to make Coverity happy.  The compiler
does not complain.
2024-04-11 12:45:33 +02:00
Slava Monich
9d35ca22fb Merge pull request #127 from monich/set_data
Remove unnecessary checks for NULL
2024-04-11 13:09:34 +03:00
Slava Monich
3e0d0005ce [gbinder] Remove unnecessary checks for NULL. JB#61912
And fix potential use after free.
2024-04-11 03:29:28 +03:00
Slava Monich
29718f921f Version 1.1.38 2024-03-02 02:13:19 +02:00
Slava Monich
99b2dd85c1 [unit] Test byte array padding. JB#42956 2024-03-02 02:09:44 +02:00
Slava Monich
cf5417d5db [gbinder] Housekeeping 2024-03-02 02:01:11 +02:00
Slava Monich
03f214eb24 [gbinder] Fixed FF padding 2024-03-02 01:59:43 +02:00
Slava Monich
6508a73dcd Merge pull request #124 from mer-hybris/bytearraypad 2024-03-02 01:46:57 +02:00
Andrew Branson
1100d8ede1 [gbinder] Byte array padding
Android aligns byte array reads and writes to 4 bytes and pads with 0xFF.
Not accounting for this causes misalignment issues on further reading.
2024-03-01 10:09:41 +01:00
Slava Monich
f89469b1a5 Version 1.1.37 2024-02-26 16:25:25 +02:00
Slava Monich
fcf2ef0ea4 Merge pull request #123 from Tomin1/jb61613
Fix gbinder_driver_reply_data return value
2024-02-26 16:18:55 +02:00
Tomi Leppänen
f9202cab37 [gbinder] Fix gbinder_driver_reply_data return value. Fixes JB#61613
Previously this always returned 1. Drop the first comparison so status
can be negative and errors will return 0.

Signed-off-by: Tomi Leppänen <tomi.leppanen@jolla.com>
2024-02-26 10:54:39 +02:00
Slava Monich
49729d95c9 Version 1.1.36 2024-02-10 05:05:39 +02:00
Slava Monich
11765cd80d [unit] Added test for surrogate pairs 2024-02-10 05:00:25 +02:00
Slava Monich
4820b2971f [gbinder] Housekeeping 2024-02-10 04:57:24 +02:00
Slava Monich
0623fb85db [license] Freshened up the license 2024-02-10 04:54:52 +02:00
Slava Monich
e655d8992a Merge pull request #122 from mer-hybris/jb61524
Calculate correct size for UTF-16 buffer in advance.
2024-02-10 04:49:11 +02:00
Andrew Branson
44e57ea98d [gbinder] Calculate correct size for UTF-16 buffer in advance. Fixes JB#61524
In UTF-16, code points U+010000 to U+10FFFF are encoded using 'surrogate
pairs' where 32 bits are actually used. If a string is mostly emojis,
that can end up larger than the len*2 bytes assumed padded_len.
Convert the string to UTF-16 before allocating the extra buffer size so
it will be correct.
2024-02-09 17:29:19 +01:00
Slava Monich
e3f705c4cc Merge pull request #120 from JamiKettunen/cross-pkgconf
[build] Support pkg-config cross-compilation
2023-12-01 03:44:46 +02:00
Jami Kettunen
6f0e8a693d [build] Support pkg-config cross-compilation
Previously to cross-compile one would need to add a pkg-config
executable in $PATH wrapping all the search paths required; now one can
e.g.

  make PKG_CONFIG=foreign-arch-target-pkg-config

with the wrapper executable being separate and allowing programs for
host to also be built if needed for example.
2023-11-30 20:54:40 +02:00
Slava Monich
c7fab6373b Version 1.1.35 2023-11-23 01:45:18 +02:00
Slava Monich
9aded94555 Merge pull request #119 from monich/test_config
Make unit tests independent on system config
2023-11-23 01:38:15 +02:00
Slava Monich
b5bab2431e [unit] Make unit tests independent on system config. JB#42956
System gbinder config shouldn't break unit tests.
2023-11-19 18:41:26 +02:00
Slava Monich
509faccba0 Merge pull request #117 from JamiKettunen/make-var
[build] Use MAKE var instead of explicitly calling make
2023-09-11 02:13:30 +03:00
Jami Kettunen
a89dcd2702 [build] Use MAKE var instead of explicitly calling make
There are multiple make implementations and nothing guarantees that the
make executable is gmake, which is what this Makefile requires.
2023-09-08 15:20:10 +03:00
Slava Monich
62b9b30865 Version 1.1.34 2023-04-30 06:10:45 +03:00
Slava Monich
4a913590d9 [gbinder] Require glib 2.32 2023-04-30 06:07:16 +03:00
Slava Monich
1ee872aaf2 Merge pull request #115 from Tomin1/jb60671_fix
Use correct suffix for 16-bit strings
2023-04-30 05:26:55 +03:00
Tomi Leppänen
00e9d8ac6f [binder-call] Use correct suffix for 16-bit strings. Fixes JB#60671
Signed-off-by: Tomi Leppänen <tomi.leppanen@jolla.com>
2023-04-27 11:44:12 +03:00
Slava Monich
b032e151a2 Version 1.1.33 2023-02-26 03:15:39 +02:00
Slava Monich
b8edc9221a Merge pull request #114 from monich/int32_vs_byte
Fix gbinder_writer_type_byte and gbinder_writer_type_int32 descriptors
2023-02-26 03:10:44 +02:00
Slava Monich
05634757d7 [unit] Added tests for byte and int32 type descriptors. JB#42956 2023-02-25 02:59:47 +02:00
Slava Monich
03ef78c9fd [gbinder] Fixed GBinderWriterType for byte and int32. JB#42956 2023-02-25 02:58:33 +02:00
Slava Monich
84efc32ac0 Version 1.1.32 2023-01-23 11:49:21 +02:00
Slava Monich
88388de696 [license] Freshened up copyright 2023-01-23 11:46:19 +02:00
Slava Monich
daa062d981 Merge pull request #113 from monich/unit-tests
Improve reliability of unit tests
2023-01-23 11:27:39 +02:00
Slava Monich
85db18f663 [unit] Handle servicemanager requests on looper thread. JB#42956
Because tests are using synchronous calls blocking the main thread,
2023-01-23 01:29:58 +02:00
Slava Monich
af796828a4 [unit] Fixed possible deadlock in proxy_object test. JB#42956
The /proxy_object/param test could be deadlocked by gbinder_ipc_exit()
blocking the main thread and waiting for all client threads to terminate
one of which waiting for the transaction (the one getting cancelled) to
complete on the main thread blocked by gbinder_ipc_exit().

The deadlock is avoided by making sure that both transactions get completed
before gbinder_ipc_exit() is called.
2023-01-22 04:35:22 +02:00
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
Slava Monich
e8c5a0c0bb Version 1.1.12 2021-09-24 18:02:37 +03:00
Slava Monich
94b74ee948 Housekeeping 2021-09-24 17:58:42 +03:00
Slava Monich
1bfacab88d [test] Add binder-call to debian build. JB#55084 2021-09-23 12:47:57 +03:00
Slava Monich
704e7d011c Merge pull request #68 from krnlyng/jb55084
Add binder-call
2021-09-23 12:23:16 +03:00
Frajo Haider
3a4ae9a716 [test] Add binder-call. JB#55084 2021-09-23 11:18:00 +03:00
Slava Monich
5ddc9d94d6 Version 1.1.11 2021-09-02 12:34:24 +03:00
Slava Monich
159708d829 Merge pull request #72 from monich/transact_2way
Serialize execution of /ipc/transact_2way test
2021-09-02 12:23:40 +03:00
Slava Monich
5753cdab1a Merge pull request #74 from monich/musl
Threading fixes
2021-09-02 12:18:55 +03:00
Slava Monich
d4ea1261eb [gbinder] Fix occasional crashes in pthread_setname_np(). JB#42956
gbinder_ipc_looper_thread() may be invoked before looper->thread is set
by pthread_create(). This does happen quite often on musl-based systems.
2021-09-02 02:26:36 +03:00
Slava Monich
7e3ac0a761 [gbinder] Fix potential deadlock in gbinder_ipc_looper_free(). JB#42956
Joining self is never a good idea. This deadlock does indeed happen
quite often on musl-based systems.
2021-09-02 02:26:36 +03:00
Slava Monich
76494c3e3d [unit] Allow side-by-side linking with libglibutil 2021-09-02 02:14:47 +03:00
Slava Monich
dfbc8acd9e [unit] Serialize execution of /ipc/transact_2way 2021-08-31 19:34:16 +03:00
Slava Monich
158d33db5a [debian] Bump libglibutil requirement 2021-08-31 17:53:31 +03:00
Slava Monich
4b11769895 Acknowledge Bart's contribution 2021-08-31 17:50:33 +03:00
Slava Monich
4da96dd0b5 Merge pull request #70 from PureTryOut/ioctl
[unit] Pull in definition of _IOC_SIZE. JB#42254
2021-08-31 17:44:34 +03:00
Bart Ribbers
d9bfb9e200 Include more definitions of _IOC_SIZE
Continuation of https://github.com/mer-hybris/libgbinder/pull/64
2021-08-31 16:39:09 +02:00
Slava Monich
f088e6d1bb [unit] Make unit tests comptible with glib < 2.36
g_type_init() was required back then, whenever a GObject is touched.
2021-08-30 19:32:21 +03:00
Slava Monich
ca665ad3d1 Version 1.1.10 2021-05-10 03:19:18 +03:00
Slava Monich
6ed9082e69 [build] Tweaked build dependencies 2021-05-10 03:17:12 +03:00
Slava Monich
5332dd3482 [gbinder] Use gutil_memdup() instead of g_memdup()
g_memdup has been deprecated since glib 2.68
2021-05-10 02:49:59 +03:00
Slava Monich
a15f63621e Merge pull request #67 from monich/bc_release
Release dead binder nodes
2021-05-10 02:34:04 +03:00
Slava Monich
e4b5f081bd [gbinder] Release dead binder nodes. JB#54002
One has to be careful about BC_RELEASE and BC_ACQUIRE. Those
increment and decrements strong references to binder nodes in
the driver. Not releasing strong references may have various
severe consequences, from kernel memory leaks to missing death
notifications.
2021-05-09 20:20:19 +03:00
Slava Monich
5fab0bcdaa [gbinder] Housekeeping 2021-05-09 20:12:55 +03:00
Slava Monich
5c1b23f30e Version 1.1.9 2021-04-20 13:01:10 +03:00
Slava Monich
8f720e11de Acknowledge contributions 2021-04-20 13:00:55 +03:00
Slava Monich
3c2cd5d599 Merge pull request #64 from george-hopkins/ioc-size
[gbinder] Include definition of _IOC_SIZE. JB#42254
2021-04-20 12:49:15 +03:00
Slava Monich
8df1e70c0b Version 1.1.8 2021-04-16 19:12:35 +03:00
Slava Monich
3833a36693 Merge pull request #66 from monich/out-of-range
Handle out-of-range transaction codes
2021-04-16 18:54:05 +03:00
Slava Monich
38fd1e6dcb [gbinder] Handle out-of-range transaction codes. JB#42956 2021-04-16 17:04:34 +03:00
Slava Monich
5fa4cd03de Version 1.1.7 2021-03-31 23:12:03 +03:00
Slava Monich
d6c0cdd231 Merge pull request #65 from monich/invoke_later
Drop use of g_main_context_invoke_full
2021-03-31 23:01:58 +03:00
Slava Monich
c38843d9c9 [gbinder] Dropped use of g_main_context_invoke_full(). JB#53719
Replaced it with gbinder_idle_callback_invoke_later(), which should
work nicely with non-GLib event loops.
2021-03-31 13:29:52 +03:00
Slava Monich
a6a5df963f [unit] Test for gbinder_idle_callback_invoke_later(). JB#53719 2021-03-31 13:29:08 +03:00
Slava Monich
b60960d955 [gbinder] Added gbinder_idle_callback_invoke_later(). JB#53719
Non-cancellable callback mechanism, similar to g_main_context_invoke_full()
but not requiring GMainContext and GLib event loop.
2021-03-31 13:28:50 +03:00
George Hopkins
0adb80a9ed Include definition of _IOC_SIZE 2021-03-18 08:04:33 +01:00
Slava Monich
f591433118 Version 1.1.6 2021-03-02 18:19:38 +02:00
Slava Monich
5a897a34c2 Merge pull request #61 from monich/objproxy
Support for passing object references over the bridge
2021-03-02 18:06:14 +02:00
Slava Monich
138423de4a [gbinder] Retry service name registration. JB#52557
Sometimes servicemanager fails to add a name right after startup.
2021-03-02 17:54:06 +02:00
Slava Monich
1d9f9c4487 [gbinder] Added gbinder_bridge_new2(). JB#52557
Allows to use different source and destination names.
2021-03-02 17:54:06 +02:00
Slava Monich
82f71a6c91 [gbinder] Support for passing object references via proxy. JB#52557
GBinderProxyObject automatically creates proxies for the remote objects
found in the transaction payload.
2021-03-02 17:53:53 +02:00
Slava Monich
0c85299efc [gbinder] Make sure libgbinder doesn't block on exit. JB#42956
In case if looper threads get stuck in read, libgbinder may block
indefinitely in exit. To prevent that, join looper thread with a
timeout and if it expires, close the binder file descriptors to
unblock all blocking reads.
2021-02-22 21:18:28 +02:00
Slava Monich
50195aae1d [gbinder] Delay processing of unrefs. JB#52557
According to comments in the Android sources, unrefs must be processed
only after clearing the incoming command queue.
2021-02-21 19:12:29 +02:00
Slava Monich
586425bc2d [gbinder] Wait until reply is handled. JB#52557
The driver sends us back one of three transaction completion messages
BR_TRANSACTION_COMPLETE, BR_DEAD_REPLY or BR_FAILED_REPLY after the
target has finished processing BC_REPLY. It's especially important
when the reply carries an object reference. That gives the other side
a chance to reference that object before we drop our reference to it
(which may be the last one, which would cause the object to be freed
and its handle invalidated).
2021-02-21 04:48:40 +02:00
Slava Monich
b0bde6b652 [gbinder] Fixed death handling by binder bridge. JB#52557 2021-02-21 04:48:40 +02:00
Slava Monich
be2369c64c [gbinder] Handle EINTR from ioctl. JB#42956 2021-02-21 04:48:40 +02:00
Slava Monich
c2cf68cab6 [gbinder] Do not set TF_ACCEPT_FDS in reply messages. JB#52557
This transaction flag doesn't make sense for replies and is probably
just ignored but let's not confuse kernel.
2021-02-21 04:48:40 +02:00
Slava Monich
f7d1863615 [unit] Improved binder simulation. JB#52557 2021-02-21 04:48:40 +02:00
Slava Monich
0bb0aee6cb [unit] Slightly improved test coverage. JB#42956 2021-02-21 04:48:39 +02:00
Slava Monich
b392e019f3 [unit] Synchronize object deletion with worker threads. JB#53002
Otherwise all kinds of race conditions are possible, e.g. with
GBinderServiceManager and its gbinder_servicemanager_died() callback.
2021-02-21 04:48:39 +02:00
Slava Monich
8eb5fa7394 [unit] Make sure loopers get terminated at the end of each test
That's done by calling test_binder_exit_wait(). Not doing so occasionally
breaks the next unit test.
2021-02-21 04:48:39 +02:00
Slava Monich
c5c04db81a [unit] Don't try to translate reply handle
It's always zero, just leave it as is.
2021-02-21 04:48:39 +02:00
Slava Monich
4056cfaa15 [gbinder] Updated comment 2021-02-21 04:48:39 +02:00
Slava Monich
ba8b226d89 [gbinder] Improved debug trace. JB#42956
Only affects debug build.
2021-02-21 04:47:47 +02:00
Slava Monich
88df2edb95 [gbinder] Fixed invalid slice deallocation. JB#42956 2021-02-09 18:31:27 +02:00
Slava Monich
b856cf2141 Version 1.1.5 2021-01-29 04:19:52 +02:00
Slava Monich
f4a2429a13 [gbinder] Added binder-bridge to libgbinder-tools package. JB#52557 2021-01-29 04:14:33 +02:00
Slava Monich
7d1f8ad4e7 Merge pull request #60 from monich/bridge
Add GBinderBridge
2021-01-29 03:55:19 +02:00
Slava Monich
82656db49d [unit] Added proxy_object and bridge tests. JB#52557 2021-01-29 03:49:55 +02:00
Slava Monich
d6dac912dd [gbinder] Added GBinderBridge object. JB#52557
It acts as a proxy between two binder devices.

This version works for binder transactions which only
pass serialized data back and forth. Passing remote
object references is not yet supported.
2021-01-27 21:21:10 +02:00
Slava Monich
207f9398b4 [unit] Improved binder simulation. JB#42956
This more or less ensures that responses get handled by the right thread
and allows to simulate more sophisticated test cases.
2021-01-27 21:20:55 +02:00
Slava Monich
7b51a82de8 [gbinder] Fixed gbinder_remote_reply_copy_to_local() for empty replies
If there's no data, buffer may be NULL.
2021-01-26 19:49:19 +02:00
Slava Monich
66f08bf0db Version 1.1.4 2021-01-21 03:38:18 +02:00
Slava Monich
90384e921f Merge pull request #59 from monich/ipc_api
Fix a threading issue + assorted changes
2021-01-21 03:31:56 +02:00
Slava Monich
1ae7c2697c [unit] Added servicemanager_hidl test. JB#42956 2021-01-21 02:13:15 +02:00
Slava Monich
536143c1d7 [gbinder] Fixed a threading issue. JB#42956
Make sure that transaction handlers don't get invoked on a worker thread.
It was possible in cases if an incoming transaction arrives while we are
waiting for response from an asynchronous call to servicemanager (which
is actually a synchronous call made on a worker thread).

Invoking callbacks on a worker thread would completely break libgbinder's
synchronization model. It was a pretty unlikely scenario, though.
2021-01-20 19:32:40 +02:00
Slava Monich
6025950aab [gbinder] Decode NULL object reference. JB#52557 2021-01-19 02:19:44 +02:00
Slava Monich
4d69940b96 [gbinder] Added new basic HIDL types. JB#52557
GBinderFds - native_handle_t
GBinderHidlHandle - struct hidl_handle
GBinderHidlMemory - struct hidl_memory
2021-01-12 20:00:26 +02:00
Slava Monich
b1f49cae13 [gbinder] Set TF_ACCEPT_FDS transaction flag. JB#52557
Except for one-way transactions where it would meaningless.
2021-01-12 13:58:23 +02:00
Slava Monich
80e9be5343 Version 1.1.3 2020-12-23 21:50:41 +02:00
Slava Monich
d6d6b76fa5 [unit] Added unit_servicemanager_aidl2 test. JB#42956 2020-12-23 21:44:53 +02:00
Slava Monich
d18a352a82 [gbinder] Set function attributes. JB#42956
For better compile time diagnostics.
2020-12-23 21:43:28 +02:00
Slava Monich
5fbaabb47e [unit] Improved gbinder_servicemanager_aidl coverage. JB#42956
Also made ServiceManagerAidl a GBinderLocalObject-derived class to prepare
for possibly making it (deriving classes from GBinderLocalObject) a public
functionality.
2020-12-23 21:38:17 +02:00
Slava Monich
83cc13b817 [gbinder] Fixed some typos. JB#42956 2020-12-23 21:37:46 +02:00
Slava Monich
1679cda4c5 [gbinder] Allow to derive objects from GBinderLocalObject. JB#42956
It's something I've always had in mind. It's still an internal API
but it's quite likely that at some point it will be made public.
For now it's only going to be used by unit tests.
2020-12-23 18:17:51 +02:00
137 changed files with 16638 additions and 3461 deletions

10
AUTHORS
View File

@@ -1,5 +1,13 @@
Slava Monich <slava.monich@jolla.com>
Slava Monich <slava@monich.com>
Matti Lehtimäki <matti.lehtimaki@gmail.com>
Franz-Josef Haider <franz.haider@jolla.com>
Juho Hämäläinen <juho.hamalainen@jolla.com>
Andrew Branson <andrew.branson@jolla.com>
Rinigus <rinigus.git@gmail.com>
George Hopkins <george-hopkins@null.net>
Bart Ribbers <bribbers@disroot.org>
Gary Wang <gary.wang@canonical.com>
Eugenio Paolantonio <me@medesimo.eu>
Alessandro Astone <ales.astone@gmail.com>
Martin Kampas <martin.kampas@seafarix.com>
Nikita Ukhrenkov <nikita.ukhrenkov@seafarix.com>

View File

@@ -1,7 +1,5 @@
Copyright (C) 2018-2020 Jolla Ltd.
Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:
Copyright (C) 2018-2024 Jolla Ltd.
Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions

View File

@@ -16,7 +16,7 @@
VERSION_MAJOR = 1
VERSION_MINOR = 1
VERSION_RELEASE = 2
VERSION_RELEASE = 40
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
@@ -50,10 +50,10 @@ RELEASE_DEPS = libglibutil_release
.PHONY: libglibutil_debug libglibutil_release
libglibutil_debug:
make -C $(LIBGLIBUTIL_PATH) debug
$(MAKE) -C $(LIBGLIBUTIL_PATH) debug
libglibutil_release:
make -C $(LIBGLIBUTIL_PATH) release
$(MAKE) -C $(LIBGLIBUTIL_PATH) release
endif
@@ -75,12 +75,14 @@ LIB = $(LIB_NAME).a
#
SRC = \
gbinder_bridge.c \
gbinder_buffer.c \
gbinder_cleanup.c \
gbinder_client.c \
gbinder_config.c \
gbinder_driver.c \
gbinder_eventloop.c \
gbinder_fmq.c \
gbinder_io_32.c \
gbinder_io_64.c \
gbinder_ipc.c \
@@ -88,6 +90,7 @@ SRC = \
gbinder_local_reply.c \
gbinder_local_request.c \
gbinder_log.c \
gbinder_proxy_object.c \
gbinder_reader.c \
gbinder_remote_object.c \
gbinder_remote_reply.c \
@@ -101,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 += \
@@ -121,16 +126,19 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
# Tools and flags
#
PKG_CONFIG ?= pkg-config
CC ?= $(CROSS_COMPILE)gcc
STRIP ?= strip
LD = $(CC)
WARNINGS = -Wall -Wstrict-aliasing -Wunused-result
DEFINES += -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_32 \
-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_MAX_ALLOWED
INCLUDES += -I$(INCLUDE_DIR)
BASE_FLAGS = -fPIC
FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) \
-MMD -MP $(shell pkg-config --cflags $(PKGS))
-MMD -MP $(shell $(PKG_CONFIG) --cflags $(PKGS))
FULL_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS) -shared -Wl,-soname,$(LIB_SONAME) \
$(shell pkg-config --libs $(PKGS)) -lpthread
$(shell $(PKG_CONFIG) --libs $(PKGS)) -lpthread
DEBUG_FLAGS = -g
RELEASE_FLAGS =
COVERAGE_FLAGS = -g
@@ -155,6 +163,16 @@ DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
COVERAGE_OBJS = $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
DEBUG_SO = $(DEBUG_BUILD_DIR)/$(LIB_SO)
RELEASE_SO = $(RELEASE_BUILD_DIR)/$(LIB_SO)
DEBUG_LINK = $(DEBUG_BUILD_DIR)/$(LIB_SYMLINK1)
RELEASE_LINK = $(RELEASE_BUILD_DIR)/$(LIB_SYMLINK1)
DEBUG_DEV_LINK = $(DEBUG_BUILD_DIR)/$(LIB_DEV_SYMLINK)
RELEASE_DEV_LINK = $(RELEASE_BUILD_DIR)/$(LIB_DEV_SYMLINK)
DEBUG_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
COVERAGE_LIB = $(COVERAGE_BUILD_DIR)/$(LIB)
#
# Dependencies
#
@@ -171,20 +189,15 @@ $(DEBUG_OBJS) $(DEBUG_SO): | $(DEBUG_BUILD_DIR) $(DEBUG_DEPS)
$(RELEASE_OBJS) $(RELEASE_SO): | $(RELEASE_BUILD_DIR) $(RELEASE_DEPS)
$(COVERAGE_OBJS) $(COVERAGE_LIB): | $(COVERAGE_BUILD_DIR)
$(DEBUG_LINK): | $(DEBUG_LIB)
$(RELEASE_LINK): | $(RELEASE_LIB)
$(DEBUG_DEV_LINK): | $(DEBUG_LINK)
$(RELEASE_DEV_LINK): | $(RELEASE_LINK)
#
# Rules
#
DEBUG_SO = $(DEBUG_BUILD_DIR)/$(LIB_SO)
RELEASE_SO = $(RELEASE_BUILD_DIR)/$(LIB_SO)
DEBUG_LINK = $(DEBUG_BUILD_DIR)/$(LIB_SYMLINK1)
RELEASE_LINK = $(RELEASE_BUILD_DIR)/$(LIB_SYMLINK1)
DEBUG_DEV_LINK = $(DEBUG_BUILD_DIR)/$(LIB_DEV_SYMLINK)
RELEASE_DEV_LINK = $(RELEASE_BUILD_DIR)/$(LIB_DEV_SYMLINK)
DEBUG_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
COVERAGE_LIB = $(COVERAGE_BUILD_DIR)/$(LIB)
debug: $(DEBUG_SO) $(DEBUG_LINK) $(DEBUG_DEV_LINK)
release: $(RELEASE_SO) $(RELEASE_LINK) $(RELEASE_DEV_LINK)
@@ -225,8 +238,8 @@ print_release_path:
@echo $(RELEASE_BUILD_DIR)
clean:
make -C test clean
make -C unit clean
$(MAKE) -C test clean
$(MAKE) -C unit clean
rm -fr test/coverage/results test/coverage/*.gcov
rm -f *~ $(SRC_DIR)/*~ $(INCLUDE_DIR)/*~
rm -fr $(BUILD_DIR) RPMS installroot
@@ -236,7 +249,7 @@ clean:
rm -f debian/libgbinder.install debian/libgbinder-dev.install
test:
make -C unit test
$(MAKE) -C unit test
$(BUILD_DIR):
mkdir -p $@

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

10
debian/Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,10 @@
@Library('ubports-build-tools') _
buildAndProvideDebianPackage()
// Or if the package consists entirely of arch-independent packages:
// (optional optimization, will confuse BlueOcean's live view at build stage)
// buildAndProvideDebianPackage(/* isArchIndependent */ true)
// Optionally, to skip building on some architectures (amd64 is always built):
// buildAndProvideDebianPackage(false, /* ignoredArchs */ ['arm64'])

243
debian/changelog vendored
View File

@@ -1,3 +1,246 @@
libgbinder (1.1.40-0ubports1) UNRELEASED; urgency=medium
* Upstream release v1.1.40
-- TheKit <thekit@disroot.org> Thu, 15 Aug 2024 15:56:51 +0300
libgbinder (1.1.35-0ubports1) UNRELEASED; urgency=unknown
* New upstream release v1.1.35
-- UBports package upgrader bot <dev@ubports.com> Thu, 23 Nov 2023 23:02:23 +0000
libgbinder (1.1.34-0ubports1) focal; urgency=medium
* New upstream release v1.1.34
-- Marius Gripsgard <mariogrip@debian.org> Thu, 31 Aug 2023 12:09:35 +0200
libgbinder (1.1.30-0ubports1) focal; urgency=medium
* Upstream release v1.1.30
-- Jami Kettunen <jami.kettunen@protonmail.com> Wed, 07 Dec 2022 00:58:38 +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-0ubports1) xenial; urgency=medium
* New upstream version 1.1.19.
* debian/ubports.source_location: update the location for 1.1.19
* debian/*: bring in upstream Debian packaging changes where appropriate
* debian/rules: pass KEEP_SYMBOLS to let dh do the strip (& auto dbgsym)
* debian/libgbinder-tools.install: add the missing .install file
-- Ratchanan Srirattanamet <ratchanan@ubports.com> Thu, 21 Apr 2022 17:22:20 +0700
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
-- Slava Monich <slava.monich@jolla.com> Fri, 24 Sep 2021 16:46:05 +0300
libgbinder (1.1.11) unstable; urgency=low
* Fix potential deadlock in gbinder_ipc_looper_free()
* Fix occasional crashes in pthread_setname_np()
* Fix unit tests on some musl-based systems
* Make unit tests comptible with glib < 2.36
* Bump libglibutil requirement for debian build
-- Slava Monich <slava.monich@jolla.com> Thu, 02 Sep 2021 12:32:39 +0300
libgbinder (1.1.10) unstable; urgency=low
* Release dead binder nodes
* Use gutil_memdup() instead of g_memdup()
-- Slava Monich <slava.monich@jolla.com> Mon, 10 May 2021 02:36:43 +0300
libgbinder (1.1.9) unstable; urgency=low
* Include definition of _IOC_SIZE
-- Slava Monich <slava.monich@jolla.com> Tue, 20 Apr 2021 12:52:41 +0300
libgbinder (1.1.8) unstable; urgency=low
* Handle out-of-range transaction codes
-- Slava Monich <slava.monich@jolla.com> Fri, 16 Apr 2021 19:11:14 +0300
libgbinder (1.1.7) unstable; urgency=low
* Dropped use of g_main_context_invoke_full()
-- Slava Monich <slava.monich@jolla.com> Wed, 31 Mar 2021 23:10:37 +0300
libgbinder (1.1.6-0ubports1) xenial; urgency=medium
* Import v1.1.6 to ubports
-- Marius Gripsgard <marius@ubports.com> Fri, 05 Mar 2021 01:02:27 +0100
libgbinder (1.1.6) unstable; urgency=low
* Implemented support for passing object over the bridge
* Retry service name registration
* Wait for completion of the reply
* Fixed death handling by GBinderBridge
* Added gbinder_bridge_new2()
* Added -s option to binder-bridge
* Fixed invalid slice deallocation
* Made unit tests more reliable
* Make sure that libgbinder doesn't block on exit
-- Slava Monich <slava.monich@jolla.com> Tue, 02 Mar 2021 18:18:03 +0200
libgbinder (1.1.5) unstable; urgency=low
* Fixed gbinder_remote_reply_copy_to_local() for empty replies
* Improved binder simulation
* Added GBinderBridge object
* Added proxy_object and bridge unit tests
* Added binder-bridge to libgbinder-tools package
-- Slava Monich <slava.monich@jolla.com> Fri, 29 Jan 2021 04:00:09 +0200
libgbinder (1.1.4) unstable; urgency=low
* Fixed a threading issue
* Decode NULL object reference
* Added new basic HIDL types
* Set TF_ACCEPT_FDS transaction flag
* Added servicemanager_hidl unit test
-- Slava Monich <slava.monich@jolla.com> Thu, 21 Jan 2021 03:34:45 +0200
libgbinder (1.1.3) unstable; urgency=low
* Improved unit test coverage
-- Slava Monich <slava.monich@jolla.com> Wed, 23 Dec 2020 21:48:27 +0200
libgbinder (1.1.2) unstable; urgency=low
* Fixed random unit text failures

2
debian/compat vendored
View File

@@ -1 +1 @@
5
7

6
debian/control vendored
View File

@@ -2,19 +2,19 @@ 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.35)
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
Section: libs
Architecture: any
Depends: libglibutil (>= 1.0.35), ${shlibs:Depends}, ${misc:Depends}
Depends: libglibutil (>= 1.0.52), ${shlibs:Depends}, ${misc:Depends}
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), ${misc:Depends}
Description: Development files for libgbinder
Package: libgbinder-tools

4
debian/copyright vendored
View File

@@ -1,5 +1,5 @@
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:

37
debian/gbinder.conf vendored Normal file
View File

@@ -0,0 +1,37 @@
# Android keeps changing both low-level RPC and service manager
# protocols from version to version. To counter that, libgbinder
# implements configirable backends for different variants of those,
# and yet keeping its own API unchanged.
# Configuration is loaded from [Protocol] and [ServiceManager] sections
# of /etc/gbinder.conf file. The keys are binder device names or the
# special Default value, the value is the identifier of the protocol
# or service manager variant, respectively.
# In addition to reading /etc/gbinder.conf if it exists, /etc/gbinder.d
# directory is scanned for .conf files, the file list is sorted, files are
# loaded one by one, overwriting the entries loaded from /etc/gbinder.conf
# or from the previously processed file.
# Known protocol and service manager variants are aidl, aidl2, aidl3 and
# hidl. This list is expected to expand further in the future. The default
# configuration is as follows:
# [Protocol]
# Default = aidl
# /dev/binder = aidl
# /dev/hwbinder = hidl
# [ServiceManager]
# Default = aidl
# /dev/binder = aidl
# /dev/hwbinder = hidl
# Alternatively and preferably, one can specify the desired Android API
# level:
# [General]
# ApiLevel = 29
# and let libgbinder pick the appropriate preset. Full list of presets can
# be found in src/gbinder_config.c

View File

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

1
debian/libgbinder.dirs vendored Normal file
View File

@@ -0,0 +1 @@
/etc/gbinder.d/

View File

@@ -1 +1,2 @@
debian/tmp/@LIBDIR@/libgbinder.so.* @LIBDIR@
debian/gbinder.conf /etc/

6
debian/rules vendored
View File

@@ -7,12 +7,16 @@
LIBDIR=usr/lib/$(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
override_dh_auto_build:
dh_auto_build -- LIBDIR=$(LIBDIR) release pkgconfig debian/libgbinder.install debian/libgbinder-dev.install
dh_auto_build -- LIBDIR=$(LIBDIR) KEEP_SYMBOLS=1 release pkgconfig debian/libgbinder.install debian/libgbinder-dev.install
dh_auto_build -- -C test/binder-bridge release
dh_auto_build -- -C test/binder-call release
dh_auto_build -- -C test/binder-list release
dh_auto_build -- -C test/binder-ping release
override_dh_auto_install:
dh_auto_install -- LIBDIR=$(LIBDIR) install-dev
dh_auto_install -- -C test/binder-bridge
dh_auto_install -- -C test/binder-call
dh_auto_install -- -C test/binder-list
dh_auto_install -- -C test/binder-ping

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-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:
*
@@ -35,8 +35,10 @@
/* Convenience header to pull in everything at once */
#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"

89
include/gbinder_bridge.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_BRIDGE_H
#define GBINDER_BRIDGE_H
#include "gbinder_types.h"
/* Since 1.1.5 */
G_BEGIN_DECLS
/*
* A binder bridge object.
*
* For example, bridging "foobar" with interfaces ["example@1.0::IFoo",
* "example@1.0::IBar"] would:
*
* 1. Watch "example@1.0::IFoo/foobar" and "example@1.0::IBar/foobar" on dest
* 2. When those names appears, register objects with the same name on src
* 3. Pass calls coming from src to the dest objects and replies in the
* opposite direction
* 4. When dest objects disappear, remove the corresponding bridging objects
* from src
*
* and so on.
*/
GBinderBridge*
gbinder_bridge_new(
const char* name,
const char* const* ifaces,
GBinderServiceManager* src,
GBinderServiceManager* dest) /* Since 1.1.5 */
G_GNUC_WARN_UNUSED_RESULT;
GBinderBridge*
gbinder_bridge_new2(
const char* src_name,
const char* dest_name,
const char* const* ifaces,
GBinderServiceManager* src,
GBinderServiceManager* dest) /* Since 1.1.6 */
G_GNUC_WARN_UNUSED_RESULT;
void
gbinder_bridge_free(
GBinderBridge* bridge); /* Since 1.1.5 */
G_END_DECLS
#endif /* GBINDER_BRIDGE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

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-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -61,6 +61,11 @@ GBinderLocalReply*
gbinder_local_object_new_reply(
GBinderLocalObject* obj);
void
gbinder_local_object_set_stability(
GBinderLocalObject* self,
GBINDER_STABILITY_LEVEL stability); /* Since 1.1.40 */
G_END_DECLS
#endif /* GBINDER_LOCAL_OBJECT_H */

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-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
@@ -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(
@@ -93,14 +101,16 @@ gbinder_servicemanager_new_local_object(
GBinderServiceManager* sm,
const char* iface,
GBinderLocalTransactFunc handler,
void* user_data);
void* user_data)
G_GNUC_WARN_UNUSED_RESULT;
GBinderLocalObject*
gbinder_servicemanager_new_local_object2(
GBinderServiceManager* sm,
const char* const* ifaces,
GBinderLocalTransactFunc handler,
void* user_data); /* Since 1.0.29 */
void* user_data) /* Since 1.0.29 */
G_GNUC_WARN_UNUSED_RESULT;
GBinderServiceManager*
gbinder_servicemanager_ref(
@@ -110,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 */
@@ -127,7 +141,9 @@ gbinder_servicemanager_list(
char**
gbinder_servicemanager_list_sync(
GBinderServiceManager* sm);
GBinderServiceManager* sm)
G_GNUC_WARN_UNUSED_RESULT
G_GNUC_MALLOC;
gulong
gbinder_servicemanager_get_service(
@@ -185,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

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -59,8 +59,10 @@ G_BEGIN_DECLS
* 6. Reader parses the data coming with RemoteRequest and RemoteReply
*/
typedef struct gbinder_bridge GBinderBridge; /* Since 1.1.5 */
typedef struct gbinder_buffer GBinderBuffer;
typedef struct gbinder_client GBinderClient;
typedef struct gbinder_fmq GBinderFmq; /* Since 1.1.14 */
typedef struct gbinder_ipc GBinderIpc;
typedef struct gbinder_local_object GBinderLocalObject;
typedef struct gbinder_local_reply GBinderLocalReply;
@@ -76,16 +78,20 @@ typedef struct gbinder_parent GBinderParent;
/* Basic HIDL types */
#define GBINDER_ALIGNED(x) __attribute__ ((aligned(x)))
typedef struct gbinder_hidl_vec {
union {
guint64 value;
const void* ptr;
} data;
guint32 count;
guint32 owns_buffer;
guint8 owns_buffer;
guint8 pad[3];
} GBinderHidlVec;
#define GBINDER_HIDL_VEC_BUFFER_OFFSET (0)
G_STATIC_ASSERT(sizeof(GBinderHidlVec) == 16);
typedef struct gbinder_hidl_string {
union {
@@ -93,10 +99,51 @@ typedef struct gbinder_hidl_string {
const char* str;
} data;
guint32 len;
guint32 owns_buffer;
guint8 owns_buffer;
guint8 pad[3];
} GBinderHidlString;
#define GBINDER_HIDL_STRING_BUFFER_OFFSET (0)
G_STATIC_ASSERT(sizeof(GBinderHidlString) == 16);
typedef struct gbinder_fds {
guint32 version GBINDER_ALIGNED(4);
guint32 num_fds GBINDER_ALIGNED(4);
guint32 num_ints GBINDER_ALIGNED(4);
} GBINDER_ALIGNED(4) GBinderFds; /* Since 1.1.4 */
/* Actual fds immediately follow GBinderFds: */
#define gbinder_fds_get_fd(fds,i) (((const int*)((fds) + 1))[i])
#define GBINDER_HIDL_FDS_VERSION (12)
G_STATIC_ASSERT(sizeof(GBinderFds) == GBINDER_HIDL_FDS_VERSION);
typedef struct gbinder_hidl_handle {
union {
guint64 value;
const GBinderFds* fds;
} data;
guint8 owns_handle;
guint8 pad[7];
} GBinderHidlHandle; /* Since 1.1.4 */
#define GBINDER_HIDL_HANDLE_VALUE_OFFSET (0)
G_STATIC_ASSERT(sizeof(GBinderHidlHandle) == 16);
typedef struct gbinder_hidl_memory {
union {
guint64 value;
const GBinderFds* fds;
} data;
guint8 owns_buffer;
guint8 pad[7];
guint64 size;
GBinderHidlString name;
} GBinderHidlMemory; /* Since 1.1.4 */
#define GBINDER_HIDL_MEMORY_PTR_OFFSET (0)
#define GBINDER_HIDL_MEMORY_NAME_OFFSET (24)
G_STATIC_ASSERT(sizeof(GBinderHidlMemory) == 40);
/*
* Each RPC call is identified by the interface name returned
@@ -126,6 +173,13 @@ typedef enum gbinder_status {
GBINDER_STATUS_DEAD_OBJECT
} GBINDER_STATUS;
typedef enum gbinder_stability_level {
GBINDER_STABILITY_UNDECLARED = 0,
GBINDER_STABILITY_VENDOR = 0x03,
GBINDER_STABILITY_SYSTEM = 0x0c,
GBINDER_STABILITY_VINTF = 0x3f
} GBINDER_STABILITY_LEVEL; /* Since 1.1.40 */
#define GBINDER_FOURCC(c1,c2,c3,c4) \
(((c1) << 24) | ((c2) << 16) | ((c3) << 8) | (c4))

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

8
misc/coverity_model.c Normal file
View File

@@ -0,0 +1,8 @@
typedef struct gbinder_remote_request GBinderRemoteRequest;
void
gbinder_remote_request_unref(
GBinderRemoteRequest* req)
{
__coverity_free__(req);
}

View File

@@ -1,15 +1,29 @@
Name: libgbinder
Version: 1.1.2
Version: 1.1.40
Release: 0
Summary: Binder client library
License: BSD
URL: https://github.com/mer-hybris/libgbinder
Source: %{name}-%{version}.tar.bz2
%define libglibutil_version 1.0.35
%define glib_version 2.32
%define libglibutil_version 1.0.52
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(glib-2.0) >= %{glib_version}
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 $?)
# make_build macro appeared in rpm 4.12
%{!?make_build:%define make_build make %{_smp_mflags}}
Requires: glib2 >= %{glib_version}
Requires: libglibutil >= %{libglibutil_version}
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
@@ -20,7 +34,7 @@ C interfaces for Android binder
%package devel
Summary: Development library for %{name}
Requires: %{name} = %{version}
Requires: pkgconfig
Requires: pkgconfig(glib-2.0) >= %{glib_version}
%description devel
This package contains the development library for %{name}.
@@ -29,15 +43,18 @@ This package contains the development library for %{name}.
%setup -q
%build
make LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig
make -C test/binder-list release
make -C test/binder-ping release
%make_build LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig
%make_build -C test/binder-bridge -j1 KEEP_SYMBOLS=1 release
%make_build -C test/binder-list -j1 KEEP_SYMBOLS=1 release
%make_build -C test/binder-ping -j1 KEEP_SYMBOLS=1 release
%make_build -C test/binder-call -j1 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
make -C test/binder-ping DESTDIR=%{buildroot} install
make -C test/binder-call DESTDIR=%{buildroot} install
%check
make -C unit test
@@ -49,9 +66,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
@@ -60,11 +81,14 @@ make -C unit test
%package tools
Summary: Binder tools
Requires: %{name} >= %{version}
%description tools
Binder command line utilities
%files tools
%defattr(-,root,root,-)
%{_bindir}/binder-bridge
%{_bindir}/binder-list
%{_bindir}/binder-ping
%{_bindir}/binder-call

272
src/gbinder_bridge.c Normal file
View File

@@ -0,0 +1,272 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_local_request.h"
#include "gbinder_local_reply.h"
#include "gbinder_proxy_object.h"
#include "gbinder_remote_request_p.h"
#include "gbinder_remote_reply.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_servicename.h"
#include "gbinder_servicemanager_p.h"
#include "gbinder_client_p.h"
#include "gbinder_bridge.h"
#include "gbinder_ipc.h"
#include "gbinder_log.h"
#include <gutil_strv.h>
#include <gutil_macros.h>
#include <errno.h>
typedef struct gbinder_bridge_interface {
GBinderBridge* bridge;
char* iface;
char* fqname;
char* src_name;
char* dest_name;
gulong dest_watch_id;
gulong dest_death_id;
GBinderRemoteObject* dest_obj;
GBinderServiceName* src_service;
GBinderProxyObject* proxy;
} GBinderBridgeInterface;
struct gbinder_bridge {
GBinderBridgeInterface** ifaces;
GBinderServiceManager* src;
GBinderServiceManager* dest;
};
/*==========================================================================*
* Implementation
*==========================================================================*/
static
void
gbinder_bridge_dest_drop_remote_object(
GBinderBridgeInterface* bi)
{
if (bi->dest_obj) {
GDEBUG("Detached from %s", bi->fqname);
gbinder_remote_object_remove_handler(bi->dest_obj, bi->dest_death_id);
gbinder_remote_object_unref(bi->dest_obj);
bi->dest_death_id = 0;
bi->dest_obj = NULL;
}
}
static
void
gbinder_bridge_interface_deactivate(
GBinderBridgeInterface* bi)
{
gbinder_bridge_dest_drop_remote_object(bi);
if (bi->proxy) {
gbinder_local_object_drop(GBINDER_LOCAL_OBJECT(bi->proxy));
bi->proxy = NULL;
}
if (bi->src_service) {
gbinder_servicename_unref(bi->src_service);
bi->src_service = NULL;
}
}
static
void
gbinder_bridge_interface_free(
GBinderBridgeInterface* bi)
{
GBinderBridge* bridge = bi->bridge;
gbinder_bridge_interface_deactivate(bi);
gbinder_servicemanager_remove_handler(bridge->dest, bi->dest_watch_id);
g_free(bi->iface);
g_free(bi->fqname);
g_free(bi->src_name);
g_free(bi->dest_name);
gutil_slice_free(bi);
}
static
void
gbinder_bridge_dest_death_proc(
GBinderRemoteObject* obj,
void* user_data)
{
GBinderBridgeInterface* bi = user_data;
GDEBUG("%s has died", bi->fqname);
gbinder_bridge_interface_deactivate(bi);
}
static
void
gbinder_bridge_interface_activate(
GBinderBridgeInterface* bi)
{
GBinderBridge* bridge = bi->bridge;
GBinderServiceManager* src = bridge->src;
GBinderServiceManager* dest = bridge->dest;
if (bi->dest_obj && bi->dest_obj->dead) {
gbinder_bridge_dest_drop_remote_object(bi);
}
if (!bi->dest_obj) {
bi->dest_obj = gbinder_servicemanager_get_service_sync(dest,
bi->fqname, NULL);
if (bi->dest_obj) {
GDEBUG("Attached to %s", bi->fqname);
gbinder_remote_object_ref(bi->dest_obj);
bi->dest_death_id = gbinder_remote_object_add_death_handler
(bi->dest_obj, gbinder_bridge_dest_death_proc, bi);
}
}
if (bi->dest_obj && !bi->proxy) {
bi->proxy = gbinder_proxy_object_new(gbinder_servicemanager_ipc(src),
bi->dest_obj);
}
if (bi->proxy && !bi->src_service) {
bi->src_service = gbinder_servicename_new(src,
GBINDER_LOCAL_OBJECT(bi->proxy), bi->src_name);
}
}
static
void
gbinder_bridge_dest_registration_proc(
GBinderServiceManager* sm,
const char* name,
void* user_data)
{
GBinderBridgeInterface* bi = user_data;
if (!g_strcmp0(name, bi->fqname)) {
GDEBUG("%s has been registered", bi->fqname);
gbinder_bridge_interface_activate(bi);
}
}
static
GBinderBridgeInterface*
gbinder_bridge_interface_new(
GBinderBridge* self,
const char* src_name,
const char* dest_name,
const char* iface)
{
GBinderBridgeInterface* bi = g_slice_new0(GBinderBridgeInterface);
bi->bridge = self;
bi->iface = g_strdup(iface);
bi->fqname = g_strconcat(iface, "/", dest_name, NULL);
bi->src_name = g_strdup(src_name);
bi->dest_name = g_strdup(dest_name);
bi->dest_watch_id = gbinder_servicemanager_add_registration_handler
(self->dest, bi->fqname, gbinder_bridge_dest_registration_proc, bi);
/* Try to activate at startup */
gbinder_bridge_interface_activate(bi);
return bi;
}
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderBridge*
gbinder_bridge_new(
const char* name,
const char* const* ifaces,
GBinderServiceManager* src,
GBinderServiceManager* dest) /* Since 1.1.5 */
{
return gbinder_bridge_new2(name, NULL, ifaces, src, dest);
}
GBinderBridge*
gbinder_bridge_new2(
const char* src_name,
const char* dest_name,
const char* const* ifaces,
GBinderServiceManager* src,
GBinderServiceManager* dest) /* Since 1.1.6 */
{
const guint n = gutil_strv_length((const GStrV*)ifaces);
if (!src_name) {
src_name = dest_name;
} else if (!dest_name) {
dest_name = src_name;
}
if (G_LIKELY(src_name) && G_LIKELY(n) && G_LIKELY(src) && G_LIKELY(dest)) {
GBinderBridge* self = g_slice_new0(GBinderBridge);
guint i;
self->src = gbinder_servicemanager_ref(src);
self->dest = gbinder_servicemanager_ref(dest);
self->ifaces = g_new(GBinderBridgeInterface*, n + 1);
for (i = 0; i < n; i++) {
self->ifaces[i] = gbinder_bridge_interface_new(self,
src_name, dest_name, ifaces[i]);
}
self->ifaces[i] = NULL;
return self;
}
return NULL;
}
void
gbinder_bridge_free(
GBinderBridge* self)
{
if (G_LIKELY(self)) {
GBinderBridgeInterface** bi = self->ifaces;
while (*bi) {
gbinder_bridge_interface_free(*bi);
bi++;
}
gbinder_servicemanager_unref(self->src);
gbinder_servicemanager_unref(self->dest);
g_free(self->ifaces);
gutil_slice_free(self);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

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
@@ -112,6 +112,47 @@ gbinder_buffer_contents_unref(
}
}
/*==========================================================================*
* GBinderBufferContentsList
* It's actually a GSList containing GBinderBufferContents refs.
*==========================================================================*/
GBinderBufferContentsList*
gbinder_buffer_contents_list_add(
GBinderBufferContentsList* list,
GBinderBufferContents* contents)
{
/* Prepend rather than append for better efficiency */
return contents ? (GBinderBufferContentsList*) g_slist_prepend((GSList*)
list, gbinder_buffer_contents_ref(contents)) : list;
}
GBinderBufferContentsList*
gbinder_buffer_contents_list_dup(
GBinderBufferContentsList* list)
{
GSList* out = NULL;
if (list) {
GSList* l = (GSList*) list;
/* The order gets reversed but it doesn't matter */
while (l) {
out = g_slist_prepend(out, gbinder_buffer_contents_ref(l->data));
l = l->next;
}
}
return (GBinderBufferContentsList*) out;
}
void
gbinder_buffer_contents_list_free(
GBinderBufferContentsList* list)
{
g_slist_free_full((GSList*) list, (GDestroyNotify)
gbinder_buffer_contents_unref);
}
/*==========================================================================*
* GBinderBuffer
*==========================================================================*/
@@ -210,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-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:
*
@@ -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)
@@ -88,6 +93,22 @@ gbinder_buffer_contents_unref(
GBinderBufferContents* contents)
GBINDER_INTERNAL;
GBinderBufferContentsList*
gbinder_buffer_contents_list_add(
GBinderBufferContentsList* list,
GBinderBufferContents* contents)
GBINDER_INTERNAL;
GBinderBufferContentsList*
gbinder_buffer_contents_list_dup(
GBinderBufferContentsList* list)
GBINDER_INTERNAL;
void
gbinder_buffer_contents_list_free(
GBinderBufferContentsList* list)
GBINDER_INTERNAL;
#endif /* GBINDER_BUFFER_PRIVATE_H */
/*

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:
*
@@ -178,6 +178,77 @@ gbinder_client_transact_destroy(
g_slice_free(GBinderClientTx, tx);
}
/*==========================================================================*
* Internal interface
*==========================================================================*/
GBinderRemoteReply*
gbinder_client_transact_sync_reply2(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
int* status,
const GBinderIpcSyncApi* api)
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
if (r) {
req = r->basic_req;
}
}
if (req) {
return api->sync_reply(obj->ipc, obj->handle, code, req,
status);
} else {
GWARN("Unable to build empty request for tx code %u", code);
}
} else {
GDEBUG("Refusing to perform transaction with a dead object");
}
}
return NULL;
}
int
gbinder_client_transact_sync_oneway2(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
const GBinderIpcSyncApi* api)
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
if (r) {
req = r->basic_req;
}
}
if (req) {
return api->sync_oneway(obj->ipc, obj->handle, code, req);
} else {
GWARN("Unable to build empty request for tx code %u", code);
}
} else {
GDEBUG("Refusing to perform transaction with a dead object");
return (-ESTALE);
}
}
return (-EINVAL);
}
/*==========================================================================*
* Interface
*==========================================================================*/
@@ -211,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;
}
@@ -280,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;
}
@@ -300,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;
@@ -319,25 +409,8 @@ gbinder_client_transact_sync_reply(
GBinderLocalRequest* req,
int* status)
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
if (r) {
req = r->basic_req;
}
}
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
code, req, status);
}
GDEBUG("Refusing to perform transaction with a dead object");
}
return NULL;
return gbinder_client_transact_sync_reply2(self, code, req, status,
&gbinder_ipc_sync_main);
}
int
@@ -346,26 +419,8 @@ gbinder_client_transact_sync_oneway(
guint32 code,
GBinderLocalRequest* req)
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
if (r) {
req = r->basic_req;
}
}
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
code, req);
}
GDEBUG("Refusing to perform transaction with a dead object");
return (-ESTALE);
}
return (-EINVAL);
return gbinder_client_transact_sync_oneway2(self, code, req,
&gbinder_ipc_sync_main);
}
gulong
@@ -382,13 +437,6 @@ gbinder_client_transact(
GBinderRemoteObject* obj = self->remote;
if (G_LIKELY(!obj->dead)) {
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
tx->client = gbinder_client_ref(self);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
@@ -398,12 +446,22 @@ gbinder_client_transact(
req = r->basic_req;
}
}
if (req) {
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
return gbinder_ipc_transact(obj->ipc, obj->handle, code,
flags, req, gbinder_client_transact_reply,
gbinder_client_transact_destroy, tx);
tx->client = gbinder_client_ref(self);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
return gbinder_ipc_transact(obj->ipc, obj->handle, code,
flags, req, gbinder_client_transact_reply,
gbinder_client_transact_destroy, tx);
} else {
GWARN("Unable to build empty request for tx code %u", code);
}
} else {
GDEBUG("Refusing to perform transaction with a dead object");
}
GDEBUG("Refusing to perform transaction with a dead object");
}
return 0;
}

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:
*
@@ -41,6 +41,24 @@ struct gbinder_client {
GBinderRemoteObject* remote;
};
GBinderRemoteReply*
gbinder_client_transact_sync_reply2(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
int* status,
const GBinderIpcSyncApi* api)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
int
gbinder_client_transact_sync_oneway2(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
const GBinderIpcSyncApi* api)
GBINDER_INTERNAL;
#define gbinder_client_ipc(client) ((client)->remote->ipc)
#endif /* GBINDER_CLIENT_PRIVATE_H */

View File

@@ -113,9 +113,54 @@ 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_protocol[] = {
{ "/dev/binder", "aidl4" },
{ "/dev/vndbinder", "aidl4" },
{ NULL, NULL }
};
static const GBinderConfigPresetGroup gbinder_config_31[] = {
{ GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_31_protocol },
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_30_servicemanager },
{ NULL, NULL }
};
/* API level 33 - reverts back to AIDL3 protocol */
static const GBinderConfigPresetGroup gbinder_config_33[] = {
{ GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_30_protocol },
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_30_servicemanager },
{ NULL, NULL }
};
/* Presets sorted by API level in descending order */
static const GBinderConfigPreset gbinder_config_presets[] = {
{ 33, gbinder_config_33 },
{ 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-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -32,6 +32,7 @@
#include "gbinder_driver.h"
#include "gbinder_buffer_p.h"
#include "gbinder_cleanup.h"
#include "gbinder_handler.h"
#include "gbinder_io.h"
#include "gbinder_local_object_p.h"
@@ -60,6 +61,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/ioctl.h>
/* BINDER_VM_SIZE copied from native/libs/binder/ProcessState.cpp */
#define BINDER_VM_SIZE ((1024*1024) - sysconf(_SC_PAGE_SIZE)*2)
@@ -80,14 +82,35 @@ struct gbinder_driver {
void* vm;
gsize vmsize;
char* dev;
const char* name;
const GBinderIo* io;
const GBinderRpcProtocol* protocol;
};
typedef struct gbinder_io_read_buf {
GBinderIoBuf buf;
typedef struct gbinder_driver_read_buf {
GBinderIoBuf io;
gsize offset;
} GBinderDriverReadBuf;
typedef struct gbinder_driver_read_data {
GBinderDriverReadBuf buf;
guint8 data[GBINDER_IO_READ_BUFFER_SIZE];
} GBinderIoReadBuf;
} GBinderDriverReadData;
typedef struct gbinder_driver_context {
GBinderDriverReadBuf* rbuf;
GBinderObjectRegistry* reg;
GBinderHandler* handler;
GBinderCleanup* unrefs;
GBinderBufferContentsList* bufs;
} GBinderDriverContext;
static
int
gbinder_driver_txstatus(
GBinderDriver* self,
GBinderDriverContext* context,
GBinderRemoteReply* reply);
/*==========================================================================*
* Implementation
@@ -140,18 +163,54 @@ gbinder_driver_verbose_transaction_data(
guint n = 0;
while (tx->objects[n]) n++;
if (tx->status) {
GVERBOSE("> %s %d (%u bytes, %u objects)", name, tx->status,
(guint)tx->size, n);
if (tx->target) {
GVERBOSE("> %s %p %d (%u bytes, %u objects)", name,
tx->target, tx->status, (guint)tx->size, n);
} else {
GVERBOSE("> %s %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 {
GVERBOSE("> %s (%u bytes, %u objects)", name,
(guint)tx->size, n);
if (tx->target) {
GVERBOSE("> %s %p (%u bytes, %u objects)", name,
tx->target, (guint)tx->size, n);
} else {
GVERBOSE("> %s (%u bytes, %u objects)", name, (guint)
tx->size, n);
}
}
} else {
if (tx->status) {
GVERBOSE("> %s %d (%u bytes)", name, tx->status,
(guint)tx->size);
if (tx->target) {
GVERBOSE("> %s %p %d (%u bytes)", name, tx->target,
tx->status, (guint)tx->size);
} else {
GVERBOSE("> %s %d (%u bytes)", name, tx->status, (guint)
tx->size);
}
} else if (tx->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 {
GVERBOSE("> %s (%u bytes)", name, (guint)tx->size);
if (tx->target) {
GVERBOSE("> %s %p (%u bytes)", name, tx->target, (guint)
tx->size);
} else {
GVERBOSE("> %s (%u bytes)", name, (guint)tx->size);
}
}
}
}
@@ -175,9 +234,11 @@ gbinder_driver_write(
gbinder_driver_verbose_dump('<',
buf->ptr + buf->consumed,
buf->size - buf->consumed);
GVERBOSE_("%u/%u", (guint)buf->consumed, (guint)buf->size);
GVERBOSE("gbinder_driver_write(%d) %u/%u", self->fd,
(guint)buf->consumed, (guint)buf->size);
err = self->io->write_read(self->fd, buf, NULL);
GVERBOSE_("%u/%u err %d", (guint)buf->consumed, (guint)buf->size, err);
GVERBOSE("gbinder_driver_write(%d) %u/%u err %d", self->fd,
(guint)buf->consumed, (guint)buf->size, err);
}
return err;
}
@@ -187,11 +248,24 @@ int
gbinder_driver_write_read(
GBinderDriver* self,
GBinderIoBuf* write,
GBinderIoBuf* read)
GBinderDriverReadBuf* rbuf)
{
int err = (-EAGAIN);
GBinderIoBuf rio;
GBinderIoBuf* read;
/* rbuf is never NULL */
if (rbuf->offset) {
rio.ptr = rbuf->io.ptr + rbuf->offset;
rio.size = rbuf->io.size - rbuf->offset;
rio.consumed = rbuf->io.consumed - rbuf->offset;
read = &rio;
} else {
read = &rbuf->io;
}
while (err == (-EAGAIN)) {
#if GUTIL_LOG_VERBOSE
const gsize were_consumed = read ? read->consumed : 0;
if (GLOG_ENABLED(GLOG_LEVEL_VERBOSE)) {
@@ -200,21 +274,23 @@ gbinder_driver_write_read(
write->ptr + write->consumed,
write->size - write->consumed);
}
GVERBOSE_("write %u/%u read %u/%u",
(guint)(write ? write->consumed : 0),
(guint)(write ? write->size : 0),
(guint)(read ? read->consumed : 0),
(guint)(read ? read->size : 0));
GVERBOSE("gbinder_driver_write_read(%d) "
"write %u/%u read %u/%u", self->fd,
(guint)(write ? write->consumed : 0),
(guint)(write ? write->size : 0),
(guint)(read ? read->consumed : 0),
(guint)(read ? read->size : 0));
}
#endif /* GUTIL_LOG_VERBOSE */
err = self->io->write_read(self->fd, write, read);
#if GUTIL_LOG_VERBOSE
if (GLOG_ENABLED(GLOG_LEVEL_VERBOSE)) {
GVERBOSE_("write %u/%u read %u/%u err %d",
(guint)(write ? write->consumed : 0),
(guint)(write ? write->size : 0),
(guint)(read ? read->consumed : 0),
(guint)(read ? read->size : 0), err);
GVERBOSE("gbinder_driver_write_read(%d) "
"write %u/%u read %u/%u err %d", self->fd,
(guint)(write ? write->consumed : 0),
(guint)(write ? write->size : 0),
(guint)(read ? read->consumed : 0),
(guint)(read ? read->size : 0), err);
if (read) {
gbinder_driver_verbose_dump('>',
read->ptr + were_consumed,
@@ -223,6 +299,10 @@ gbinder_driver_write_read(
}
#endif /* GUTIL_LOG_VERBOSE */
}
if (rbuf->offset) {
rbuf->io.consumed = rio.consumed + rbuf->offset;
}
return err;
}
@@ -280,55 +360,78 @@ gbinder_driver_cmd_data(
static
gboolean
gbinder_driver_death_notification(
gbinder_driver_handle_cookie(
GBinderDriver* self,
guint32 cmd,
GBinderRemoteObject* obj)
{
GBinderIoBuf write;
guint8 buf[4 + GBINDER_MAX_DEATH_NOTIFICATION_SIZE];
guint8 buf[4 + GBINDER_MAX_HANDLE_COOKIE_SIZE];
guint32* data = (guint32*)buf;
data[0] = cmd;
memset(&write, 0, sizeof(write));
write.ptr = (uintptr_t)buf;
write.size = 4 + self->io->encode_death_notification(data + 1, obj);
write.size = 4 + self->io->encode_handle_cookie(data + 1, obj);
return gbinder_driver_write(self, &write) >= 0;
}
static
void
gbinder_driver_read_init(
GBinderIoReadBuf* rb)
GBinderDriverReadData* read)
{
rb->buf.ptr = (uintptr_t)(rb->data);
rb->buf.size = sizeof(rb->data);
rb->buf.consumed = 0;
/*
* It shouldn't be necessary to zero-initialize the buffer but
* valgrind complains about access to uninitialised data if we
* don't do so. Oh well...
* It shouldn't be necessary to zero-initialize the whole buffer
* but valgrind complains about access to uninitialised data if
* we don't do so. Oh well...
*/
memset(rb->data, 0, sizeof(rb->data));
memset(read, 0, sizeof(*read));
read->buf.io.ptr = GPOINTER_TO_SIZE(read->data);
read->buf.io.size = sizeof(read->data);
}
static
void
gbinder_driver_context_init(
GBinderDriverContext* context,
GBinderDriverReadBuf* rbuf,
GBinderObjectRegistry* reg,
GBinderHandler* handler)
{
context->rbuf = rbuf;
context->reg = reg;
context->handler = handler;
context->unrefs = NULL;
context->bufs = NULL;
}
static
void
gbinder_driver_context_cleanup(
GBinderDriverContext* context)
{
gbinder_cleanup_free(context->unrefs);
gbinder_buffer_contents_list_free(context->bufs);
}
static
guint32
gbinder_driver_next_command(
GBinderDriver* self,
const GBinderIoBuf* buf)
const GBinderDriverReadBuf* rbuf)
{
const size_t remaining = buf->size - buf->consumed;
guint32 cmd = 0;
if (rbuf->io.consumed > rbuf->offset) {
const gsize remaining = rbuf->io.consumed - rbuf->offset;
if (remaining >= sizeof(cmd)) {
int datalen;
/* The size of the data to follow is encoded in the command code */
cmd = *(guint32*)(buf->ptr + buf->consumed);
datalen = _IOC_SIZE(cmd);
if (remaining >= sizeof(cmd) + datalen) {
return cmd;
if (remaining >= 4) {
/* The size of the data to follow is encoded in the command code */
const guint32 cmd = *(guint32*)(rbuf->io.ptr + rbuf->offset);
const guint datalen = _IOC_SIZE(cmd);
if (remaining >= 4 + datalen) {
return cmd;
}
}
}
return 0;
@@ -377,18 +480,18 @@ gbinder_driver_reply_data(
GUtilIntArray* offsets = gbinder_output_data_offsets(data);
void* offsets_buf = NULL;
/* Build BC_TRANSACTION */
/* Build BC_REPLY */
if (extra_buffers) {
GVERBOSE("< BC_REPLY_SG %u bytes", (guint)extra_buffers);
gbinder_driver_verbose_dump_bytes(' ', data->bytes);
*cmd = io->bc.reply_sg;
len += io->encode_transaction_sg(buf + len, 0, 0, data->bytes, 0,
len += io->encode_reply_sg(buf + len, 0, 0, data->bytes,
offsets, &offsets_buf, extra_buffers);
} else {
GVERBOSE("< BC_REPLY");
gbinder_driver_verbose_dump_bytes(' ', data->bytes);
*cmd = io->bc.reply;
len += io->encode_transaction(buf + len, 0, 0, data->bytes, 0,
len += io->encode_reply(buf + len, 0, 0, data->bytes,
offsets, &offsets_buf);
}
@@ -403,7 +506,7 @@ gbinder_driver_reply_data(
write.ptr = (uintptr_t)buf;
write.size = len;
write.consumed = 0;
status = gbinder_driver_write(self, &write) >= 0;
status = gbinder_driver_write(self, &write);
g_free(offsets_buf);
return status >= 0;
@@ -413,16 +516,16 @@ static
void
gbinder_driver_handle_transaction(
GBinderDriver* self,
GBinderObjectRegistry* reg,
GBinderHandler* h,
GBinderDriverContext* context,
const void* data)
{
GBinderLocalReply* reply = NULL;
GBinderObjectRegistry* reg = context->reg;
GBinderRemoteRequest* req;
GBinderIoTxData tx;
GBinderLocalObject* obj;
const char* iface;
int status = -EBADMSG;
int txstatus = -EBADMSG;
self->io->decode_transaction_data(data, &tx);
gbinder_driver_verbose_transaction_data("BR_TRANSACTION", &tx);
@@ -431,9 +534,13 @@ gbinder_driver_handle_transaction(
/* Transfer data ownership to the request */
if (tx.data && tx.size) {
GBinderBuffer* buf = gbinder_buffer_new(self,
tx.data, tx.size, tx.objects);
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
gbinder_remote_request_set_data(req, tx.code,
gbinder_buffer_new(self, tx.data, tx.size, tx.objects));
gbinder_remote_request_set_data(req, tx.code, buf);
context->bufs = gbinder_buffer_contents_list_add(context->bufs,
gbinder_buffer_contents(buf));
} else {
GASSERT(!tx.objects);
gbinder_driver_free_buffer(self, tx.data);
@@ -444,7 +551,7 @@ gbinder_driver_handle_transaction(
switch (gbinder_local_object_can_handle_transaction(obj, iface, tx.code)) {
case GBINDER_LOCAL_TRANSACTION_LOOPER:
reply = gbinder_local_object_handle_looper_transaction(obj, req,
tx.code, tx.flags, &status);
tx.code, tx.flags, &txstatus);
break;
case GBINDER_LOCAL_TRANSACTION_SUPPORTED:
/*
@@ -452,22 +559,35 @@ gbinder_driver_handle_transaction(
* executed on the main thread, meaning that we can call the
* local object directly.
*/
reply = h ? gbinder_handler_transact(h, obj, req, tx.code, tx.flags,
&status) : gbinder_local_object_handle_transaction(obj, req,
tx.code, tx.flags, &status);
reply = context->handler ?
gbinder_handler_transact(context->handler, obj, req, tx.code,
tx.flags, &txstatus) :
gbinder_local_object_handle_transaction(obj, req, tx.code,
tx.flags, &txstatus);
break;
default:
GWARN("Unhandled transaction %s 0x%08x", iface, tx.code);
GWARN("Unhandled transaction %s 0x%08x from %s", iface, tx.code,
self->name);
break;
}
/* No reply for one-way transactions */
if (!(tx.flags & GBINDER_TX_FLAG_ONEWAY)) {
if (reply) {
context->bufs = gbinder_buffer_contents_list_add(context->bufs,
gbinder_local_reply_contents(reply));
gbinder_driver_reply_data(self, gbinder_local_reply_data(reply));
} else {
gbinder_driver_reply_status(self, status);
gbinder_driver_reply_status(self, txstatus);
}
/* Wait until the reply is handled */
do {
txstatus = gbinder_driver_write_read(self, NULL, context->rbuf);
if (txstatus >= 0) {
txstatus = gbinder_driver_txstatus(self, context, NULL);
}
} while (txstatus == (-EAGAIN));
}
/* Free the data allocated for the transaction */
@@ -476,23 +596,45 @@ gbinder_driver_handle_transaction(
gbinder_local_object_unref(obj);
}
static
void
gbinder_driver_cleanup_decrefs(
gpointer pointer)
{
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(pointer);
gbinder_local_object_handle_decrefs(obj);
gbinder_local_object_unref(obj);
}
static
void
gbinder_driver_cleanup_release(
gpointer pointer)
{
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(pointer);
gbinder_local_object_handle_release(obj);
gbinder_local_object_unref(obj);
}
static
void
gbinder_driver_handle_command(
GBinderDriver* self,
GBinderObjectRegistry* reg,
GBinderHandler* handler,
GBinderDriverContext* context,
guint32 cmd,
const void* data)
{
const GBinderIo* io = self->io;
GBinderObjectRegistry* reg = context->reg;
if (cmd == io->br.noop) {
GVERBOSE("> BR_NOOP");
} else if (cmd == io->br.ok) {
GVERBOSE("> BR_OK");
} else if (cmd == io->br.transaction_complete) {
GVERBOSE("> BR_TRANSACTION_COMPLETE");
GVERBOSE("> BR_TRANSACTION_COMPLETE (?)");
} else if (cmd == io->br.spawn_looper) {
GVERBOSE("> BR_SPAWN_LOOPER");
} else if (cmd == io->br.finished) {
@@ -500,7 +642,7 @@ gbinder_driver_handle_command(
} else if (cmd == io->br.increfs) {
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
GBinderLocalObject* obj = gbinder_object_registry_get_local
(reg, io->decode_binder_ptr_cookie(data));
(reg, io->decode_ptr_cookie(data));
GVERBOSE("> BR_INCREFS %p", obj);
gbinder_local_object_handle_increfs(obj);
@@ -509,114 +651,150 @@ gbinder_driver_handle_command(
gbinder_driver_cmd_data(self, io->bc.increfs_done, data, buf);
} else if (cmd == io->br.decrefs) {
GBinderLocalObject* obj = gbinder_object_registry_get_local
(reg, io->decode_binder_ptr_cookie(data));
(reg, io->decode_ptr_cookie(data));
GVERBOSE("> BR_DECREFS %p", obj);
gbinder_local_object_handle_decrefs(obj);
gbinder_local_object_unref(obj);
if (obj) {
/*
* Unrefs must be processed only after clearing the incoming
* command queue.
*/
context->unrefs = gbinder_cleanup_add(context->unrefs,
gbinder_driver_cleanup_decrefs, obj);
}
} else if (cmd == io->br.acquire) {
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
GBinderLocalObject* obj = gbinder_object_registry_get_local
(reg, io->decode_binder_ptr_cookie(data));
(reg, io->decode_ptr_cookie(data));
GVERBOSE("> BR_ACQUIRE %p", obj);
gbinder_local_object_handle_acquire(obj);
gbinder_local_object_unref(obj);
GVERBOSE("< BC_ACQUIRE_DONE %p", obj);
gbinder_driver_cmd_data(self, io->bc.acquire_done, data, buf);
if (obj) {
/* BC_ACQUIRE_DONE will be sent after the request is handled */
gbinder_local_object_handle_acquire(obj, context->bufs);
gbinder_local_object_unref(obj);
} else {
/* This shouldn't normally happen. Just send the same data back. */
GVERBOSE("< BC_ACQUIRE_DONE");
gbinder_driver_cmd_data(self, io->bc.acquire_done, data, buf);
}
} else if (cmd == io->br.release) {
GBinderLocalObject* obj = gbinder_object_registry_get_local
(reg, io->decode_binder_ptr_cookie(data));
(reg, io->decode_ptr_cookie(data));
GVERBOSE("> BR_RELEASE %p", obj);
gbinder_local_object_handle_release(obj);
gbinder_local_object_unref(obj);
if (obj) {
/*
* Unrefs must be processed only after clearing the incoming
* command queue.
*/
context->unrefs = gbinder_cleanup_add(context->unrefs,
gbinder_driver_cleanup_release, obj);
}
} else if (cmd == io->br.transaction) {
gbinder_driver_handle_transaction(self, reg, handler, data);
gbinder_driver_handle_transaction(self, context, data);
} else if (cmd == io->br.dead_binder) {
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
guint64 handle = 0;
GBinderRemoteObject* obj;
io->decode_cookie(data, &handle);
GVERBOSE("> BR_DEAD_BINDER %llu", (long long unsigned int)handle);
obj = gbinder_object_registry_get_remote(reg, (guint32)handle);
GVERBOSE("> BR_DEAD_BINDER 0x%08llx", (long long unsigned int) handle);
obj = gbinder_object_registry_get_remote(reg, (guint32)handle,
REMOTE_REGISTRY_DONT_CREATE);
if (obj) {
/* BC_DEAD_BINDER_DONE will be sent after the request is handled */
gbinder_remote_object_handle_death_notification(obj);
gbinder_remote_object_unref(obj);
} else {
guint8 buf[4 + GBINDER_MAX_COOKIE_SIZE];
/* This shouldn't normally happen. Just send the same data back. */
GVERBOSE("< BC_DEAD_BINDER_DONE 0x%08llx", (long long unsigned int)
handle);
gbinder_driver_cmd_data(self, io->bc.dead_binder_done, data, buf);
}
GVERBOSE("< BC_DEAD_BINDER_DONE %llu", (long long unsigned int)handle);
gbinder_driver_cmd_data(self, io->bc.dead_binder_done, data, buf);
} else if (cmd == io->br.clear_death_notification_done) {
GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE");
#if GUTIL_LOG_VERBOSE
if (GLOG_ENABLED(GLOG_LEVEL_VERBOSE)) {
guint64 handle = 0;
io->decode_cookie(data, &handle);
GVERBOSE("> BR_CLEAR_DEATH_NOTIFICATION_DONE 0x%08llx",
(long long unsigned int) handle);
}
#endif /* GUTIL_LOG_VERBOSE */
} else {
#pragma message("TODO: handle more commands from the driver")
GWARN("Unexpected command 0x%08x", cmd);
}
}
static
void
gbinder_driver_compact_read_buf(
GBinderDriverReadBuf* buf)
{
/*
* Move the data to the beginning of the buffer to make room for the
* next portion of data (in case if we need one)
*/
if (buf->io.consumed > buf->offset) {
const gsize unprocessed = buf->io.consumed - buf->offset;
guint8* data = GSIZE_TO_POINTER(buf->io.ptr);
memmove(data, data + buf->offset, unprocessed);
buf->io.consumed = unprocessed;
} else {
buf->io.consumed = 0;
}
buf->offset = 0;
}
static
void
gbinder_driver_handle_commands(
GBinderDriver* self,
GBinderObjectRegistry* reg,
GBinderHandler* handler,
GBinderIoReadBuf* rb)
GBinderDriverContext* context)
{
GBinderDriverReadBuf* rbuf = context->rbuf;
guint32 cmd;
gsize unprocessed;
GBinderIoBuf buf;
buf.ptr = rb->buf.ptr;
buf.size = rb->buf.consumed;
buf.consumed = 0;
while ((cmd = gbinder_driver_next_command(self, &buf)) != 0) {
const size_t datalen = _IOC_SIZE(cmd);
const size_t total = datalen + sizeof(cmd);
while ((cmd = gbinder_driver_next_command(self, rbuf)) != 0) {
const gsize datalen = _IOC_SIZE(cmd);
const gsize total = datalen + sizeof(cmd);
const void* data = GSIZE_TO_POINTER(rbuf->io.ptr + rbuf->offset + 4);
/* Handle this command */
gbinder_driver_handle_command(self, reg, handler, cmd,
(void*)(buf.ptr + buf.consumed + sizeof(cmd)));
/* Switch to the next packet in the buffer */
buf.consumed += total;
rbuf->offset += total;
gbinder_driver_handle_command(self, context, cmd, data);
}
/* Move the data to the beginning of the buffer to make room for the
* next portion of data (in case if we need one) */
unprocessed = buf.size - buf.consumed;
memmove(rb->data, rb->data + buf.consumed, unprocessed);
rb->buf.consumed = unprocessed;
gbinder_driver_compact_read_buf(rbuf);
}
static
int
gbinder_driver_txstatus(
GBinderDriver* self,
GBinderObjectRegistry* reg,
GBinderHandler* handler,
GBinderIoReadBuf* rb,
GBinderDriverContext* context,
GBinderRemoteReply* reply)
{
guint32 cmd;
gsize unprocessed;
int txstatus = (-EAGAIN);
GBinderIoBuf buf;
GBinderDriverReadBuf* rbuf = context->rbuf;
const guint8* buf = GSIZE_TO_POINTER(rbuf->io.ptr);
const GBinderIo* io = self->io;
buf.ptr = rb->buf.ptr;
buf.size = rb->buf.consumed;
buf.consumed = 0;
while (txstatus == (-EAGAIN) && (cmd =
gbinder_driver_next_command(self, &buf)) != 0) {
gbinder_driver_next_command(self, context->rbuf)) != 0) {
/* The size of the data is encoded in the command code */
const size_t datalen = _IOC_SIZE(cmd);
const size_t total = datalen + sizeof(cmd);
const void* data = (void*)(buf.ptr + buf.consumed + sizeof(cmd));
const gsize datalen = _IOC_SIZE(cmd);
const gsize total = datalen + sizeof(cmd);
const void* data = buf + rbuf->offset + sizeof(cmd);
/* Handle the packet */
/* Swallow this packet */
rbuf->offset += total;
/* Handle the command */
if (cmd == io->br.transaction_complete) {
GVERBOSE("> BR_TRANSACTION_COMPLETE");
if (!reply) {
@@ -634,32 +812,44 @@ gbinder_driver_txstatus(
io->decode_transaction_data(data, &tx);
gbinder_driver_verbose_transaction_data("BR_REPLY", &tx);
/* Transfer data ownership to the request */
if (tx.data && tx.size) {
/* Transfer data ownership to the reply */
if (tx.data && tx.size && reply) {
GBinderBuffer* buf = gbinder_buffer_new(self,
tx.data, tx.size, tx.objects);
gbinder_driver_verbose_dump(' ', (uintptr_t)tx.data, tx.size);
gbinder_remote_reply_set_data(reply,
gbinder_buffer_new(self, tx.data, tx.size, tx.objects));
gbinder_remote_reply_set_data(reply, buf);
context->bufs = gbinder_buffer_contents_list_add(context->bufs,
gbinder_buffer_contents(buf));
} else {
GASSERT(!tx.objects);
gbinder_driver_free_buffer(self, tx.data);
}
txstatus = tx.status;
GASSERT(txstatus != (-EAGAIN));
if (txstatus == (-EAGAIN)) txstatus = (-EFAULT);
/*
* Filter out special cases. It's a bit unfortunate that
* libgbinder API historically mixed TF_STATUS_CODE payload
* with special delivery errors. It's not a bit deal though,
* because in real life TF_STATUS_CODE transactions are not
* being used that often, if at all.
*/
switch (tx.status) {
case (-EAGAIN):
case GBINDER_STATUS_FAILED:
case GBINDER_STATUS_DEAD_OBJECT:
txstatus = (-EFAULT);
GWARN("Replacing tx status %d with %d", tx.status, txstatus);
break;
default:
txstatus = tx.status;
break;
}
} else {
gbinder_driver_handle_command(self, reg, handler, cmd, data);
gbinder_driver_handle_command(self, context, cmd, data);
}
/* Switch to the next packet in the buffer */
buf.consumed += total;
}
/* Move the data to the beginning of the buffer to make room for the
* next portion of data (in case if we need one) */
unprocessed = buf.size - buf.consumed;
memmove(rb->data, rb->data + buf.consumed, unprocessed);
rb->buf.consumed = unprocessed;
gbinder_driver_compact_read_buf(rbuf);
return txstatus;
}
@@ -707,13 +897,16 @@ 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,
max_threads, strerror(errno));
}
/* Choose the protocol based on the device name
* if none is explicitely specified */
* if none is explicitly specified */
self->protocol = protocol ? protocol :
gbinder_rpc_protocol_for_device(dev);
return self;
@@ -746,11 +939,23 @@ gbinder_driver_unref(
{
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_driver_close(self);
g_free(self->dev);
g_slice_free(GBinderDriver, self);
}
}
void
gbinder_driver_close(
GBinderDriver* self)
{
if (self->vm) {
GDEBUG("Closing %s", self->dev);
gbinder_system_munmap(self->vm, self->vmsize);
gbinder_system_close(self->fd);
g_free(self->dev);
g_slice_free(GBinderDriver, self);
self->fd = -1;
self->vm = NULL;
self->vmsize = 0;
}
}
@@ -809,6 +1014,55 @@ gbinder_driver_io(
return self->io;
}
const GBinderRpcProtocol*
gbinder_driver_protocol(
GBinderDriver* self)
{
return self->protocol;
}
gboolean
gbinder_driver_acquire_done(
GBinderDriver* self,
GBinderLocalObject* obj)
{
GBinderIoBuf write;
guint8 buf[4 + GBINDER_MAX_PTR_COOKIE_SIZE];
guint32* data = (guint32*)buf;
const GBinderIo* io = self->io;
data[0] = io->bc.acquire_done;
memset(&write, 0, sizeof(write));
write.ptr = (uintptr_t)buf;
write.size = 4 + io->encode_ptr_cookie(data + 1, obj);
GVERBOSE("< BC_ACQUIRE_DONE %p", obj);
return gbinder_driver_write(self, &write) >= 0;
}
gboolean
gbinder_driver_dead_binder_done(
GBinderDriver* self,
GBinderRemoteObject* obj)
{
if (G_LIKELY(obj)) {
GBinderIoBuf write;
guint8 buf[4 + GBINDER_MAX_COOKIE_SIZE];
guint32* data = (guint32*)buf;
const GBinderIo* io = self->io;
data[0] = io->bc.dead_binder_done;
memset(&write, 0, sizeof(write));
write.ptr = (uintptr_t)buf;
write.size = 4 + io->encode_cookie(data + 1, obj->handle);
GVERBOSE("< BC_DEAD_BINDER_DONE 0x%08x", obj->handle);
return gbinder_driver_write(self, &write) >= 0;
} else {
return FALSE;
}
}
gboolean
gbinder_driver_request_death_notification(
GBinderDriver* self,
@@ -816,7 +1070,7 @@ gbinder_driver_request_death_notification(
{
if (G_LIKELY(obj)) {
GVERBOSE("< BC_REQUEST_DEATH_NOTIFICATION 0x%08x", obj->handle);
return gbinder_driver_death_notification(self,
return gbinder_driver_handle_cookie(self,
self->io->bc.request_death_notification, obj);
} else {
return FALSE;
@@ -830,7 +1084,7 @@ gbinder_driver_clear_death_notification(
{
if (G_LIKELY(obj)) {
GVERBOSE("< BC_CLEAR_DEATH_NOTIFICATION 0x%08x", obj->handle);
return gbinder_driver_death_notification(self,
return gbinder_driver_handle_cookie(self,
self->io->bc.clear_death_notification, obj);
} else {
return FALSE;
@@ -919,7 +1173,7 @@ gbinder_driver_free_buffer(
write.ptr = (uintptr_t)wbuf;
write.size = len;
write.consumed = 0;
gbinder_driver_write(self, &write);
(void) gbinder_driver_write(self, &write);
}
}
@@ -945,23 +1199,26 @@ gbinder_driver_read(
GBinderObjectRegistry* reg,
GBinderHandler* handler)
{
GBinderIoReadBuf rb;
GBinderDriverReadData read;
GBinderDriverContext context;
int ret;
gbinder_driver_read_init(&rb);
ret = gbinder_driver_write_read(self, NULL, &rb.buf);
gbinder_driver_read_init(&read);
gbinder_driver_context_init(&context, &read.buf, reg, handler);
ret = gbinder_driver_write_read(self, NULL, context.rbuf);
if (ret >= 0) {
/* Loop until we have handled all the incoming commands */
gbinder_driver_handle_commands(self, reg, handler, &rb);
while (rb.buf.consumed && gbinder_handler_can_loop(handler)) {
ret = gbinder_driver_write_read(self, NULL, &rb.buf);
gbinder_driver_handle_commands(self, &context);
while (read.buf.io.consumed && gbinder_handler_can_loop(handler)) {
ret = gbinder_driver_write_read(self, NULL, context.rbuf);
if (ret >= 0) {
gbinder_driver_handle_commands(self, reg, handler, &rb);
gbinder_driver_handle_commands(self, &context);
} else {
break;
}
}
}
gbinder_driver_context_cleanup(&context);
return ret;
}
@@ -975,8 +1232,10 @@ gbinder_driver_transact(
GBinderLocalRequest* req,
GBinderRemoteReply* reply)
{
GBinderDriverReadData read;
GBinderDriverContext context;
GBinderIoBuf write;
GBinderIoReadBuf rb;
GBinderDriverReadBuf* rbuf = &read.buf;
const GBinderIo* io = self->io;
const guint flags = reply ? 0 : GBINDER_TX_FLAG_ONEWAY;
GBinderOutputData* data = gbinder_local_request_data(req);
@@ -988,7 +1247,8 @@ gbinder_driver_transact(
guint len = sizeof(*cmd);
int txstatus = (-EAGAIN);
gbinder_driver_read_init(&rb);
gbinder_driver_read_init(&read);
gbinder_driver_context_init(&context, &read.buf, reg, handler);
/* Build BC_TRANSACTION */
if (extra_buffers) {
@@ -1022,11 +1282,11 @@ gbinder_driver_transact(
* negative is a driver error (except for -EAGAIN meaning that there's
* no status yet) */
while (txstatus == (-EAGAIN)) {
int err = gbinder_driver_write_read(self, &write, &rb.buf);
int err = gbinder_driver_write_read(self, &write, rbuf);
if (err < 0) {
txstatus = err;
} else {
txstatus = gbinder_driver_txstatus(self, reg, handler, &rb, reply);
txstatus = gbinder_driver_txstatus(self, &context, reply);
}
}
@@ -1035,54 +1295,41 @@ gbinder_driver_transact(
GASSERT(write.consumed == write.size || txstatus > 0);
/* Loop until we have handled all the incoming commands */
gbinder_driver_handle_commands(self, reg, handler, &rb);
while (rb.buf.consumed) {
int err = gbinder_driver_write_read(self, NULL, &rb.buf);
gbinder_driver_handle_commands(self, &context);
while (rbuf->io.consumed) {
int err = gbinder_driver_write_read(self, NULL, rbuf);
if (err < 0) {
txstatus = err;
break;
} else {
gbinder_driver_handle_commands(self, reg, handler, &rb);
gbinder_driver_handle_commands(self, &context);
}
}
}
gbinder_driver_context_cleanup(&context);
g_free(offsets_buf);
return txstatus;
}
int
gbinder_driver_ping(
GBinderDriver* self,
GBinderObjectRegistry* reg,
guint32 handle)
{
const GBinderRpcProtocol* protocol = self->protocol;
GBinderLocalRequest* req = gbinder_local_request_new(self->io, NULL);
GBinderRemoteReply* reply = gbinder_remote_reply_new(reg);
GBinderWriter writer;
int ret;
gbinder_local_request_init_writer(req, &writer);
protocol->write_ping(&writer);
ret = gbinder_driver_transact(self, reg, NULL, handle, protocol->ping_tx,
req, reply);
gbinder_local_request_unref(req);
gbinder_remote_reply_unref(reply);
return ret;
}
GBinderLocalRequest*
gbinder_driver_local_request_new(
GBinderDriver* self,
const char* iface)
{
GBinderLocalRequest* req = gbinder_local_request_new(self->io, NULL);
return gbinder_local_request_new_iface(self->io, self->protocol, iface);
}
GBinderLocalRequest*
gbinder_driver_local_request_new_ping(
GBinderDriver* self)
{
GBinderWriter writer;
GBinderLocalRequest* req = gbinder_local_request_new(self->io,
self->protocol, NULL);
gbinder_local_request_init_writer(req, &writer);
self->protocol->write_rpc_header(&writer, iface);
self->protocol->write_ping(&writer);
return req;
}

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:
*
@@ -53,6 +53,11 @@ gbinder_driver_unref(
GBinderDriver* driver)
GBINDER_INTERNAL;
void
gbinder_driver_close(
GBinderDriver* driver)
GBINDER_INTERNAL;
int
gbinder_driver_fd(
GBinderDriver* driver)
@@ -74,6 +79,23 @@ gbinder_driver_io(
GBinderDriver* driver)
GBINDER_INTERNAL;
const GBinderRpcProtocol*
gbinder_driver_protocol(
GBinderDriver* driver)
GBINDER_INTERNAL;
gboolean
gbinder_driver_acquire_done(
GBinderDriver* driver,
GBinderLocalObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_dead_binder_done(
GBinderDriver* driver,
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_request_death_notification(
GBinderDriver* driver,
@@ -112,7 +134,7 @@ gbinder_driver_release(
void
gbinder_driver_close_fds(
GBinderDriver* self,
GBinderDriver* driver,
void** objects,
const void* end)
GBINDER_INTERNAL;
@@ -151,17 +173,15 @@ gbinder_driver_transact(
GBinderRemoteReply* reply)
GBINDER_INTERNAL;
int
gbinder_driver_ping(
GBinderLocalRequest*
gbinder_driver_local_request_new(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
guint32 handle)
const char* iface)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_driver_local_request_new(
GBinderDriver* self,
const char* iface)
gbinder_driver_local_request_new_ping(
GBinderDriver* self)
GBINDER_INTERNAL;
#endif /* GBINDER_DRIVER_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2020-2021 Jolla Ltd.
* Copyright (C) 2020-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -34,6 +34,13 @@
#include <gutil_macros.h>
typedef struct gbinder_idle_callback_data {
GBinderEventLoopCallback* cb;
GBinderEventLoopCallbackFunc func;
GDestroyNotify destroy;
gpointer data;
} GBinderIdleCallbackData;
#define GBINDER_DEFAULT_EVENTLOOP (&gbinder_eventloop_glib)
static const GBinderEventLoopIntegration gbinder_eventloop_glib;
@@ -220,6 +227,36 @@ static const GBinderEventLoopIntegration gbinder_eventloop_glib = {
gbinder_eventloop_glib_cleanup
};
/*==========================================================================*
* Implementation
*==========================================================================*/
static
void
gbinder_idle_callback_invoke_proc(
void* user_data)
{
GBinderIdleCallbackData* idle = user_data;
if (idle->func) {
idle->func(idle->data);
}
gbinder_idle_callback_unref(idle->cb);
}
static
void
gbinder_idle_callback_invoke_done(
void* user_data)
{
GBinderIdleCallbackData* idle = user_data;
if (idle->destroy) {
idle->destroy(idle->data);
}
gutil_slice_free(idle);
}
/*==========================================================================*
* Internal interface
*==========================================================================*/
@@ -325,6 +362,27 @@ gbinder_idle_callback_destroy(
}
}
/* Non-cancellable callback */
void
gbinder_idle_callback_invoke_later(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
{
GBinderIdleCallbackData* idle = g_slice_new(GBinderIdleCallbackData);
idle->func = func;
idle->data = data;
idle->destroy = destroy;
idle->cb = gbinder_idle_callback_new(gbinder_idle_callback_invoke_proc,
idle, gbinder_idle_callback_invoke_done);
gbinder_idle_callback_schedule(idle->cb);
}
/*==========================================================================*
* Public interface
*==========================================================================*/
void
gbinder_eventloop_set(
const GBinderEventLoopIntegration* loop)

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2020-2021 Jolla Ltd.
* Copyright (C) 2020-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -41,12 +41,14 @@ gbinder_timeout_add(
guint millis,
GSourceFunc func,
gpointer data)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
GBinderEventLoopTimeout*
gbinder_idle_add(
GSourceFunc func,
gpointer data)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
void
@@ -59,6 +61,7 @@ gbinder_idle_callback_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
GBinderEventLoopCallback*
@@ -66,6 +69,7 @@ gbinder_idle_callback_schedule_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
GBinderEventLoopCallback*
@@ -93,6 +97,13 @@ gbinder_idle_callback_destroy(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_invoke_later(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
GBINDER_INTERNAL;
#endif /* GBINDER_EVENTLOOP_PRIVATE_H */
/*

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-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:
*
@@ -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"
@@ -90,19 +91,51 @@ GBINDER_IO_FN(write_read)(
return ret;
}
/* Returns size of the object */
static
gsize
GBINDER_IO_FN(object_size)(
const void* obj,
const GBinderRpcProtocol* protocol)
{
if (obj) {
const struct binder_object_header* hdr = obj;
switch (hdr->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER:
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE:
return sizeof(struct flat_binder_object) +
protocol->flat_binder_object_extra;
case BINDER_TYPE_FD:
return sizeof(struct binder_fd_object);
case BINDER_TYPE_FDA:
return sizeof(struct binder_fd_array_object);
case BINDER_TYPE_PTR:
return sizeof(struct binder_buffer_object);
}
}
return 0;
}
/* Returns size of the object's extra data */
static
gsize
GBINDER_IO_FN(object_data_size)(
const void* obj)
{
const struct binder_buffer_object* buf = obj;
if (obj) {
const struct binder_object_header* hdr = obj;
if (buf && buf->hdr.type == BINDER_TYPE_PTR) {
return buf->length;
} else {
return 0;
switch (hdr->type) {
case BINDER_TYPE_PTR:
return ((struct binder_buffer_object*)obj)->length;
case BINDER_TYPE_FDA:
return ((struct binder_fd_array_object*)obj)->num_fds * 4;
}
}
return 0;
}
/* Writes pointer to the buffer */
@@ -118,24 +151,41 @@ GBINDER_IO_FN(encode_pointer)(
return sizeof(*dest);
}
/* Encodes flat_buffer_object */
/* Writes cookie to the buffer */
static
guint
GBINDER_IO_FN(encode_cookie)(
void* out,
guint64 cookie)
{
binder_uintptr_t* dest = out;
*dest = (uintptr_t)cookie;
return sizeof(*dest);
}
/* Encodes flat_binder_object */
static
guint
GBINDER_IO_FN(encode_local_object)(
void* out,
GBinderLocalObject* obj)
GBinderLocalObject* obj,
const GBinderRpcProtocol* protocol)
{
struct flat_binder_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_BINDER;
if (obj) {
dest->hdr.type = BINDER_TYPE_BINDER;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
} else {
dest->hdr.type = BINDER_TYPE_WEAK_BINDER;
}
return sizeof(*dest);
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
@@ -163,12 +213,29 @@ GBINDER_IO_FN(encode_fd_object)(
void* out,
int fd)
{
struct flat_binder_object* dest = out;
struct binder_fd_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_FD;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->handle = fd;
dest->pad_flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->fd = fd;
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);
}
@@ -197,7 +264,7 @@ GBINDER_IO_FN(encode_buffer_object)(
static
guint
GBINDER_IO_FN(encode_death_notification)(
GBINDER_IO_FN(encode_handle_cookie)(
void* out,
GBinderRemoteObject* obj)
{
@@ -209,7 +276,21 @@ GBINDER_IO_FN(encode_death_notification)(
return sizeof(*dest);
}
/* Encodes BC_TRANSACTION data */
static
guint
GBINDER_IO_FN(encode_ptr_cookie)(
void* out,
GBinderLocalObject* obj)
{
struct binder_ptr_cookie* dest = out;
/* We never send these cookies and don't expect them back */
dest->ptr = (uintptr_t)obj;
dest->cookie = 0;
return sizeof(*dest);
}
/* Fills binder_transaction_data for BC_TRANSACTION/REPLY */
static
void
GBINDER_IO_FN(fill_transaction_data)(
@@ -217,7 +298,7 @@ GBINDER_IO_FN(fill_transaction_data)(
guint32 handle,
guint32 code,
const GByteArray* payload,
guint flags,
guint tx_flags,
GUtilIntArray* offsets,
void** offsets_buf)
{
@@ -226,9 +307,7 @@ GBINDER_IO_FN(fill_transaction_data)(
tr->code = code;
tr->data_size = payload->len;
tr->data.ptr.buffer = (uintptr_t)payload->data;
if (flags & GBINDER_TX_FLAG_ONEWAY) {
tr->flags |= TF_ONE_WAY;
}
tr->flags = tx_flags;
if (offsets && offsets->count) {
guint i;
binder_size_t* tx_offsets = g_new(binder_size_t, offsets->count);
@@ -244,6 +323,7 @@ GBINDER_IO_FN(fill_transaction_data)(
}
}
/* Encodes BC_TRANSACTION data */
static
guint
GBINDER_IO_FN(encode_transaction)(
@@ -257,7 +337,8 @@ GBINDER_IO_FN(encode_transaction)(
{
struct binder_transaction_data* tr = out;
GBINDER_IO_FN(fill_transaction_data)(tr, handle, code, payload, flags,
GBINDER_IO_FN(fill_transaction_data)(tr, handle, code, payload,
(flags & GBINDER_TX_FLAG_ONEWAY) ? TF_ONE_WAY : TF_ACCEPT_FDS,
offsets, offsets_buf);
return sizeof(*tr);
}
@@ -278,13 +359,53 @@ GBINDER_IO_FN(encode_transaction_sg)(
struct binder_transaction_data_sg* sg = out;
GBINDER_IO_FN(fill_transaction_data)(&sg->transaction_data, handle, code,
payload, flags, offsets, offsets_buf);
payload, (flags & GBINDER_TX_FLAG_ONEWAY) ? TF_ONE_WAY : TF_ACCEPT_FDS,
offsets, offsets_buf);
/* The driver seems to require buffers to be 8-byte aligned */
sg->buffers_size = G_ALIGN8(buffers_size);
return sizeof(*sg);
}
/* Encode BC_REPLY */
/* Encodes BC_REPLY data */
static
guint
GBINDER_IO_FN(encode_reply)(
void* out,
guint32 handle,
guint32 code,
const GByteArray* payload,
GUtilIntArray* offsets,
void** offsets_buf)
{
struct binder_transaction_data* tr = out;
GBINDER_IO_FN(fill_transaction_data)(tr, handle, code, payload, 0,
offsets, offsets_buf);
return sizeof(*tr);
}
/* Encodes BC_REPLY_SG data */
static
guint
GBINDER_IO_FN(encode_reply_sg)(
void* out,
guint32 handle,
guint32 code,
const GByteArray* payload,
GUtilIntArray* offsets,
void** offsets_buf,
gsize buffers_size)
{
struct binder_transaction_data_sg* sg = out;
GBINDER_IO_FN(fill_transaction_data)(&sg->transaction_data, handle, code,
payload, 0, offsets, offsets_buf);
/* The driver seems to require buffers to be 8-byte aligned */
sg->buffers_size = G_ALIGN8(buffers_size);
return sizeof(*sg);
}
/* Encode BC_REPLY with just status */
static
guint
GBINDER_IO_FN(encode_status_reply)(
@@ -372,7 +493,7 @@ GBINDER_IO_FN(decode_cookie)(
/* Decode struct binder_ptr_cookie */
static
void*
GBINDER_IO_FN(decode_binder_ptr_cookie)(
GBINDER_IO_FN(decode_ptr_cookie)(
const void* data)
{
const struct binder_ptr_cookie* ptr = data;
@@ -382,13 +503,33 @@ GBINDER_IO_FN(decode_binder_ptr_cookie)(
return (void*)(uintptr_t)ptr->ptr;
}
static
guint
GBINDER_IO_FN(decode_binder_handle)(
const void* data,
guint32* handle,
const GBinderRpcProtocol* protocol)
{
const struct flat_binder_object* obj = data;
/* Caller guarantees that data points to an object */
if (obj->hdr.type == BINDER_TYPE_HANDLE) {
if (handle) {
*handle = obj->handle;
}
return sizeof(*obj) + protocol->flat_binder_object_extra;
}
return 0;
}
static
guint
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;
@@ -396,9 +537,22 @@ GBINDER_IO_FN(decode_binder_object)(
switch (obj->hdr.type) {
case BINDER_TYPE_HANDLE:
if (out) {
*out = gbinder_object_registry_get_remote(reg, obj->handle);
*out = gbinder_object_registry_get_remote(reg, obj->handle,
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE);
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) + protocol->flat_binder_object_extra;
}
/* fallthrough */
default:
GERR("Unsupported binder object type 0x%08x", obj->hdr.type);
break;
@@ -503,23 +657,30 @@ const GBinderIo GBINDER_IO_PREFIX = {
.failed_reply = BR_FAILED_REPLY
},
.object_size = GBINDER_IO_FN(object_size),
.object_data_size = GBINDER_IO_FN(object_data_size),
/* Encoders */
.encode_pointer = GBINDER_IO_FN(encode_pointer),
.encode_cookie = GBINDER_IO_FN(encode_cookie),
.encode_local_object = GBINDER_IO_FN(encode_local_object),
.encode_remote_object = GBINDER_IO_FN(encode_remote_object),
.encode_fd_object = GBINDER_IO_FN(encode_fd_object),
.encode_fda_object = GBINDER_IO_FN(encode_fda_object),
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
.encode_handle_cookie = GBINDER_IO_FN(encode_handle_cookie),
.encode_ptr_cookie = GBINDER_IO_FN(encode_ptr_cookie),
.encode_transaction = GBINDER_IO_FN(encode_transaction),
.encode_transaction_sg = GBINDER_IO_FN(encode_transaction_sg),
.encode_reply = GBINDER_IO_FN(encode_reply),
.encode_reply_sg = GBINDER_IO_FN(encode_reply_sg),
.encode_status_reply = GBINDER_IO_FN(encode_status_reply),
/* Decoders */
.decode_transaction_data = GBINDER_IO_FN(decode_transaction_data),
.decode_cookie = GBINDER_IO_FN(decode_cookie),
.decode_binder_ptr_cookie = GBINDER_IO_FN(decode_binder_ptr_cookie),
.decode_ptr_cookie = GBINDER_IO_FN(decode_ptr_cookie),
.decode_binder_handle = GBINDER_IO_FN(decode_binder_handle),
.decode_binder_object = GBINDER_IO_FN(decode_binder_object),
.decode_buffer_object = GBINDER_IO_FN(decode_buffer_object),
.decode_fd_object = GBINDER_IO_FN(decode_fd_object),
@@ -532,10 +693,14 @@ 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) <=
GBINDER_MAX_DEATH_NOTIFICATION_SIZE);
GBINDER_MAX_HANDLE_COOKIE_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_transaction_data) <=
GBINDER_MAX_BC_TRANSACTION_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_transaction_data_sg) <=

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:
*
@@ -125,7 +125,8 @@ struct gbinder_io {
guint failed_reply;
} br;
/* Size of the object's extra data */
/* Size of the object and its extra data */
gsize (*object_size)(const void* obj, const GBinderRpcProtocol* protocol);
gsize (*object_data_size)(const void* obj);
/* Writes pointer to the buffer. The destination buffer must have
@@ -134,45 +135,66 @@ struct gbinder_io {
#define GBINDER_MAX_POINTER_SIZE (8)
guint (*encode_pointer)(void* out, const void* pointer);
/* Writes cookie to the buffer. The destination buffer must have
* at least GBINDER_IO_MAX_COOKIE_SIZE bytes available. The
* actual size is returned. */
#define GBINDER_MAX_COOKIE_SIZE GBINDER_MAX_POINTER_SIZE
guint (*encode_cookie)(void* out, guint64 cookie);
/* Encode flat_buffer_object */
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
#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)
guint (*encode_buffer_object)(void* out, const void* data, gsize size,
const GBinderParent* parent);
/* Encode death notification */
#define GBINDER_MAX_DEATH_NOTIFICATION_SIZE (12)
guint (*encode_death_notification)(void* out, GBinderRemoteObject* obj);
/* Encode binder_handle_cookie */
#define GBINDER_MAX_HANDLE_COOKIE_SIZE (12)
guint (*encode_handle_cookie)(void* out, GBinderRemoteObject* obj);
/* Encode BC_TRANSACTION/REPLY data */
/* Encode binder_ptr_cookie */
#define GBINDER_MAX_PTR_COOKIE_SIZE (16)
guint (*encode_ptr_cookie)(void* out, GBinderLocalObject* obj);
/* Encode BC_TRANSACTION/BC_TRANSACTION_SG data */
#define GBINDER_MAX_BC_TRANSACTION_SIZE (64)
guint (*encode_transaction)(void* out, guint32 handle, guint32 code,
const GByteArray* data, guint flags /* See below */,
GUtilIntArray* offsets, void** offsets_buf);
/* Encode BC_TRANSACTION_SG/REPLY_SG data */
#define GBINDER_MAX_BC_TRANSACTION_SG_SIZE (72)
guint (*encode_transaction_sg)(void* out, guint32 handle, guint32 code,
const GByteArray* data, guint flags /* GBINDER_TX_FLAG_xxx */,
GUtilIntArray* offsets, void** offsets_buf,
gsize buffers_size);
/* Encode BC_REPLY/REPLY_SG data */
#define GBINDER_MAX_BC_REPLY_SIZE GBINDER_MAX_BC_TRANSACTION_SIZE
guint (*encode_reply)(void* out, guint32 handle, guint32 code,
const GByteArray* data, GUtilIntArray* offsets, void** offsets_buf);
#define GBINDER_MAX_BC_REPLY_SG_SIZE GBINDER_MAX_BC_TRANSACTION_SG_SIZE
guint (*encode_reply_sg)(void* out, guint32 handle, guint32 code,
const GByteArray* data, GUtilIntArray* offsets, void** offsets_buf,
gsize buffers_size);
/* Encode BC_REPLY */
guint (*encode_status_reply)(void* out, gint32* status);
/* Decoders */
void (*decode_transaction_data)(const void* data, GBinderIoTxData* tx);
#define GBINDER_MAX_PTR_COOKIE_SIZE (16)
void* (*decode_binder_ptr_cookie)(const void* data);
void* (*decode_ptr_cookie)(const void* data);
guint (*decode_cookie)(const void* data, guint64* cookie);
guint (*decode_binder_handle)(const void* obj, guint32* handle,
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-2020 Jolla Ltd.
* Copyright (C) 2018-2020 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:
*
@@ -30,7 +30,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#define _GNU_SOURCE /* pthread_*_np */
#include "gbinder_ipc.h"
#include "gbinder_driver.h"
@@ -54,14 +54,18 @@
#include <pthread.h>
#include <poll.h>
#include <errno.h>
#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;
GMutex remote_objects_mutex;
@@ -75,11 +79,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
@@ -91,6 +96,7 @@ static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
#define GBINDER_IPC_MAX_TX_THREADS (15)
#define GBINDER_IPC_MAX_PRIMARY_LOOPERS (5)
#define GBINDER_IPC_LOOPER_START_TIMEOUT_SEC (2)
#define GBINDER_IPC_LOOPER_JOIN_TIMEOUT_MS (500)
/*
* When looper receives the transaction:
@@ -154,11 +160,12 @@ struct gbinder_ipc_looper {
GBinderHandler handler;
GBinderDriver* driver;
GBinderIpc* ipc; /* Not a reference! */
GThread* thread;
pthread_t thread;
GMutex mutex;
GCond start_cond;
gint exit;
gint started;
gint joined;
int pipefd[2];
int txfd[2];
};
@@ -202,14 +209,28 @@ typedef struct gbinder_ipc_tx_custom {
GDestroyNotify fn_custom_destroy;
} GBinderIpcTxCustom;
GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self)
{ return gbinder_driver_dev(self->driver); }
static
GBinderIpcLooper*
gbinder_ipc_looper_new(
GBinderIpc* ipc);
static
GBinderRemoteReply*
gbinder_ipc_transact_sync_reply_worker(
GBinderIpc* self,
guint32 handle,
guint32 code,
GBinderLocalRequest* req,
int* status);
static
int
gbinder_ipc_transact_sync_oneway_worker(
GBinderIpc* self,
guint32 handle,
guint32 code,
GBinderLocalRequest* req);
/*==========================================================================*
* Utilities
*==========================================================================*/
@@ -244,6 +265,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
*==========================================================================*/
@@ -407,8 +437,8 @@ void
gbinder_ipc_looper_free(
GBinderIpcLooper* looper)
{
if (looper->thread) {
g_thread_unref(looper->thread);
if (!looper->joined && looper->thread != pthread_self()) {
pthread_join(looper->thread, NULL);
}
close(looper->pipefd[0]);
close(looper->pipefd[1]);
@@ -664,7 +694,7 @@ gbinder_ipc_looper_transact(
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (gbinder_ipc_looper_remove_primary(looper)) {
GDEBUG("Primary looper %s is blocked", looper->name);
GVERBOSE("Primary looper %s is blocked", looper->name);
looper->next = priv->blocked_loopers;
priv->blocked_loopers = looper;
was_blocked = TRUE;
@@ -691,7 +721,7 @@ gbinder_ipc_looper_transact(
/* Block until asynchronous transaction gets completed. */
done = 0;
if (gbinder_ipc_wait(looper->pipefd[0], tx->pipefd[0], &done)) {
GDEBUG("Looper %s is released", looper->name);
GVERBOSE("Looper %s is released", looper->name);
GASSERT(done == TX_DONE);
}
}
@@ -744,12 +774,13 @@ gbinder_ipc_looper_thread(
GBinderIpcLooper* looper = data;
GBinderDriver* driver = looper->driver;
g_mutex_lock(&looper->mutex);
pthread_setname_np(looper->thread, looper->name);
if (gbinder_driver_enter_looper(driver)) {
struct pollfd pipefd;
int res;
GDEBUG("Looper %s running", looper->name);
g_mutex_lock(&looper->mutex);
g_atomic_int_set(&looper->started, TRUE);
g_cond_broadcast(&looper->start_cond);
g_mutex_unlock(&looper->mutex);
@@ -814,7 +845,6 @@ gbinder_ipc_looper_thread(
GDEBUG("Looper %s is abandoned", looper->name);
}
} else {
g_mutex_lock(&looper->mutex);
g_atomic_int_set(&looper->started, TRUE);
g_cond_broadcast(&looper->start_cond);
g_mutex_unlock(&looper->mutex);
@@ -837,7 +867,6 @@ gbinder_ipc_looper_new(
.can_loop = gbinder_ipc_looper_can_loop,
.transact = gbinder_ipc_looper_transact
};
GError* error = NULL;
GBinderIpcLooper* looper = g_slice_new0(GBinderIpcLooper);
static gint gbinder_ipc_next_looper_id = 1;
guint id = (guint)g_atomic_int_add(&gbinder_ipc_next_looper_id, 1);
@@ -847,21 +876,22 @@ gbinder_ipc_looper_new(
g_atomic_int_set(&looper->refcount, 1);
g_cond_init(&looper->start_cond);
g_mutex_init(&looper->mutex);
g_mutex_lock(&looper->mutex);
looper->name = g_strdup_printf("%s#%u", gbinder_ipc_name(ipc), id);
looper->handler.f = &handler_functions;
looper->ipc = ipc;
looper->driver = gbinder_driver_ref(ipc->driver);
looper->thread = g_thread_try_new(looper->name,
gbinder_ipc_looper_thread, looper, &error);
if (looper->thread) {
if (!pthread_create(&looper->thread, NULL, gbinder_ipc_looper_thread,
looper)) {
/* gbinder_ipc_looper_thread() will release this reference: */
gbinder_ipc_looper_ref(looper);
g_mutex_unlock(&looper->mutex);
GDEBUG("Starting looper %s", looper->name);
return looper;
} else {
GERR("Failed to create looper thread: %s", GERRMSG(error));
g_error_free(error);
GERR("Failed to create looper thread %s", looper->name);
}
g_mutex_unlock(&looper->mutex);
gbinder_ipc_looper_unref(looper);
} else {
GERR("Failed to create looper pipe: %s", strerror(errno));
@@ -875,28 +905,25 @@ gbinder_ipc_looper_check(
{
if (G_LIKELY(self)) {
GBinderIpcPriv* priv = self->priv;
GBinderIpcLooper* new_looper = NULL;
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (!priv->primary_loopers) {
GBinderIpcLooper* looper;
priv->primary_loopers = gbinder_ipc_looper_new(self);
new_looper = priv->primary_loopers;
if (new_looper) {
gbinder_ipc_looper_ref(new_looper);
}
}
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (!priv->primary_loopers) {
priv->primary_loopers = gbinder_ipc_looper_new(self);
}
looper = priv->primary_loopers;
if (looper) {
gbinder_ipc_looper_ref(looper);
}
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
/* We are not ready to accept incoming transactions until
* looper has started. We may need to wait a bit. */
if (looper) {
gbinder_ipc_looper_start(looper);
gbinder_ipc_looper_unref(looper);
}
/* We are not ready to accept incoming transactions until
* looper has started. We may need to wait a bit. */
if (new_looper) {
gbinder_ipc_looper_start(new_looper);
gbinder_ipc_looper_unref(new_looper);
}
}
}
@@ -910,11 +937,11 @@ gbinder_ipc_looper_stop(
if (looper->thread) {
GDEBUG("Stopping looper %s", looper->name);
g_atomic_int_set(&looper->exit, TRUE);
if (looper->thread != g_thread_self()) {
if (looper->thread != pthread_self()) {
guint8 done = TX_DONE;
if (write(looper->pipefd[1], &done, sizeof(done)) <= 0) {
looper->thread = NULL;
GWARN("Failed to stop looper %s", looper->name);
}
}
}
@@ -944,9 +971,36 @@ gbinder_ipc_looper_join(
GBinderIpcLooper* looper)
{
/* Caller checks looper for NULL */
if (looper->thread && looper->thread != g_thread_self()) {
g_thread_join(looper->thread);
looper->thread = NULL;
if (looper->thread && looper->thread != pthread_self()) {
struct timespec ts;
int err = clock_gettime(CLOCK_REALTIME, &ts);
if (!err) {
const long ms = 1000000;
const long sec = 1000 * ms;
const long ns = ts.tv_nsec + GBINDER_IPC_LOOPER_JOIN_TIMEOUT_MS*ms;
ts.tv_sec += ns / sec;
ts.tv_nsec = ns % sec;
err = pthread_timedjoin_np(looper->thread, NULL, &ts);
}
if (err) {
/* Assume that looper is stuck in read */
GBinderIpc* ipc = looper->ipc;
GBinderIpcPriv* priv = ipc->priv;
GDEBUG("Looper %s is stuck", looper->name);
/* Lock */
g_mutex_lock(&priv->looper_mutex);
gbinder_driver_close(ipc->driver);
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
pthread_join(looper->thread, NULL);
}
looper->joined = TRUE;
}
looper->ipc = NULL;
}
@@ -1068,21 +1122,60 @@ gbinder_ipc_tx_handler_transact(
static
void
gbinder_ipc_invalidate_remote_handle_locked(
GBinderIpcPriv* priv,
guint32 handle)
gbinder_ipc_invalidate_local_object_locked(
GBinderIpc* self,
GBinderLocalObject* obj)
{
/* Caller holds priv->remote_objects_mutex */
if (priv->remote_objects) {
GVERBOSE_("handle %u", handle);
g_hash_table_remove(priv->remote_objects, GINT_TO_POINTER(handle));
if (g_hash_table_size(priv->remote_objects) == 0) {
g_hash_table_unref(priv->remote_objects);
priv->remote_objects = NULL;
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(
GBinderIpc* self,
guint32 handle)
{
GBinderIpcPriv* priv = self->priv;
/* Caller holds priv->remote_objects_mutex */
if (priv->remote_objects) {
const gpointer key = GINT_TO_POINTER(handle);
#if GUTIL_LOG_VERBOSE
const gpointer obj = g_hash_table_lookup(priv->remote_objects, key);
#endif
if (g_hash_table_remove(priv->remote_objects, key)) {
GVERBOSE_("handle %u %p %s", handle, obj, gbinder_ipc_name(self));
if (g_hash_table_size(priv->remote_objects) == 0) {
g_hash_table_unref(priv->remote_objects);
priv->remote_objects = NULL;
}
}
}
}
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,
@@ -1092,7 +1185,7 @@ gbinder_ipc_invalidate_remote_handle(
/* Lock */
g_mutex_lock(&priv->remote_objects_mutex);
gbinder_ipc_invalidate_remote_handle_locked(priv, handle);
gbinder_ipc_invalidate_remote_handle_locked(self, handle);
g_mutex_unlock(&priv->remote_objects_mutex);
/* Unlock */
}
@@ -1126,12 +1219,8 @@ gbinder_ipc_local_object_disposed(
/* Lock */
g_mutex_lock(&priv->local_objects_mutex);
if (obj->object.ref_count == 1 && priv->local_objects) {
g_hash_table_remove(priv->local_objects, obj);
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 */
@@ -1144,10 +1233,33 @@ 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) {
gbinder_ipc_invalidate_remote_handle_locked(priv, obj->handle);
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);
/* Unlock */
@@ -1165,11 +1277,13 @@ gbinder_ipc_register_local_object(
if (!priv->local_objects) {
priv->local_objects = g_hash_table_new(g_direct_hash, g_direct_equal);
}
g_hash_table_insert(priv->local_objects, obj, obj);
if (!g_hash_table_contains(priv->local_objects, obj)) {
g_hash_table_insert(priv->local_objects, obj, obj);
GVERBOSE_("%p %s", obj, gbinder_ipc_name(self));
}
g_mutex_unlock(&priv->local_objects_mutex);
/* Unlock */
GVERBOSE_("%p", obj);
gbinder_ipc_looper_check(self);
}
@@ -1189,10 +1303,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 */
@@ -1206,6 +1320,7 @@ GBinderRemoteObject*
gbinder_ipc_priv_get_remote_object(
GBinderIpcPriv* priv,
guint32 handle,
REMOTE_REGISTRY_CREATE create,
gboolean maybe_dead)
{
GBinderRemoteObject* obj = NULL;
@@ -1218,17 +1333,25 @@ gbinder_ipc_priv_get_remote_object(
}
if (obj) {
gbinder_remote_object_ref(obj);
} else {
} else if (create != REMOTE_REGISTRY_DONT_CREATE) {
GBinderIpc* self = priv->self;
/*
* If maybe_dead is TRUE, the caller is supposed to try reanimating
* the object on the main thread not holding any global locks.
*/
obj = gbinder_remote_object_new(priv->self, handle, maybe_dead);
obj = gbinder_remote_object_new(self, handle, maybe_dead ?
REMOTE_OBJECT_CREATE_DEAD : (create == REMOTE_REGISTRY_CAN_CREATE) ?
REMOTE_OBJECT_CREATE_ALIVE :
REMOTE_OBJECT_CREATE_ACQUIRED);
if (!priv->remote_objects) {
priv->remote_objects = g_hash_table_new
(g_direct_hash, g_direct_equal);
}
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 */
@@ -1236,14 +1359,47 @@ gbinder_ipc_priv_get_remote_object(
return obj;
}
GBinderRemoteObject*
gbinder_ipc_get_remote_object(
GBinderLocalObject*
gbinder_ipc_find_local_object(
GBinderIpc* self,
guint32 handle,
gboolean maybe_dead)
GBinderIpcLocalObjectCheckFunc func,
void* user_data)
{
GBinderLocalObject* found = NULL;
if (self) {
GBinderIpcPriv* priv = self->priv;
/* Lock */
g_mutex_lock(&priv->local_objects_mutex);
if (priv->local_objects) {
GHashTableIter it;
gpointer value;
g_hash_table_iter_init(&it, priv->local_objects);
while (g_hash_table_iter_next(&it, NULL, &value)) {
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(value);
if (func(obj, user_data)) {
found = gbinder_local_object_ref(obj);
break;
}
}
}
g_mutex_unlock(&priv->local_objects_mutex);
/* Unlock */
}
return found;
}
GBinderRemoteObject*
gbinder_ipc_get_service_manager(
GBinderIpc* self)
{
/* GBinderServiceManager makes sure that GBinderIpc pointer is not NULL */
return gbinder_ipc_priv_get_remote_object(self->priv, handle, maybe_dead);
return gbinder_ipc_priv_get_remote_object(self->priv,
GBINDER_SERVICEMANAGER_HANDLE, REMOTE_REGISTRY_CAN_CREATE, TRUE);
}
GBINDER_INLINE_FUNC
@@ -1292,10 +1448,11 @@ static
GBinderRemoteObject*
gbinder_ipc_object_registry_get_remote(
GBinderObjectRegistry* reg,
guint32 handle)
guint32 handle,
REMOTE_REGISTRY_CREATE create)
{
return gbinder_ipc_priv_get_remote_object
(gbinder_ipc_priv_from_object_registry(reg), handle, FALSE);
(gbinder_ipc_priv_from_object_registry(reg), handle, create, FALSE);
}
/*==========================================================================*
@@ -1433,30 +1590,15 @@ void
gbinder_ipc_tx_internal_exec(
GBinderIpcTxPriv* priv)
{
static const GBinderHandlerFunctions handler_fn = {
.can_loop = NULL,
.transact = gbinder_ipc_tx_handler_transact
};
GBinderIpcTxInternal* tx = gbinder_ipc_tx_internal_cast(priv);
GBinderIpcTx* pub = &priv->pub;
GBinderIpc* self = pub->ipc;
GBinderObjectRegistry* reg = &self->priv->object_registry;
GBinderHandler handler = { &handler_fn };
GBinderIpc* ipc = priv->pub.ipc;
/* Perform synchronous transaction */
if (tx->flags & GBINDER_TX_FLAG_ONEWAY) {
tx->status = gbinder_driver_transact(self->driver, reg, &handler,
tx->handle, tx->code, tx->req, NULL);
tx->status = gbinder_ipc_transact_sync_oneway_worker(ipc, tx->handle,
tx->code, tx->req);
} else {
tx->reply = gbinder_remote_reply_new(&self->priv->object_registry);
tx->status = gbinder_driver_transact(self->driver, reg, &handler,
tx->handle, tx->code, tx->req, tx->reply);
if (tx->status != GBINDER_STATUS_OK &&
gbinder_remote_reply_is_empty(tx->reply)) {
/* Drop useless reply */
gbinder_remote_reply_unref(tx->reply);
tx->reply = NULL;
}
tx->reply = gbinder_ipc_transact_sync_reply_worker(ipc, tx->handle,
tx->code, tx->req, &tx->status);
}
}
@@ -1580,78 +1722,77 @@ gbinder_ipc_tx_proc(
}
/*==========================================================================*
* Interface
* GBinderIpcSyncApi for worker threads
*==========================================================================*/
GBinderIpc*
gbinder_ipc_new(
const char* dev)
static
GBinderRemoteReply*
gbinder_ipc_transact_sync_reply_worker(
GBinderIpc* self,
guint32 handle,
guint32 code,
GBinderLocalRequest* req,
int* status)
{
GBinderIpc* self = NULL;
const GBinderRpcProtocol* protocol;
/* Must be invoked on worker thread */
if (G_LIKELY(self)) {
static const GBinderHandlerFunctions handler_fn = {
.can_loop = NULL,
.transact = gbinder_ipc_tx_handler_transact
};
GBinderHandler handler = { &handler_fn };
GBinderIpcPriv* priv = self->priv;
GBinderObjectRegistry* reg = &priv->object_registry;
GBinderRemoteReply* reply = gbinder_remote_reply_new(reg);
int ret = gbinder_driver_transact(self->driver, reg, &handler,
handle, code, req, reply);
if (!dev || !dev[0]) dev = GBINDER_DEFAULT_BINDER;
protocol = gbinder_rpc_protocol_for_device(dev); /* Never returns NULL */
/* Lock */
pthread_mutex_lock(&gbinder_ipc_mutex);
if (gbinder_ipc_table) {
self = g_hash_table_lookup(gbinder_ipc_table, dev);
}
if (self) {
gbinder_ipc_ref(self);
} else {
GBinderDriver* driver = gbinder_driver_new(dev, protocol);
if (driver) {
GBinderIpcPriv* priv;
self = g_object_new(GBINDER_TYPE_IPC, NULL);
priv = self->priv;
self->driver = driver;
self->dev = priv->key = g_strdup(dev);
self->priv->object_registry.io = gbinder_driver_io(driver);
/* gbinder_ipc_dispose will remove iself from the table */
if (!gbinder_ipc_table) {
gbinder_ipc_table = g_hash_table_new(g_str_hash, g_str_equal);
}
g_hash_table_replace(gbinder_ipc_table, priv->key, self);
if (status) *status = ret;
if (ret == GBINDER_STATUS_OK || !gbinder_remote_reply_is_empty(reply)) {
return reply;
} else {
gbinder_remote_reply_unref(reply);
}
}
pthread_mutex_unlock(&gbinder_ipc_mutex);
/* Unlock */
return self;
}
GBinderIpc*
gbinder_ipc_ref(
GBinderIpc* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_IPC(self));
return self;
} else {
return NULL;
if (status) *status = (-EINVAL);
}
return NULL;
}
void
gbinder_ipc_unref(
GBinderIpc* self)
static
int
gbinder_ipc_transact_sync_oneway_worker(
GBinderIpc* self,
guint32 handle,
guint32 code,
GBinderLocalRequest* req)
{
/* Must be invoked on worker thread */
if (G_LIKELY(self)) {
g_object_unref(GBINDER_IPC(self));
static const GBinderHandlerFunctions handler_fn = {
.can_loop = NULL,
.transact = gbinder_ipc_tx_handler_transact
};
GBinderHandler handler = { &handler_fn };
GBinderIpcPriv* priv = self->priv;
return gbinder_driver_transact(self->driver, &priv->object_registry,
&handler, handle, code, req, NULL);
} else {
return (-EINVAL);
}
}
GBinderObjectRegistry*
gbinder_ipc_object_registry(
GBinderIpc* self)
{
/* Only used by unit tests */
return G_LIKELY(self) ? &self->priv->object_registry : NULL;
}
const GBinderIpcSyncApi gbinder_ipc_sync_worker = {
.sync_reply = gbinder_ipc_transact_sync_reply_worker,
.sync_oneway = gbinder_ipc_transact_sync_oneway_worker
};
/*==========================================================================*
* GBinderIpcSyncApi for the main thread
*==========================================================================*/
static
GBinderRemoteReply*
gbinder_ipc_transact_sync_reply(
GBinderIpc* self,
@@ -1679,6 +1820,7 @@ gbinder_ipc_transact_sync_reply(
return NULL;
}
static
int
gbinder_ipc_transact_sync_oneway(
GBinderIpc* self,
@@ -1696,6 +1838,131 @@ gbinder_ipc_transact_sync_oneway(
}
}
const GBinderIpcSyncApi gbinder_ipc_sync_main = {
.sync_reply = gbinder_ipc_transact_sync_reply,
.sync_oneway = gbinder_ipc_transact_sync_oneway
};
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderIpc*
gbinder_ipc_new(
const char* dev,
const char* protocol_name)
{
GBinderIpc* self = NULL;
char* key;
const GBinderRpcProtocol* protocol = (protocol_name ?
gbinder_rpc_protocol_by_name(protocol_name) : NULL);
if (!dev || !dev[0]) dev = GBINDER_DEFAULT_BINDER;
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, key);
}
if (self) {
g_free(key);
gbinder_ipc_ref(self);
} else {
GBinderDriver* driver = gbinder_driver_new(dev, protocol);
if (driver) {
GBinderIpcPriv* priv;
self = g_object_new(THIS_TYPE, NULL);
priv = self->priv;
self->driver = driver;
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) {
gbinder_ipc_table = g_hash_table_new(g_str_hash, g_str_equal);
}
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 = self->dev +
(g_str_has_prefix(priv->dev, "/dev/") ? 5 : 0);
} else {
g_free(key);
}
}
pthread_mutex_unlock(&gbinder_ipc_mutex);
/* Unlock */
return self;
}
GBinderIpc*
gbinder_ipc_ref(
GBinderIpc* self)
{
if (G_LIKELY(self)) {
g_object_ref(THIS(self));
return self;
} else {
return NULL;
}
}
void
gbinder_ipc_unref(
GBinderIpc* self)
{
if (G_LIKELY(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)
{
return G_LIKELY(self) ? &self->priv->object_registry : NULL;
}
const GBinderIo*
gbinder_ipc_io(
GBinderIpc* self)
{
return G_LIKELY(self) ? gbinder_driver_io(self->driver) : NULL;
}
const GBinderRpcProtocol*
gbinder_ipc_protocol(
GBinderIpc* self)
{
return G_LIKELY(self) ? gbinder_driver_protocol(self->driver) : NULL;
}
int
gbinder_ipc_ping_sync(
GBinderIpc* ipc,
guint32 handle,
const GBinderIpcSyncApi* api)
{
GBinderDriver* driver = ipc->driver;
GBinderLocalRequest* req = gbinder_driver_local_request_new_ping(driver);
guint32 code = gbinder_driver_protocol(driver)->ping_tx;
int ret;
gbinder_remote_reply_unref(api->sync_reply(ipc, handle, code, req, &ret));
gbinder_local_request_unref(req);
return ret;
}
gulong
gbinder_ipc_transact(
GBinderIpc* self,
@@ -1786,7 +2053,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);
@@ -1837,12 +2104,16 @@ void
gbinder_ipc_dispose(
GObject* object)
{
GBinderIpc* self = GBINDER_IPC(object);
GBinderIpc* self = THIS(object);
GVERBOSE_("%s", self->dev);
/* Lock */
pthread_mutex_lock(&gbinder_ipc_mutex);
GASSERT(gbinder_ipc_table);
/*
* gbinder_ipc_dispose() can be invoked more than once (typically
* at shutdown) and gbinder_ipc_table here may actually happen to
* be NULL, hence the check.
*/
if (gbinder_ipc_table) {
GBinderIpcPriv* priv = self->priv;
@@ -1857,7 +2128,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
@@ -1865,7 +2136,7 @@ void
gbinder_ipc_finalize(
GObject* object)
{
GBinderIpc* self = GBINDER_IPC(object);
GBinderIpc* self = THIS(object);
GBinderIpcPriv* priv = self->priv;
GASSERT(!priv->local_objects);
@@ -1879,8 +2150,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
@@ -1916,9 +2188,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;
@@ -1929,8 +2200,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-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:
*
@@ -59,6 +59,12 @@ struct gbinder_ipc_tx {
void* user_data;
};
typedef
gboolean
(*GBinderIpcLocalObjectCheckFunc)(
GBinderLocalObject* obj,
void* user_data);
typedef
void
(*GBinderIpcReplyFunc)(
@@ -67,9 +73,35 @@ void
int status,
void* user_data);
typedef
GBinderRemoteReply*
(*GBinderIpcSyncReplyFunc)(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req,
int* status);
typedef
int
(*GBinderIpcSyncOnewayFunc)(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req);
struct gbinder_ipc_sync_api {
GBinderIpcSyncReplyFunc sync_reply;
GBinderIpcSyncOnewayFunc sync_oneway;
};
extern const GBinderIpcSyncApi gbinder_ipc_sync_main GBINDER_INTERNAL;
extern const GBinderIpcSyncApi gbinder_ipc_sync_worker GBINDER_INTERNAL;
GBinderIpc*
gbinder_ipc_new(
const char* dev)
const char* dev,
const char* protocol)
GBINDER_INTERNAL;
GBinderIpc*
@@ -82,9 +114,14 @@ gbinder_ipc_unref(
GBinderIpc* ipc)
GBINDER_INTERNAL;
const char*
gbinder_ipc_name(
GBinderIpc* ipc)
GBINDER_INTERNAL;
void
gbinder_ipc_looper_check(
GBinderIpc* ipc)
GBinderIpc* ipc)
GBINDER_INTERNAL;
GBinderObjectRegistry*
@@ -92,6 +129,24 @@ gbinder_ipc_object_registry(
GBinderIpc* ipc)
GBINDER_INTERNAL;
const GBinderIo*
gbinder_ipc_io(
GBinderIpc* ipc)
GBINDER_INTERNAL;
const GBinderRpcProtocol*
gbinder_ipc_protocol(
GBinderIpc* ipc)
GBINDER_INTERNAL;
GBinderLocalObject*
gbinder_ipc_find_local_object(
GBinderIpc* ipc,
GBinderIpcLocalObjectCheckFunc func,
void* user_data)
GBINDER_INTERNAL
G_GNUC_WARN_UNUSED_RESULT;
void
gbinder_ipc_register_local_object(
GBinderIpc* ipc,
@@ -99,11 +154,10 @@ gbinder_ipc_register_local_object(
GBINDER_INTERNAL;
GBinderRemoteObject*
gbinder_ipc_get_remote_object(
GBinderIpc* ipc,
guint32 handle,
gboolean maybe_dead)
GBINDER_INTERNAL;
gbinder_ipc_get_service_manager(
GBinderIpc* ipc)
GBINDER_INTERNAL
G_GNUC_WARN_UNUSED_RESULT;
void
gbinder_ipc_invalidate_remote_handle(
@@ -111,21 +165,11 @@ gbinder_ipc_invalidate_remote_handle(
guint32 handle)
GBINDER_INTERNAL;
GBinderRemoteReply*
gbinder_ipc_transact_sync_reply(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req,
int* status)
GBINDER_INTERNAL;
int
gbinder_ipc_transact_sync_oneway(
gbinder_ipc_ping_sync(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req)
const GBinderIpcSyncApi* api)
GBINDER_INTERNAL;
gulong
@@ -158,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-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -30,29 +30,35 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_buffer_p.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_remote_request.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_writer.h"
#include "gbinder_log.h"
#include <gutil_strv.h>
#include <gutil_macros.h>
#include <errno.h>
struct gbinder_local_object_priv {
GMainContext* context;
char** ifaces;
GBinderLocalTransactFunc txproc;
void* user_data;
};
typedef struct gbinder_local_object_acquire_data {
GBinderLocalObject* object;
GBinderBufferContentsList* bufs;
} GBinderLocalObjectAcquireData;
G_DEFINE_TYPE(GBinderLocalObject, gbinder_local_object, G_TYPE_OBJECT)
#define PARENT_CLASS gbinder_local_object_parent_class
#define GBINDER_LOCAL_OBJECT_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_LOCAL_OBJECT, \
GBinderLocalObjectClass)
@@ -81,6 +87,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(
@@ -131,8 +146,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);
@@ -147,9 +161,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]);
@@ -165,8 +178,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));
@@ -183,9 +195,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\"",
@@ -205,8 +216,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\"",
@@ -256,73 +266,115 @@ gbinder_local_object_default_handle_looper_transaction(
return handler(self, req, status);
}
static
void
gbinder_local_object_default_drop(
GBinderLocalObject* self)
{
GBinderLocalObjectPriv* priv = self->priv;
/* Clear the transaction callback */
priv->txproc = NULL;
priv->user_data = NULL;
}
static
void
gbinder_local_object_handle_later(
GBinderLocalObject* self,
GSourceFunc function)
GBinderEventLoopCallbackFunc function)
{
if (G_LIKELY(self)) {
GBinderLocalObjectPriv* priv = self->priv;
g_main_context_invoke_full(priv->context, G_PRIORITY_DEFAULT, function,
gbinder_idle_callback_invoke_later(function,
gbinder_local_object_ref(self), g_object_unref);
}
}
static
gboolean
gbinder_local_object_handle_increfs_proc(
gpointer local)
void
gbinder_local_object_increfs_proc(
gpointer user_data)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(user_data);
self->weak_refs++;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_WEAK_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_decrefs_proc(
gpointer local)
void
gbinder_local_object_decrefs_proc(
gpointer user_data)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(user_data);
GASSERT(self->weak_refs > 0);
self->weak_refs--;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_WEAK_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_acquire_proc(
gpointer local)
void
gbinder_local_object_default_acquire(
GBinderLocalObject* self)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
self->strong_refs++;
gbinder_local_object_ref(self);
GVERBOSE_("%p => %d", self, self->strong_refs);
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_release_proc(
gpointer local)
void
gbinder_local_object_acquire_proc(
gpointer user_data)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObjectAcquireData* data = user_data;
GBinderLocalObject* self = data->object;
GASSERT(self->strong_refs > 0);
self->strong_refs--;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0);
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->acquire(self);
}
static
void
gbinder_local_object_acquire_done(
gpointer user_data)
{
GBinderLocalObjectAcquireData* data = user_data;
GBinderLocalObject* self = data->object;
gbinder_driver_acquire_done(self->ipc->driver, self);
gbinder_local_object_unref(self);
return G_SOURCE_REMOVE;
gbinder_buffer_contents_list_free(data->bufs);
return gutil_slice_free(data);
}
static
void
gbinder_local_object_default_release(
GBinderLocalObject* self)
{
GASSERT(self->strong_refs > 0);
if (self->strong_refs > 0) {
self->strong_refs--;
GVERBOSE_("%p => %d", self, self->strong_refs);
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0);
gbinder_local_object_unref(self);
}
}
static
void
gbinder_local_object_release_proc(
gpointer obj)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(obj);
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->release(self);
}
/*==========================================================================*
@@ -335,42 +387,66 @@ gbinder_local_object_new(
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data) /* Since 1.0.30 */
{
return gbinder_local_object_new_with_type(GBINDER_TYPE_LOCAL_OBJECT,
ipc, ifaces, txproc, user_data);
}
GBinderLocalObject*
gbinder_local_object_new_with_type(
GType type,
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* arg)
{
if (G_LIKELY(ipc)) {
GBinderLocalObject* self = g_object_new
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
GBinderLocalObjectPriv* priv = self->priv;
guint i = 0, n = gutil_strv_length((char**)ifaces);
gboolean append_base_interface;
GBinderLocalObject* obj = g_object_new(type, NULL);
if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
append_base_interface = TRUE;
n++;
} else {
append_base_interface = FALSE;
}
priv->ifaces = g_new(char*, n + 1);
if (ifaces) {
while (*ifaces) {
priv->ifaces[i++] = g_strdup(*ifaces++);
}
}
if (append_base_interface) {
priv->ifaces[i++] = g_strdup(hidl_base_interface);
}
priv->ifaces[i] = NULL;
self->ipc = gbinder_ipc_ref(ipc);
self->ifaces = (const char**)priv->ifaces;
priv->txproc = txproc;
priv->user_data = user_data;
gbinder_ipc_register_local_object(ipc, self);
return self;
gbinder_local_object_init_base(obj, ipc, ifaces, txproc, arg);
gbinder_ipc_register_local_object(ipc, obj);
return obj;
}
return NULL;
}
void
gbinder_local_object_init_base(
GBinderLocalObject* self,
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
{
GBinderLocalObjectPriv* priv = self->priv;
guint i = 0, n = gutil_strv_length((char**)ifaces);
gboolean append_base_interface;
if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
append_base_interface = TRUE;
n++;
} else {
append_base_interface = FALSE;
}
priv->ifaces = g_new(char*, n + 1);
if (ifaces) {
while (*ifaces) {
priv->ifaces[i++] = g_strdup(*ifaces++);
}
}
if (append_base_interface) {
priv->ifaces[i++] = g_strdup(hidl_base_interface);
}
priv->ifaces[i] = NULL;
self->ipc = gbinder_ipc_ref(ipc);
self->ifaces = (const char**)priv->ifaces;
self->stability = GBINDER_STABILITY_SYSTEM;
priv->txproc = txproc;
priv->user_data = user_data;
}
GBinderLocalObject*
gbinder_local_object_ref(
GBinderLocalObject* self)
@@ -397,11 +473,7 @@ gbinder_local_object_drop(
GBinderLocalObject* self)
{
if (G_LIKELY(self)) {
GBinderLocalObjectPriv* priv = self->priv;
/* Clear the transaction callback */
priv->txproc = NULL;
priv->user_data = NULL;
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->drop(self);
g_object_unref(GBINDER_LOCAL_OBJECT(self));
}
}
@@ -411,7 +483,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;
}
@@ -495,33 +567,59 @@ void
gbinder_local_object_handle_increfs(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_increfs_proc);
gbinder_local_object_handle_later(self, gbinder_local_object_increfs_proc);
}
void
gbinder_local_object_handle_decrefs(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_decrefs_proc);
gbinder_local_object_handle_later(self, gbinder_local_object_decrefs_proc);
}
void
gbinder_local_object_handle_acquire(
GBinderLocalObject* self)
GBinderLocalObject* self,
GBinderBufferContentsList* bufs)
{
gbinder_local_object_ref(self);
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_acquire_proc);
if (G_LIKELY(self)) {
GBinderLocalObjectAcquireData* data =
g_slice_new(GBinderLocalObjectAcquireData);
/*
* This is a bit complicated :)
* GBinderProxyObject derived from GBinderLocalObject acquires a
* reference to the remote object in addition to performing the
* default GBinderLocalObject action later on the main thread.
* We must ensure that remote object doesn't go away before we
* acquire our reference to it. One of the references to that
* remote object (possibly the last one) may be associated with
* the transaction buffer contained in GBinderBufferContentsList.
* We don't know exactly which one we need, so we keep all those
* buffers alive until we are done with BR_ACQUIRE.
*/
data->object = gbinder_local_object_ref(self);
data->bufs = gbinder_buffer_contents_list_dup(bufs);
gbinder_idle_callback_invoke_later(gbinder_local_object_acquire_proc,
data, gbinder_local_object_acquire_done);
}
}
void
gbinder_local_object_handle_release(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_release_proc);
gbinder_local_object_handle_later(self, gbinder_local_object_release_proc);
}
void
gbinder_local_object_set_stability(
GBinderLocalObject* self,
GBINDER_STABILITY_LEVEL stability) /* Since 1.1.40 */
{
if (G_LIKELY(self)) {
self->stability = stability;
}
}
/*==========================================================================*
@@ -536,33 +634,33 @@ gbinder_local_object_init(
GBinderLocalObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObjectPriv);
priv->context = g_main_context_default();
self->priv = priv;
}
static
void
gbinder_local_object_dispose(
GObject* local)
GObject* object)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(object);
gbinder_ipc_local_object_disposed(self->ipc, self);
G_OBJECT_CLASS(gbinder_local_object_parent_class)->dispose(local);
G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
}
static
void
gbinder_local_object_finalize(
GObject* local)
GObject* object)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(object);
GBinderLocalObjectPriv* priv = self->priv;
GASSERT(!self->strong_refs);
gbinder_ipc_invalidate_local_object(self->ipc, self);
gbinder_ipc_unref(self->ipc);
g_strfreev(priv->ifaces);
G_OBJECT_CLASS(gbinder_local_object_parent_class)->finalize(local);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
@@ -582,6 +680,9 @@ gbinder_local_object_class_init(
gbinder_local_object_default_handle_looper_transaction;
klass->can_handle_transaction =
gbinder_local_object_default_can_handle_transaction;
klass->acquire = gbinder_local_object_default_acquire;
klass->release = gbinder_local_object_default_release;
klass->drop = gbinder_local_object_default_drop;
gbinder_local_object_signals[SIGNAL_WEAK_REFS_CHANGED] =
g_signal_new(SIGNAL_WEAK_REFS_CHANGED_NAME,

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,8 +40,9 @@
#include <glib-object.h>
/*
* Some if this stuff may become public if we decide to allow the clients
* to derive their classes from GBinderLocalObject
* Some of this stuff may become public if we decide to allow the clients
* to derive their own classes from GBinderLocalObject. For now it's all
* private.
*/
typedef
@@ -58,6 +59,7 @@ struct gbinder_local_object {
const char* const* ifaces;
gint weak_refs;
gint strong_refs;
GBINDER_STABILITY_LEVEL stability;
};
typedef enum gbinder_local_transaction_support {
@@ -76,6 +78,9 @@ typedef struct gbinder_local_object_class {
GBinderLocalReply* (*handle_looper_transaction)
(GBinderLocalObject* self, GBinderRemoteRequest* req, guint code,
guint flags, int* status);
void (*acquire)(GBinderLocalObject* self);
void (*release)(GBinderLocalObject* self);
void (*drop)(GBinderLocalObject* self);
/* Need to add some placeholders if this class becomes public */
} GBinderLocalObjectClass;
@@ -83,9 +88,31 @@ GType gbinder_local_object_get_type(void) GBINDER_INTERNAL;
#define GBINDER_TYPE_LOCAL_OBJECT (gbinder_local_object_get_type())
#define GBINDER_LOCAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObject))
#define GBINDER_LOCAL_OBJECT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObjectClass)
#define gbinder_local_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
#define gbinder_local_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
#define gbinder_local_object_protocol(obj) \
(gbinder_driver_protocol((obj)->ipc->driver))
GBinderLocalObject*
gbinder_local_object_new_with_type(
GType type,
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
GBINDER_INTERNAL;
void
gbinder_local_object_init_base(
GBinderLocalObject* self,
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
GBINDER_INTERNAL;
gulong
gbinder_local_object_add_weak_refs_changed_handler(
@@ -144,7 +171,8 @@ gbinder_local_object_handle_decrefs(
void
gbinder_local_object_handle_acquire(
GBinderLocalObject* obj)
GBinderLocalObject* obj,
GBinderBufferContentsList* bufs)
GBINDER_INTERNAL;
void

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
@@ -43,6 +43,7 @@ struct gbinder_local_reply {
gint refcount;
GBinderWriterData data;
GBinderOutputData out;
GBinderBufferContents* contents;
};
GBINDER_INLINE_FUNC
@@ -71,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;
@@ -86,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;
@@ -94,14 +98,16 @@ gbinder_local_reply_new(
}
GBinderLocalReply*
gbinder_local_reply_new_from_data(
GBinderBuffer* buffer)
gbinder_local_reply_set_contents(
GBinderLocalReply* self,
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
{
const GBinderIo* io = gbinder_buffer_io(buffer);
GBinderLocalReply* self = gbinder_local_reply_new(io);
if (self) {
gbinder_writer_data_set_contents(&self->data, buffer);
gbinder_writer_data_set_contents(&self->data, buffer, convert);
gbinder_buffer_contents_unref(self->contents);
self->contents = gbinder_buffer_contents_ref
(gbinder_buffer_contents(buffer));
}
return self;
}
@@ -116,7 +122,8 @@ gbinder_local_reply_free(
gutil_int_array_free(data->offsets, TRUE);
g_byte_array_free(data->bytes, TRUE);
gbinder_cleanup_free(data->cleanup);
g_slice_free(GBinderLocalReply, self);
gbinder_buffer_contents_unref(self->contents);
gutil_slice_free(self);
}
GBinderLocalReply*
@@ -149,6 +156,13 @@ gbinder_local_reply_data(
return G_LIKELY(self) ? &self->out : NULL;
}
GBinderBufferContents*
gbinder_local_reply_contents(
GBinderLocalReply* self)
{
return G_LIKELY(self) ? self->contents : NULL;
}
void
gbinder_local_reply_cleanup(
GBinderLocalReply* self,
@@ -296,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-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:
*
@@ -39,7 +39,8 @@
GBinderLocalReply*
gbinder_local_reply_new(
const GBinderIo* io)
const GBinderIo* io,
const GBinderRpcProtocol* protocol)
GBINDER_INTERNAL;
GBinderOutputData*
@@ -47,9 +48,16 @@ gbinder_local_reply_data(
GBinderLocalReply* reply)
GBINDER_INTERNAL;
GBinderBufferContents*
gbinder_local_reply_contents(
GBinderLocalReply* reply)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_local_reply_new_from_data(
GBinderBuffer* buffer)
gbinder_local_reply_set_contents(
GBinderLocalReply* reply,
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-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
@@ -31,6 +31,7 @@
*/
#include "gbinder_local_request_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_output_data.h"
#include "gbinder_writer_p.h"
#include "gbinder_buffer_p.h"
@@ -73,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;
@@ -88,9 +91,11 @@ 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);
writer->bytes = g_byte_array_sized_new(size);
g_byte_array_append(writer->bytes, data, size);
} else {
@@ -104,18 +109,49 @@ gbinder_local_request_new(
}
GBinderLocalRequest*
gbinder_local_request_new_from_data(
GBinderBuffer* buffer)
gbinder_local_request_new_iface(
const GBinderIo* io,
const GBinderRpcProtocol* protocol,
const char* iface)
{
GBinderLocalRequest* self = gbinder_local_request_new
(gbinder_buffer_io(buffer), NULL);
GBinderLocalRequest* self = gbinder_local_request_new(io, protocol, NULL);
if (self) {
gbinder_writer_data_set_contents(&self->data, buffer);
/* gbinder_local_request_new() fails if protocol is NULL */
if (self && G_LIKELY(iface)) {
GBinderWriter writer;
gbinder_local_request_init_writer(self, &writer);
protocol->write_rpc_header(&writer, iface);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_new_from_data(
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
{
GBinderLocalRequest* self = gbinder_local_request_new
(gbinder_buffer_io(buffer), gbinder_buffer_protocol(buffer), NULL);
if (self) {
gbinder_writer_data_append_contents(&self->data, buffer, 0, convert);
}
return self;
}
void
gbinder_local_request_append_contents(
GBinderLocalRequest* self,
GBinderBuffer* buffer,
gsize off,
GBinderObjectConverter* convert)
{
if (self) {
gbinder_writer_data_append_contents(&self->data, buffer, off, convert);
}
}
static
void
gbinder_local_request_free(

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,17 +40,34 @@
GBinderLocalRequest*
gbinder_local_request_new(
const GBinderIo* io,
const GBinderRpcProtocol* protocol,
GBytes* init)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_local_request_new_iface(
const GBinderIo* io,
const GBinderRpcProtocol* protocol,
const char* iface)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_local_request_new_from_data(
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
GBinderOutputData*
gbinder_local_request_data(
GBinderLocalRequest* req)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_local_request_new_from_data(
GBinderBuffer* buffer)
void
gbinder_local_request_append_contents(
GBinderLocalRequest* req,
GBinderBuffer* buffer,
gsize offset,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */

View File

@@ -38,6 +38,9 @@
#define GLOG_MODULE_NAME GBINDER_LOG_MODULE
#include <gutil_log.h>
#define DBG(fmt, ...) \
gutil_log(GLOG_MODULE_CURRENT, GLOG_LEVEL_ALWAYS, "gbinder:"fmt, ##__VA_ARGS__)
/* Declared for unit tests */
__attribute__((constructor))
void

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_OBJECT_CONVERTER_H
#define GBINDER_OBJECT_CONVERTER_H
#include "gbinder_types_p.h"
typedef struct gbinder_object_converter_functions {
GBinderLocalObject* (*handle_to_local)(GBinderObjectConverter*, guint32);
} GBinderObjectConverterFunctions;
struct gbinder_object_converter {
const GBinderObjectConverterFunctions* f;
const GBinderIo* io;
const GBinderRpcProtocol* protocol;
};
/* Inline wrappers */
GBINDER_INLINE_FUNC
GBinderLocalObject*
gbinder_object_converter_handle_to_local(
GBinderObjectConverter* convert,
guint32 handle)
{
return convert ? convert->f->handle_to_local(convert, handle) : NULL;
}
#endif /* GBINDER_OBJECT_CONVERTER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

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:
*
@@ -35,13 +35,19 @@
#include "gbinder_types_p.h"
typedef enum gbinder_remote_registry_create {
REMOTE_REGISTRY_DONT_CREATE,
REMOTE_REGISTRY_CAN_CREATE,
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE
} REMOTE_REGISTRY_CREATE;
typedef struct gbinder_object_registry_functions {
void (*ref)(GBinderObjectRegistry* reg);
void (*unref)(GBinderObjectRegistry* reg);
GBinderLocalObject* (*get_local)(GBinderObjectRegistry* reg,
void* pointer);
GBinderRemoteObject* (*get_remote)(GBinderObjectRegistry* reg,
guint32 handle);
guint32 handle, REMOTE_REGISTRY_CREATE create);
} GBinderObjectRegistryFunctions;
struct gbinder_object_registry {
@@ -81,9 +87,10 @@ GBINDER_INLINE_FUNC
GBinderRemoteObject*
gbinder_object_registry_get_remote(
GBinderObjectRegistry* reg,
guint32 handle)
guint32 handle,
REMOTE_REGISTRY_CREATE create)
{
return reg ? reg->f->get_remote(reg, handle) : NULL;
return reg ? reg->f->get_remote(reg, handle, create) : NULL;
}
#endif /* GBINDER_OBJECT_REGISTRY_H */

420
src/gbinder_proxy_object.c Normal file
View File

@@ -0,0 +1,420 @@
/*
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-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 "gbinder_proxy_object.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_request.h"
#include "gbinder_local_reply.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_remote_request_p.h"
#include "gbinder_remote_reply_p.h"
#include "gbinder_object_converter.h"
#include "gbinder_object_registry.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
#include <errno.h>
typedef GBinderLocalObjectClass GBinderProxyObjectClass;
typedef struct gbinder_proxy_tx GBinderProxyTx;
struct gbinder_proxy_tx {
GBinderProxyTx* next;
GBinderRemoteRequest* req;
GBinderProxyObject* proxy;
gulong id;
};
struct gbinder_proxy_object_priv {
gboolean acquired;
gboolean dropped;
GBinderProxyTx* tx;
};
G_DEFINE_TYPE(GBinderProxyObject, gbinder_proxy_object, \
GBINDER_TYPE_LOCAL_OBJECT)
#define GBINDER_IS_PROXY_OBJECT(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, \
GBINDER_TYPE_PROXY_OBJECT)
#define THIS(obj) GBINDER_PROXY_OBJECT(obj)
#define THIS_TYPE GBINDER_TYPE_PROXY_OBJECT
#define PARENT_CLASS gbinder_proxy_object_parent_class
/*==========================================================================*
* Converter
*==========================================================================*/
typedef struct gbinder_proxy_object_converter {
GBinderObjectConverter pub;
GBinderIpc* remote;
GBinderIpc* local;
} GBinderProxyObjectConverter;
GBINDER_INLINE_FUNC
GBinderProxyObjectConverter*
gbinder_proxy_object_converter_cast(
GBinderObjectConverter* pub)
{
return G_CAST(pub, GBinderProxyObjectConverter, pub);
}
static
gboolean
gbinder_proxy_object_converter_check(
GBinderLocalObject* obj,
void* remote)
{
if (GBINDER_IS_PROXY_OBJECT(obj) && THIS(obj)->remote == remote) {
/* Found matching proxy object */
return TRUE;
}
/* Keep looking */
return FALSE;
}
static
GBinderLocalObject*
gbinder_proxy_object_converter_handle_to_local(
GBinderObjectConverter* pub,
guint32 handle)
{
GBinderProxyObjectConverter* c = gbinder_proxy_object_converter_cast(pub);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(c->remote);
GBinderRemoteObject* remote = gbinder_object_registry_get_remote(reg,
handle, REMOTE_REGISTRY_CAN_CREATE /* but don't acquire */);
GBinderLocalObject* local = gbinder_ipc_find_local_object(c->local,
gbinder_proxy_object_converter_check, remote);
if (!local && !remote->dead) {
/* GBinderProxyObject will reference GBinderRemoteObject */
local = &gbinder_proxy_object_new(c->local, remote)->parent;
}
/* Release the reference returned by gbinder_object_registry_get_remote */
gbinder_remote_object_unref(remote);
return local;
}
static
void
gbinder_proxy_object_converter_init(
GBinderProxyObjectConverter* convert,
GBinderProxyObject* proxy,
GBinderIpc* remote,
GBinderIpc* local)
{
static const GBinderObjectConverterFunctions gbinder_converter_fn = {
.handle_to_local = gbinder_proxy_object_converter_handle_to_local
};
GBinderObjectConverter* pub = &convert->pub;
GBinderIpc* dest = proxy->parent.ipc;
memset(convert, 0, sizeof(*convert));
convert->remote = remote;
convert->local = local;
pub->f = &gbinder_converter_fn;
pub->io = gbinder_ipc_io(dest);
pub->protocol = gbinder_ipc_protocol(dest);
}
/*==========================================================================*
* Implementation
*==========================================================================*/
static
void
gbinder_proxy_tx_dequeue(
GBinderProxyTx* tx)
{
GBinderProxyObject* proxy = tx->proxy;
if (proxy) {
GBinderProxyObjectPriv* priv = proxy->priv;
if (priv->tx) {
if (priv->tx == tx) {
priv->tx = tx->next;
} else {
GBinderProxyTx* prev = priv->tx;
while (prev->next) {
if (prev->next == tx) {
prev->next = tx->next;
break;
}
prev = prev->next;
}
}
}
tx->next = NULL;
tx->proxy = NULL;
g_object_unref(proxy);
}
}
static
void
gbinder_proxy_tx_reply(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
GBinderProxyTx* tx = user_data;
GBinderProxyObject* self = tx->proxy;
GBinderProxyObjectConverter convert;
GBinderLocalReply* fwd;
/*
* For proxy objects auto-created by the reply, the remote side (the
* one sent the reply) will be the remote GBinderIpc and this object's
* GBinderIpc will be the local, i.e. those proxies will work in the
* same direction as the top level object. The direction gets inverted
* twice.
*/
gbinder_proxy_object_converter_init(&convert, self, ipc, self->parent.ipc);
fwd = gbinder_remote_reply_convert_to_local(reply, &convert.pub);
tx->id = 0;
gbinder_proxy_tx_dequeue(tx);
gbinder_remote_request_complete(tx->req, fwd,
(status > 0) ? (-EFAULT) : status);
if (status == GBINDER_STATUS_DEAD_OBJECT) {
/*
* Some kernels sometimes don't bother sending us death notifications.
* Let's also interpret BR_DEAD_REPLY as an obituary to make sure that
* we don't keep dead remote objects around.
*/
gbinder_remote_object_commit_suicide(self->remote);
}
gbinder_local_reply_unref(fwd);
}
static
void
gbinder_proxy_tx_destroy(
gpointer user_data)
{
GBinderProxyTx* tx = user_data;
gbinder_proxy_tx_dequeue(tx);
gbinder_remote_request_unref(tx->req);
gutil_slice_free(tx);
}
static
GBinderLocalReply*
gbinder_proxy_object_handle_transaction(
GBinderLocalObject* object,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
GBinderRemoteObject* remote = self->remote;
if (!priv->dropped && !remote->dead) {
GBinderLocalRequest* fwd;
GBinderProxyTx* tx = g_slice_new0(GBinderProxyTx);
GBinderProxyObjectConverter convert;
g_object_ref(tx->proxy = self);
tx->req = gbinder_remote_request_ref(req);
tx->next = priv->tx;
priv->tx = tx;
/* Mark the incoming request as pending */
gbinder_remote_request_block(req);
/*
* For auto-created proxy objects, this object's GBinderIpc will
* become a remote, and the remote's GBinderIpc will become local
* because they work in the opposite direction.
*/
gbinder_proxy_object_converter_init(&convert, self, object->ipc,
remote->ipc);
/* Forward the transaction */
fwd = gbinder_remote_request_convert_to_local(req, &convert.pub);
tx->id = gbinder_ipc_transact(remote->ipc, remote->handle, code, flags,
fwd, gbinder_proxy_tx_reply, gbinder_proxy_tx_destroy, tx);
gbinder_local_request_unref(fwd);
*status = GBINDER_STATUS_OK;
} else {
GVERBOSE_("dropped: %d dead:%d", priv->dropped, remote->dead);
*status = (-EBADMSG);
}
return NULL;
}
static
GBINDER_LOCAL_TRANSACTION_SUPPORT
gbinder_proxy_object_can_handle_transaction(
GBinderLocalObject* self,
const char* iface,
guint code)
{
/* Process all transactions on the main thread */
return GBINDER_LOCAL_TRANSACTION_SUPPORTED;
}
static
void
gbinder_proxy_object_acquire(
GBinderLocalObject* object)
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
GBinderRemoteObject* remote = self->remote;
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_drop(
GBinderLocalObject* object)
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
priv->dropped = TRUE;
GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->drop(object);
}
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderProxyObject*
gbinder_proxy_object_new(
GBinderIpc* src,
GBinderRemoteObject* remote)
{
if (G_LIKELY(remote)) {
/*
* We don't need to specify the interface list because all
* transactions (including HIDL_GET_DESCRIPTOR_TRANSACTION
* and HIDL_DESCRIPTOR_CHAIN_TRANSACTION) are getting forwared
* to the remote object.
*/
GBinderLocalObject* object = gbinder_local_object_new_with_type
(THIS_TYPE, src, NULL, NULL, NULL);
if (object) {
GBinderProxyObject* self = THIS(object);
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;
}
}
return NULL;
}
/*==========================================================================*
* Internals
*==========================================================================*/
static
void
gbinder_proxy_object_finalize(
GObject* object)
{
GBinderProxyObject* self = THIS(object);
GBinderProxyObjectPriv* priv = self->priv;
GBinderLocalObject* local = &self->parent;
GBinderRemoteObject* remote = self->remote;
/*
* 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);
}
static
void
gbinder_proxy_object_init(
GBinderProxyObject* self)
{
GBinderProxyObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
THIS_TYPE, GBinderProxyObjectPriv);
self->priv = priv;
}
static
void
gbinder_proxy_object_class_init(
GBinderProxyObjectClass* klass)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
g_type_class_add_private(klass, sizeof(GBinderProxyObjectPriv));
object_class->finalize = gbinder_proxy_object_finalize;
klass->can_handle_transaction = gbinder_proxy_object_can_handle_transaction;
klass->handle_transaction = gbinder_proxy_object_handle_transaction;
klass->acquire = gbinder_proxy_object_acquire;
klass->drop = gbinder_proxy_object_drop;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_PROXY_OBJECT_H
#define GBINDER_PROXY_OBJECT_H
#include "gbinder_local_object_p.h"
typedef struct gbinder_proxy_object_priv GBinderProxyObjectPriv;
struct gbinder_proxy_object {
GBinderLocalObject parent;
GBinderProxyObjectPriv* priv;
GBinderRemoteObject* remote;
};
GType gbinder_proxy_object_get_type(void) GBINDER_INTERNAL;
#define GBINDER_TYPE_PROXY_OBJECT gbinder_proxy_object_get_type()
#define GBINDER_PROXY_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_PROXY_OBJECT, GBinderProxyObject))
/* Registers with src and forwards all transactions to the remote */
GBinderProxyObject*
gbinder_proxy_object_new(
GBinderIpc* src,
GBinderRemoteObject* remote)
GBINDER_INTERNAL;
#endif /* GBINDER_PROXY_OBJECT_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

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-2024 Jolla Ltd.
* Copyright (C) 2018-2024 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(
@@ -674,19 +770,45 @@ gbinder_reader_read_byte_array(
*len = (gsize)*ptr;
p->ptr += sizeof(*ptr);
data = p->ptr;
p->ptr += *len;
/* Android aligns byte array reads and writes to 4 bytes */
p->ptr += G_ALIGN4(*len);
}
}
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 +817,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 +825,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-2020 Jolla Ltd.
* Copyright (C) 2018-2020 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:
*
@@ -30,25 +30,24 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_servicemanager_p.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_log.h"
struct gbinder_remote_object_priv {
GMainContext* context;
gboolean acquired;
};
typedef GObjectClass GBinderRemoteObjectClass;
GType gbinder_remote_object_get_type(void) GBINDER_INTERNAL;
G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT)
GType gbinder_remote_object_get_type(void);
#define GBINDER_TYPE_REMOTE_OBJECT (gbinder_remote_object_get_type())
#define GBINDER_REMOTE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObject))
#define PARENT_CLASS gbinder_remote_object_parent_class
#define THIS_TYPE (gbinder_remote_object_get_type())
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,THIS_TYPE,GBinderRemoteObject)
enum gbinder_remote_object_signal {
SIGNAL_DEATH,
@@ -65,34 +64,31 @@ static guint gbinder_remote_object_signals[SIGNAL_COUNT] = { 0 };
static
void
gbinder_remote_object_died_on_main_thread(
GBinderRemoteObject* self)
gbinder_remote_object_handle_death_on_main_thread(
gpointer user_data)
{
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
GBinderRemoteObject* self = THIS(user_data);
GASSERT(!self->dead);
if (!self->dead) {
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
GBinderRemoteObjectPriv* priv = self->priv;
self->dead = TRUE;
if (priv->acquired) {
priv->acquired = FALSE;
/* Release the dead node */
gbinder_driver_release(driver, self->handle);
}
/* ServiceManager always has the same handle, and can be reanimated. */
if (self->handle != GBINDER_SERVICEMANAGER_HANDLE) {
gbinder_ipc_invalidate_remote_handle(self->ipc, self->handle);
gbinder_ipc_invalidate_remote_handle(ipc, self->handle);
}
gbinder_driver_clear_death_notification(driver, self);
gbinder_driver_release(driver, self->handle);
gbinder_driver_dead_binder_done(driver, self);
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
}
}
static
gboolean
gbinder_remote_object_died_handle(
gpointer self)
{
gbinder_remote_object_died_on_main_thread(GBINDER_REMOTE_OBJECT(self));
return G_SOURCE_REMOVE;
}
/*==========================================================================*
* Internal interface
*==========================================================================*/
@@ -108,16 +104,20 @@ gbinder_remote_object_reanimate(
*/
if (self->dead) {
GBinderIpc* ipc = self->ipc;
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
guint32 handle = self->handle;
/* Kick the horse */
GASSERT(self->handle == GBINDER_SERVICEMANAGER_HANDLE);
if (gbinder_driver_ping(ipc->driver, reg, self->handle) == 0) {
if (gbinder_ipc_ping_sync(ipc, handle, &gbinder_ipc_sync_main) == 0) {
GBinderRemoteObjectPriv* priv = self->priv;
GBinderDriver* driver = ipc->driver;
/* Wow, it's alive! */
self->dead = FALSE;
gbinder_ipc_looper_check(self->ipc); /* For death notifications */
gbinder_driver_acquire(ipc->driver, self->handle);
gbinder_driver_request_death_notification(ipc->driver, self);
priv->acquired = TRUE;
gbinder_ipc_looper_check(ipc); /* For death notifications */
gbinder_driver_acquire(driver, handle);
gbinder_driver_request_death_notification(driver, self);
}
}
return !self->dead;
@@ -130,9 +130,34 @@ gbinder_remote_object_handle_death_notification(
/* This function is invoked from the looper thread, the caller has
* checked the object pointer */
GVERBOSE_("%p %u", self, self->handle);
g_main_context_invoke_full(self->priv->context, G_PRIORITY_DEFAULT,
gbinder_remote_object_died_handle, gbinder_remote_object_ref(self),
g_object_unref);
gbinder_idle_callback_invoke_later
(gbinder_remote_object_handle_death_on_main_thread,
gbinder_remote_object_ref(self), g_object_unref);
}
void
gbinder_remote_object_commit_suicide(
GBinderRemoteObject* self)
{
/* This function is only invoked by GBinderProxyObject in context of
* the main thread, the object pointer is checked by the caller */
if (!self->dead) {
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
GBinderRemoteObjectPriv* priv = self->priv;
self->dead = TRUE;
gbinder_driver_clear_death_notification(driver, self);
if (priv->acquired) {
priv->acquired = FALSE;
/* Release the dead node */
gbinder_driver_release(driver, self->handle);
}
GVERBOSE_("%p %u", self, self->handle);
gbinder_ipc_invalidate_remote_handle(self->ipc, self->handle);
/* Don't submit BC_DEAD_BINDER_DONE because this is a suicide */
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
}
}
/*==========================================================================*
@@ -143,17 +168,29 @@ GBinderRemoteObject*
gbinder_remote_object_new(
GBinderIpc* ipc,
guint32 handle,
gboolean dead)
REMOTE_OBJECT_CREATE create)
{
if (G_LIKELY(ipc)) {
GBinderRemoteObject* self = g_object_new
(GBINDER_TYPE_REMOTE_OBJECT, NULL);
GBinderRemoteObject* self = g_object_new(THIS_TYPE, NULL);
GBinderRemoteObjectPriv* priv = self->priv;
self->ipc = gbinder_ipc_ref(ipc);
self->handle = handle;
if (!(self->dead = dead)) {
switch (create) {
case REMOTE_OBJECT_CREATE_DEAD:
self->dead = TRUE;
break;
case REMOTE_OBJECT_CREATE_ACQUIRED:
priv->acquired = TRUE;
/* fallthrough */
case REMOTE_OBJECT_CREATE_ALIVE:
break;
}
if (!self->dead) {
gbinder_ipc_looper_check(self->ipc); /* For death notifications */
gbinder_driver_acquire(ipc->driver, handle);
if (priv->acquired) {
gbinder_driver_acquire(ipc->driver, handle);
}
gbinder_driver_request_death_notification(ipc->driver, self);
}
return self;
@@ -166,7 +203,7 @@ gbinder_remote_object_ref(
GBinderRemoteObject* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_REMOTE_OBJECT(self));
g_object_ref(THIS(self));
return self;
} else {
return NULL;
@@ -178,7 +215,7 @@ gbinder_remote_object_unref(
GBinderRemoteObject* self)
{
if (G_LIKELY(self)) {
g_object_unref(GBINDER_REMOTE_OBJECT(self));
g_object_unref(THIS(self));
}
}
@@ -230,38 +267,41 @@ gbinder_remote_object_init(
GBinderRemoteObject* self)
{
GBinderRemoteObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObjectPriv);
THIS_TYPE, GBinderRemoteObjectPriv);
priv->context = g_main_context_default();
self->priv = priv;
}
static
void
gbinder_remote_object_dispose(
GObject* remote)
GObject* object)
{
GBinderRemoteObject* self = GBINDER_REMOTE_OBJECT(remote);
GBinderRemoteObject* self = THIS(object);
gbinder_ipc_remote_object_disposed(self->ipc, self);
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->dispose(remote);
G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
}
static
void
gbinder_remote_object_finalize(
GObject* remote)
GObject* object)
{
GBinderRemoteObject* self = GBINDER_REMOTE_OBJECT(remote);
GBinderRemoteObject* self = THIS(object);
GBinderRemoteObjectPriv* priv = self->priv;
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
gbinder_ipc_invalidate_remote_handle(ipc, self->handle);
if (!self->dead) {
gbinder_driver_clear_death_notification(driver, self);
}
if (priv->acquired) {
gbinder_driver_release(driver, self->handle);
}
gbinder_ipc_unref(ipc);
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->finalize(remote);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static

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:
*
@@ -51,11 +51,17 @@ struct gbinder_remote_object {
#define gbinder_remote_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
#define gbinder_remote_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
typedef enum gbinder_remote_object_create {
REMOTE_OBJECT_CREATE_DEAD,
REMOTE_OBJECT_CREATE_ALIVE,
REMOTE_OBJECT_CREATE_ACQUIRED
} REMOTE_OBJECT_CREATE;
GBinderRemoteObject*
gbinder_remote_object_new(
GBinderIpc* ipc,
guint32 handle,
gboolean maybe_dead)
REMOTE_OBJECT_CREATE create)
GBINDER_INTERNAL;
gboolean
@@ -68,6 +74,11 @@ gbinder_remote_object_handle_death_notification(
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
void
gbinder_remote_object_commit_suicide(
GBinderRemoteObject* self)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_OBJECT_PRIVATE_H */
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2024 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
@@ -73,15 +73,12 @@ gbinder_remote_reply_set_data(
GBinderRemoteReply* self,
GBinderBuffer* buffer)
{
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
/* The caller checks the pointer for NULL */
GBinderReaderData* data = &self->data;
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = gbinder_buffer_objects(buffer);
} else {
gbinder_buffer_free(buffer);
}
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = gbinder_buffer_objects(buffer);
}
GBinderRemoteReply*
@@ -117,11 +114,24 @@ gbinder_remote_reply_is_empty(
GBinderLocalReply*
gbinder_remote_reply_copy_to_local(
GBinderRemoteReply* self)
{
return gbinder_remote_reply_convert_to_local(self, NULL);
}
GBinderLocalReply*
gbinder_remote_reply_convert_to_local(
GBinderRemoteReply* self,
GBinderObjectConverter* convert)
{
if (G_LIKELY(self)) {
GBinderReaderData* d = &self->data;
GBinderObjectRegistry* reg = d->reg;
return gbinder_local_reply_new_from_data(d->buffer);
if (reg) {
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-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:
*
@@ -42,6 +42,12 @@ gbinder_remote_reply_new(
GBinderObjectRegistry* reg)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_remote_reply_convert_to_local(
GBinderRemoteReply* reply,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
void
gbinder_remote_reply_set_data(
GBinderRemoteReply* reply,

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-2024 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
@@ -34,8 +34,10 @@
#include "gbinder_reader_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_local_request_p.h"
#include "gbinder_object_converter.h"
#include "gbinder_object_registry.h"
#include "gbinder_buffer_p.h"
#include "gbinder_driver.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
@@ -85,7 +87,33 @@ gbinder_remote_request_copy_to_local(
if (G_LIKELY(self)) {
GBinderReaderData* d = &self->data;
return gbinder_local_request_new_from_data(d->buffer);
return gbinder_local_request_new_from_data(d->buffer, NULL);
}
return NULL;
}
GBinderLocalRequest*
gbinder_remote_request_convert_to_local(
GBinderRemoteRequest* req,
GBinderObjectConverter* convert)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
if (!convert || convert->protocol == self->protocol) {
/* The same protocol, the same format of RPC header */
return gbinder_local_request_new_from_data(data->buffer, convert);
} else {
/* Need to translate to another format */
GBinderLocalRequest* local = gbinder_local_request_new_iface
(convert->io, convert->protocol, self->iface);
gbinder_local_request_append_contents(local, data->buffer,
self->header_size, convert);
return local;
}
}
return NULL;
}
@@ -134,29 +162,25 @@ gbinder_remote_request_set_data(
guint32 txcode,
GBinderBuffer* buffer)
{
/* The caller never passes NULL req */
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
GBinderReaderData* data = &self->data;
GBinderReader reader;
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
GBinderReader reader;
g_free(self->iface2);
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = gbinder_buffer_objects(buffer);
g_free(self->iface2);
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = gbinder_buffer_objects(buffer);
/* Parse RPC header */
gbinder_remote_request_init_reader2(self, &reader);
self->iface = self->protocol->read_rpc_header(&reader, txcode,
&self->iface2);
if (self->iface) {
self->header_size = gbinder_reader_bytes_read(&reader);
} else {
/* No RPC header */
self->header_size = 0;
}
/* Parse RPC header */
gbinder_remote_request_init_reader2(self, &reader);
self->iface = self->protocol->read_rpc_header(&reader, txcode,
&self->iface2);
if (self->iface) {
self->header_size = gbinder_reader_bytes_read(&reader);
} else {
gbinder_buffer_free(buffer);
/* No RPC header */
self->header_size = 0;
}
}

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:
*
@@ -56,6 +56,12 @@ gbinder_remote_request_set_data(
GBinderBuffer* buffer)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_remote_request_convert_to_local(
GBinderRemoteRequest* req,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_REQUEST_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:
*
@@ -35,11 +35,17 @@
#include "gbinder_writer.h"
#include "gbinder_config.h"
#include "gbinder_log.h"
#include "gbinder_local_object_p.h"
#include <string.h>
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#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 +179,103 @@ 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)
{
if (G_LIKELY(obj)) {
*(guint32*)out = obj->stability;
} else {
*(guint32*)out = GBINDER_STABILITY_UNDECLARED;
}
}
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
};
/*==========================================================================*
* AIDL protocol appeared in Android 12 (API level 31), but reverted in
* Android 13 (API level 33).
*==========================================================================*/
#define BINDER_WIRE_FORMAT_VERSION_AIDL4 1
struct stability_category {
guint8 binder_wire_format_version;
guint8 reserved[2];
guint8 stability_level;
};
G_STATIC_ASSERT(sizeof(struct stability_category) == sizeof(guint32));
static
void
gbinder_rpc_protocol_aidl4_finish_flatten_binder(
void* out,
GBinderLocalObject* obj)
{
struct stability_category cat = {
.binder_wire_format_version = BINDER_WIRE_FORMAT_VERSION_AIDL4,
.reserved = { 0, 0, },
.stability_level = obj ? obj->stability : GBINDER_STABILITY_UNDECLARED,
};
memcpy(out, &cat, sizeof(cat));
}
static const GBinderRpcProtocol gbinder_rpc_protocol_aidl4 = {
.name = "aidl4",
.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_aidl4_finish_flatten_binder
};
/*==========================================================================*
* The original /dev/hwbinder protocol.
*==========================================================================*/
@@ -225,6 +328,8 @@ 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_aidl4,
&gbinder_rpc_protocol_hidl
};
@@ -331,6 +436,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-2020 Jolla Ltd.
* Copyright (C) 2018-2020 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:
*
@@ -30,8 +30,6 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_servicemanager_p.h"
#include "gbinder_client_p.h"
#include "gbinder_config.h"
@@ -82,11 +80,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;
@@ -199,7 +199,8 @@ gbinder_servicemanager_list_tx_exec(
{
GBinderServiceManagerListTxData* data = tx->user_data;
data->result = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->list(data->sm);
data->result = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
list(data->sm, &gbinder_ipc_sync_worker);
}
static
@@ -243,8 +244,9 @@ gbinder_servicemanager_get_service_tx_exec(
{
GBinderServiceManagerGetServiceTxData* data = tx->user_data;
data->obj = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->get_service
(data->sm, data->name, &data->status);
data->obj = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
get_service(data->sm, data->name, &data->status,
&gbinder_ipc_sync_worker);
}
static
@@ -286,8 +288,8 @@ gbinder_servicemanager_add_service_tx_exec(
{
GBinderServiceManagerAddServiceTxData* data = tx->user_data;
data->status = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->add_service
(data->sm, data->name, data->obj);
data->status = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
add_service(data->sm, data->name, data->obj, &gbinder_ipc_sync_worker);
}
static
@@ -516,7 +518,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);
@@ -525,11 +528,10 @@ 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 remote object */
GBinderRemoteObject* object = gbinder_ipc_get_remote_object
(ipc, GBINDER_SERVICEMANAGER_HANDLE, TRUE);
/* Create a (possibly) dead service manager object */
GBinderRemoteObject* object = gbinder_ipc_get_service_manager(ipc);
if (object) {
gboolean first_ref;
@@ -618,25 +620,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);
@@ -644,9 +657,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*
@@ -697,6 +722,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 */
@@ -776,7 +808,8 @@ gbinder_servicemanager_list_sync(
GBinderServiceManager* self)
{
if (G_LIKELY(self)) {
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->list(self);
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->
list(self, &gbinder_ipc_sync_main);
}
return NULL;
}
@@ -815,8 +848,8 @@ gbinder_servicemanager_get_service_sync(
GBinderRemoteObject* obj = NULL;
if (G_LIKELY(self) && name) {
obj = GBINDER_SERVICEMANAGER_GET_CLASS(self)->get_service
(self, name, status);
obj = GBINDER_SERVICEMANAGER_GET_CLASS(self)->
get_service(self, name, status, &gbinder_ipc_sync_main);
if (obj) {
GBinderServiceManagerPriv* priv = self->priv;
@@ -866,8 +899,8 @@ gbinder_servicemanager_add_service_sync(
GBinderLocalObject* obj)
{
if (G_LIKELY(self) && name && obj) {
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->add_service
(self, name, obj);
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->
add_service(self, name, obj, &gbinder_ipc_sync_main);
} else {
return (-EINVAL);
}
@@ -1006,7 +1039,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*
@@ -1014,7 +1047,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

@@ -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-2023 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -30,14 +30,12 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_servicemanager_aidl.h"
#include "gbinder_servicepoll.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_client_p.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
@@ -61,16 +59,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"
@@ -172,7 +160,8 @@ gbinder_servicemanager_aidl_add_service_req(
static
char**
gbinder_servicemanager_aidl_list(
GBinderServiceManager* manager)
GBinderServiceManager* manager,
const GBinderIpcSyncApi* api)
{
GPtrArray* list = g_ptr_array_new();
GBinderClient* client = manager->client;
@@ -181,8 +170,8 @@ gbinder_servicemanager_aidl_list(
GBinderLocalRequest* req = klass->list_services_req(client, 0);
GBinderRemoteReply* reply;
while ((reply = gbinder_client_transact_sync_reply(client,
LIST_SERVICES_TRANSACTION, req, NULL)) != NULL) {
while ((reply = gbinder_client_transact_sync_reply2(client,
LIST_SERVICES_TRANSACTION, req, NULL, api)) != NULL) {
char* service = gbinder_remote_reply_read_string16(reply);
gbinder_remote_reply_unref(reply);
@@ -205,15 +194,16 @@ GBinderRemoteObject*
gbinder_servicemanager_aidl_get_service(
GBinderServiceManager* self,
const char* name,
int* status)
int* status,
const GBinderIpcSyncApi* api)
{
GBinderRemoteObject* obj;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
reply = gbinder_client_transact_sync_reply(self->client,
CHECK_SERVICE_TRANSACTION, req, status);
reply = gbinder_client_transact_sync_reply2(self->client,
CHECK_SERVICE_TRANSACTION, req, status, api);
obj = gbinder_remote_reply_read_object(reply);
gbinder_remote_reply_unref(reply);
@@ -226,14 +216,15 @@ int
gbinder_servicemanager_aidl_add_service(
GBinderServiceManager* manager,
const char* name,
GBinderLocalObject* obj)
GBinderLocalObject* obj,
const GBinderIpcSyncApi* api)
{
int status;
GBinderClient* client = manager->client;
GBinderLocalRequest* req = GBINDER_SERVICEMANAGER_AIDL_GET_CLASS
(manager)->add_service_req(client, name, obj);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply(client,
ADD_SERVICE_TRANSACTION, req, &status);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply2(client,
ADD_SERVICE_TRANSACTION, req, &status, api);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);

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

@@ -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:
*
@@ -31,9 +31,9 @@
*/
#include "gbinder_servicemanager_p.h"
#include "gbinder_client_p.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gbinder_local_object.h>
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
@@ -147,11 +147,12 @@ gbinder_servicemanager_hidl_notification(
static
char**
gbinder_servicemanager_hidl_list(
GBinderServiceManager* self)
GBinderServiceManager* self,
const GBinderIpcSyncApi* api)
{
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply
(self->client, LIST_TRANSACTION, req, NULL);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply2
(self->client, LIST_TRANSACTION, req, NULL, api);
gbinder_local_request_unref(req);
if (reply) {
@@ -178,7 +179,8 @@ GBinderRemoteObject*
gbinder_servicemanager_hidl_get_service(
GBinderServiceManager* self,
const char* fqinstance,
int* status)
int* status,
const GBinderIpcSyncApi* api)
{
/* e.g. "android.hardware.radio@1.1::IRadio/slot1" */
const char* sep = strchr(fqinstance, '/');
@@ -193,8 +195,8 @@ gbinder_servicemanager_hidl_get_service(
gbinder_local_request_append_hidl_string(req, fqname);
gbinder_local_request_append_hidl_string(req, name);
reply = gbinder_client_transact_sync_reply(self->client,
GET_TRANSACTION, req, status);
reply = gbinder_client_transact_sync_reply2(self->client,
GET_TRANSACTION, req, status, api);
if (reply) {
GBinderReader reader;
@@ -225,7 +227,8 @@ int
gbinder_servicemanager_hidl_add_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj)
GBinderLocalObject* obj,
const GBinderIpcSyncApi* api)
{
int status;
GBinderRemoteReply* reply;
@@ -235,8 +238,8 @@ gbinder_servicemanager_hidl_add_service(
gbinder_local_request_append_hidl_string(req, name);
gbinder_local_request_append_local_object(req, obj);
reply = gbinder_client_transact_sync_reply(self->client,
ADD_TRANSACTION, req, &status);
reply = gbinder_client_transact_sync_reply2(self->client,
ADD_TRANSACTION, req, &status, api);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);

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:
*
@@ -39,9 +39,6 @@
#include <glib-object.h>
/* As a special case, ServiceManager's handle is zero */
#define GBINDER_SERVICEMANAGER_HANDLE (0)
typedef struct gbinder_servicemanager_priv GBinderServiceManagerPriv;
typedef struct gbinder_servicemanager {
@@ -66,12 +63,11 @@ typedef struct gbinder_servicemanager_class {
const char* default_device;
/* Methods (synchronous) */
char** (*list)(GBinderServiceManager* self);
GBinderRemoteObject* (*get_service)
(GBinderServiceManager* self, const char* name, int* status);
int (*add_service)
(GBinderServiceManager* self, const char* name,
GBinderLocalObject* obj);
char** (*list)(GBinderServiceManager* self, const GBinderIpcSyncApi* api);
GBinderRemoteObject* (*get_service)(GBinderServiceManager* self,
const char* name, int* status, const GBinderIpcSyncApi* api);
int (*add_service)(GBinderServiceManager* self, const char* name,
GBinderLocalObject* obj, const GBinderIpcSyncApi* api);
/* Checking/normalizing watch names */
GBINDER_SERVICEMANAGER_NAME_CHECK (*check_name)
@@ -89,10 +85,13 @@ GType gbinder_servicemanager_get_type(void) GBINDER_INTERNAL;
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
#define gbinder_servicemanager_ipc(sm) gbinder_client_ipc(sm->client)
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
GType type,
const char* dev)
const char* dev,
const char* rpc_protocol)
GBINDER_INTERNAL;
void
@@ -112,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) 2019 Jolla Ltd.
* Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2019-2021 Jolla Ltd.
* Copyright (C) 2019-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -31,6 +31,7 @@
*/
#include "gbinder_types_p.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_servicename.h"
#include "gbinder_servicemanager.h"
#include "gbinder_local_object.h"
@@ -40,16 +41,24 @@
/* Since 1.0.26 */
#define GBINDER_SERVICENAME_RETRY_INTERVAL_MS (500)
typedef struct gbinder_servicename_priv {
GBinderServiceName pub;
gint refcount;
char* name;
GBinderLocalObject* object;
GBinderServiceManager* sm;
GBinderEventLoopTimeout* retry_timer;
gulong presence_id;
gulong add_call_id;
} GBinderServiceNamePriv;
static
void
gbinder_servicename_add_service(
GBinderServiceNamePriv* priv);
GBINDER_INLINE_FUNC GBinderServiceNamePriv*
gbinder_servicename_cast(GBinderServiceName* pub)
{ return G_CAST(pub, GBinderServiceNamePriv, pub); }
@@ -58,6 +67,18 @@ gbinder_servicename_cast(GBinderServiceName* pub)
* Implementation
*==========================================================================*/
static
gboolean
gbinder_servicename_add_service_retry(
gpointer user_data)
{
GBinderServiceNamePriv* priv = user_data;
priv->retry_timer = NULL;
gbinder_servicename_add_service(priv);
return G_SOURCE_REMOVE;
}
static
void
gbinder_servicename_add_service_done(
@@ -71,6 +92,10 @@ gbinder_servicename_add_service_done(
priv->add_call_id = 0;
if (status) {
GWARN("Error %d adding name \"%s\"", status, priv->name);
gbinder_timeout_remove(priv->retry_timer);
priv->retry_timer =
gbinder_timeout_add(GBINDER_SERVICENAME_RETRY_INTERVAL_MS,
gbinder_servicename_add_service_retry, priv);
} else {
GDEBUG("Service \"%s\" has been registered", priv->name);
}
@@ -97,9 +122,15 @@ gbinder_servicename_presence_handler(
if (gbinder_servicemanager_is_present(sm)) {
gbinder_servicename_add_service(priv);
} else if (priv->add_call_id) {
gbinder_servicemanager_cancel(priv->sm, priv->add_call_id);
priv->add_call_id = 0;
} else {
if (priv->add_call_id) {
gbinder_servicemanager_cancel(priv->sm, priv->add_call_id);
priv->add_call_id = 0;
}
if (priv->retry_timer) {
gbinder_timeout_remove(priv->retry_timer);
priv->retry_timer = NULL;
}
}
}
@@ -158,8 +189,9 @@ gbinder_servicename_unref(
gbinder_servicemanager_remove_handler(priv->sm, priv->presence_id);
gbinder_servicemanager_unref(priv->sm);
gbinder_local_object_unref(priv->object);
gbinder_timeout_remove(priv->retry_timer);
g_free(priv->name);
g_slice_free(GBinderServiceName, self);
gutil_slice_free(priv);
}
}
}

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 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -34,6 +34,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -58,7 +59,10 @@ gbinder_system_ioctl(
int request,
void* data)
{
return ioctl(fd, request, data);
int ret;
while ((ret = ioctl(fd, request, data)) < 0 && errno == EINTR);
return ret >= 0 ? 0 : -errno;
}
void*

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:
*
@@ -36,15 +36,19 @@
#include <gbinder_types.h>
typedef struct gbinder_buffer_contents GBinderBufferContents;
typedef struct gbinder_buffer_contents_list GBinderBufferContentsList;
typedef struct gbinder_cleanup GBinderCleanup;
typedef struct gbinder_driver GBinderDriver;
typedef struct gbinder_handler GBinderHandler;
typedef struct gbinder_io GBinderIo;
typedef struct gbinder_object_converter GBinderObjectConverter;
typedef struct gbinder_object_registry GBinderObjectRegistry;
typedef struct gbinder_output_data GBinderOutputData;
typedef struct gbinder_proxy_object GBinderProxyObject;
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;
typedef struct gbinder_servicepoll GBinderServicePoll;
typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
typedef struct gbinder_ipc_sync_api GBinderIpcSyncApi;
#define GBINDER_INLINE_FUNC static inline
#define GBINDER_INTERNAL G_GNUC_INTERNAL
@@ -70,6 +74,9 @@ typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
#define HIDL_DEBUG_TRANSACTION HIDL_FOURCC('D','B','G')
#define HIDL_HASH_CHAIN_TRANSACTION HIDL_FOURCC('H','S','H')
/* As a special case, ServiceManager's handle is zero */
#define GBINDER_SERVICEMANAGER_HANDLE (0)
#endif /* GBINDER_TYPES_PRIVATE_H */
/*

View File

@@ -1,8 +1,8 @@
/*
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2024 Jolla Ltd.
* Copyright (C) 2018-2024 Slava Monich <slava@monich.com>
*
* You may use this file under the terms of BSD license as follows:
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,12 +32,16 @@
#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"
#include "gbinder_log.h"
#include <gutil_intarray.h>
#include <gutil_macros.h>
#include <gutil_strv.h>
#include <gutil_misc.h>
#include <unistd.h>
#include <stdint.h>
@@ -48,6 +52,20 @@ typedef struct gbinder_writer_priv {
GBinderWriterData* data;
} GBinderWriterPriv;
const GBinderWriterType gbinder_writer_type_byte = { "byte", 1, NULL };
const GBinderWriterType gbinder_writer_type_int32 = { "int32", 4, 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)
@@ -55,52 +73,90 @@ GBINDER_INLINE_FUNC GBinderWriterPriv* gbinder_writer_cast(GBinderWriter* pub)
GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub)
{ return G_LIKELY(pub) ? gbinder_writer_cast(pub)->data : NULL; }
static
void
gbinder_writer_data_buffer_cleanup(
gpointer data)
{
gbinder_buffer_contents_unref((GBinderBufferContents*)data);
}
void
gbinder_writer_data_set_contents(
GBinderWriterData* data,
GBinderBuffer* buffer)
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
{
gsize bufsize;
const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize);
const GBinderIo* io = gbinder_buffer_io(buffer);
GBinderBufferContents* contents = gbinder_buffer_contents(buffer);
GASSERT(data->io == io);
g_byte_array_set_size(data->bytes, 0);
gutil_int_array_set_count(data->offsets, 0);
data->buffers_size = 0;
gbinder_cleanup_reset(data->cleanup);
gbinder_writer_data_append_contents(data, buffer, 0, convert);
}
void
gbinder_writer_data_append_contents(
GBinderWriterData* data,
GBinderBuffer* buffer,
gsize off,
GBinderObjectConverter* convert)
{
GBinderBufferContents* contents = gbinder_buffer_contents(buffer);
g_byte_array_append(data->bytes, bufdata, bufsize);
if (contents) {
gsize bufsize;
GByteArray* dest = data->bytes;
const guint8* bufdata = gbinder_buffer_data(buffer, &bufsize);
void** objects = gbinder_buffer_objects(buffer);
data->cleanup = gbinder_cleanup_add(data->cleanup,
gbinder_writer_data_buffer_cleanup,
data->cleanup = gbinder_cleanup_add(data->cleanup, (GDestroyNotify)
gbinder_buffer_contents_unref,
gbinder_buffer_contents_ref(contents));
if (objects && *objects) {
const GBinderIo* io = gbinder_buffer_io(buffer);
const GBinderRpcProtocol* proto = gbinder_buffer_protocol(buffer);
/* GBinderIo must be the same because it's defined by the kernel */
GASSERT(io == data->io);
if (!data->offsets) {
data->offsets = gutil_int_array_new();
}
while (*objects) {
const guint8* obj = *objects++;
gsize offset = obj - bufdata;
gsize objsize = io->object_data_size(obj);
gsize objsize, offset = obj - bufdata;
GBinderLocalObject* local;
guint32 handle;
GASSERT(offset >= off && offset < bufsize);
if (offset > off) {
/* Copy serialized data preceeding this object */
g_byte_array_append(dest, bufdata + off, offset - off);
off = offset;
}
/* Offset in the destination buffer */
gutil_int_array_append(data->offsets, dest->len);
/* Convert remote object into local if necessary */
if (convert && io->decode_binder_handle(obj, &handle, 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, 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, proto);
g_byte_array_append(dest, obj, objsize);
}
GASSERT(offset > 0 && offset < bufsize);
gutil_int_array_append(data->offsets, (int)offset);
/* Size of each buffer has to be 8-byte aligned */
data->buffers_size += G_ALIGN8(objsize);
data->buffers_size += G_ALIGN8(io->object_data_size(obj));
off += objsize;
}
}
if (off < bufsize) {
/* Copy remaining data */
g_byte_array_append(dest, bufdata + off, bufsize - off);
}
}
}
@@ -116,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,
@@ -149,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
@@ -174,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
@@ -430,37 +523,37 @@ gbinder_writer_data_append_string16_len(
gsize padded_len = G_ALIGN4((len+1)*2);
guint32* len_ptr;
gunichar2* utf16_ptr;
gunichar2* utf16 = NULL;
/* Create utf-16 string to make sure of its size */
if (len > 0) {
glong utf16_len = 0;
utf16 = g_utf8_to_utf16(utf8, num_bytes, NULL, &utf16_len, NULL);
if (utf16) {
len = utf16_len;
padded_len = G_ALIGN4((len+1)*2);
}
}
/* Preallocate space */
g_byte_array_set_size(buf, old_size + padded_len + 4);
len_ptr = (guint32*)(buf->data + old_size);
utf16_ptr = (gunichar2*)(len_ptr + 1);
/* TODO: this could be optimized for ASCII strings, i.e. if
* len equals num_bytes */
if (len > 0) {
glong utf16_len = 0;
gunichar2* utf16 = g_utf8_to_utf16(utf8, num_bytes, NULL,
&utf16_len, NULL);
if (utf16) {
len = utf16_len;
padded_len = G_ALIGN4((len+1)*2);
memcpy(utf16_ptr, utf16, (len+1)*2);
g_free(utf16);
}
/* Copy string */
if (utf16) {
memcpy(utf16_ptr, utf16, len*2);
g_free(utf16);
}
/* Actual length */
*len_ptr = len;
/* Zero padding */
if (padded_len - (len + 1)*2) {
memset(utf16_ptr + (len + 1), 0, padded_len - (len + 1)*2);
if (padded_len > len*2) {
memset(utf16_ptr + len, 0, padded_len - len*2);
}
/* Correct the packet size if necessaary */
g_byte_array_set_size(buf, old_size + padded_len + 4);
} else if (utf8) {
/* Empty string */
gbinder_writer_data_append_string16_empty(data);
@@ -542,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(
@@ -565,7 +647,6 @@ gbinder_writer_data_close_fd(
}
}
static
void
gbinder_writer_data_append_fd(
GBinderWriterData* data,
@@ -607,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,
@@ -636,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,
@@ -643,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,
@@ -661,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,
@@ -671,11 +997,7 @@ gbinder_writer_data_append_hidl_vec(
GBinderParent vec_parent;
GBinderHidlVec* vec = g_new0(GBinderHidlVec, 1);
const gsize total = count * elemsize;
void* buf = g_memdup(base, total);
/* Prepare parent descriptor for the string data */
vec_parent.index = gbinder_writer_data_prepare(data);
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
void* buf = gutil_memdup(base, total);
/* Fill in the vector descriptor */
if (buf) {
@@ -687,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
@@ -714,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;
@@ -725,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);
}
}
@@ -768,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);
@@ -794,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;
@@ -803,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 */
@@ -811,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,
@@ -819,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);
}
}
@@ -853,11 +1173,14 @@ 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 */
gbinder_writer_data_record_offset(data, offset);
if (obj) {
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
}
}
void
@@ -883,25 +1206,96 @@ gbinder_writer_append_byte_array(
GASSERT(len >= 0);
if (G_LIKELY(data)) {
GByteArray* buf = data->bytes;
void* ptr;
gsize padded_len;
guint8* ptr;
if (!byte_array) {
len = 0;
}
g_byte_array_set_size(buf, buf->len + sizeof(len) + len);
ptr = buf->data + (buf->len - sizeof(len) - len);
/*
* Android aligns byte array reads and writes to 4 bytes and
* pads with 0xFF.
*/
padded_len = G_ALIGN4(len);
g_byte_array_set_size(buf, buf->len + sizeof(len) + padded_len);
ptr = buf->data + (buf->len - sizeof(len) - padded_len);
if (len > 0) {
*((gint32*)ptr) = len;
ptr += sizeof(len);
memcpy(ptr, byte_array, len);
/* FF padding */
if (padded_len > len) {
memset(ptr + len, 0xff, padded_len - len);
}
} else {
*((gint32*)ptr) = -1;
}
}
}
#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,
@@ -917,8 +1311,11 @@ gbinder_writer_data_append_remote_object(
n = data->io->encode_remote_object(buf->data + offset, obj);
/* Fix the data size */
g_byte_array_set_size(buf, offset + n);
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
if (obj) {
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
}
}
static
@@ -956,6 +1353,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-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:
*
@@ -39,6 +39,7 @@
typedef struct gbinder_writer_data {
const GBinderIo* io;
const GBinderRpcProtocol* protocol;
GByteArray* bytes;
GUtilIntArray* offsets;
gsize buffers_size;
@@ -54,7 +55,16 @@ gbinder_writer_init(
void
gbinder_writer_data_set_contents(
GBinderWriterData* data,
GBinderBuffer* buffer)
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_contents(
GBinderWriterData* data,
GBinderBuffer* buffer,
gsize data_offset,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
void
@@ -121,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,
@@ -154,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

@@ -2,9 +2,11 @@
all:
%:
@$(MAKE) -C binder-bridge $*
@$(MAKE) -C binder-client $*
@$(MAKE) -C binder-dump $*
@$(MAKE) -C binder-list $*
@$(MAKE) -C binder-ping $*
@$(MAKE) -C binder-service $*
@$(MAKE) -C binder-call $*
@$(MAKE) -C rild-card-status $*

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

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

View File

@@ -0,0 +1,196 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gbinder.h>
#include <gutil_log.h>
#include <glib-unix.h>
#define RET_OK (0)
#define RET_NODEV (1)
#define RET_INVARG (2)
typedef struct app_options {
const char* src;
const char* dest;
char* src_name;
const char* dest_name;
const char** ifaces;
} AppOptions;
static
gboolean
app_signal(
gpointer loop)
{
GINFO("Caught signal, shutting down...");
g_main_loop_quit(loop);
return G_SOURCE_CONTINUE;
}
static
int
app_run(
const AppOptions* opt)
{
int ret = RET_NODEV;
GBinderServiceManager* src = gbinder_servicemanager_new(opt->src);
if (src) {
GBinderServiceManager* dest = gbinder_servicemanager_new(opt->dest);
if (dest) {
GMainLoop* loop = g_main_loop_new(NULL, TRUE);
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, loop);
guint sigint = g_unix_signal_add(SIGINT, app_signal, loop);
GBinderBridge* bridge = gbinder_bridge_new2
(opt->src_name, opt->dest_name, opt->ifaces, src, dest);
g_main_loop_run(loop);
if (sigtrm) g_source_remove(sigtrm);
if (sigint) g_source_remove(sigint);
g_main_loop_unref(loop);
gbinder_bridge_free(bridge);
gbinder_servicemanager_unref(dest);
ret = RET_OK;
} else {
GERR("No servicemanager at %s", opt->dest);
}
gbinder_servicemanager_unref(src);
} else {
GERR("No servicemanager at %s", opt->src);
}
return ret;
}
static
gboolean
app_log_verbose(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
gutil_log_default.level = GLOG_LEVEL_VERBOSE;
return TRUE;
}
static
gboolean
app_log_quiet(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
gutil_log_default.level = GLOG_LEVEL_NONE;
return TRUE;
}
static
gboolean
app_init(
AppOptions* opt,
int argc,
char* argv[])
{
gboolean ok = FALSE;
GOptionEntry entries[] = {
{ "source", 's', 0, G_OPTION_ARG_STRING, &opt->src_name,
"Register a different name on source", "NAME" },
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_verbose, "Enable verbose output", NULL },
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_quiet, "Be quiet", NULL },
{ NULL }
};
GError* error = NULL;
GOptionContext* options = g_option_context_new("SRC DST NAME IFACES...");
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
g_option_context_add_main_entries(options, entries, NULL);
g_option_context_set_summary(options,
"Forwards calls from device SRC to device DST.");
if (g_option_context_parse(options, &argc, &argv, &error)) {
if (argc >= 5) {
int i;
const int first_iface = 4;
opt->src = argv[1];
opt->dest = argv[2];
opt->dest_name = argv[3];
opt->ifaces = g_new(const char*, argc - first_iface + 1);
for (i = first_iface; i < argc; i++) {
opt->ifaces[i - first_iface] = argv[i];
}
opt->ifaces[i - first_iface] = NULL;
ok = TRUE;
} else {
char* help = g_option_context_get_help(options, TRUE, NULL);
fprintf(stderr, "%s", help);
g_free(help);
}
} else {
GERR("%s", error->message);
g_error_free(error);
}
g_option_context_free(options);
return ok;
}
int main(int argc, char* argv[])
{
AppOptions opt;
int ret = RET_INVARG;
memset(&opt, 0, sizeof(opt));
if (app_init(&opt, argc, argv)) {
ret = app_run(&opt);
}
g_free(opt.src_name);
g_free(opt.ifaces);
return ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

180
test/binder-call/Makefile Normal file
View File

@@ -0,0 +1,180 @@
# -*- Mode: makefile-gmake -*-
.PHONY: all debug release install clean cleaner
.PHONY: libgbinder-release libgbinder-debug
#
# Required packages
#
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
#
# Default target
#
all: debug release
#
# Executable
#
EXE = binder-call
#
# Sources
#
SRC = $(EXE).c
GEN_SRC = \
cmdline.tab.c \
lex.cmdline.c
#
# Directories
#
SRC_DIR = .
BUILD_DIR = build
GEN_DIR = $(BUILD_DIR)
LIB_DIR = ../..
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
#
# Tools and flags
#
PKG_CONFIG ?= pkg-config
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
DEFINES += -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_32 \
-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_MAX_ALLOWED
INCLUDES = -I$(LIB_DIR)/include -I$(GEN_DIR) -I$(SRC_DIR)
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 = \
$(GEN_SRC:%.c=$(DEBUG_BUILD_DIR)/%.o) \
$(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = \
$(GEN_SRC:%.c=$(RELEASE_BUILD_DIR)/%.o) \
$(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
GEN_FILES = $(GEN_SRC:%=$(GEN_DIR)/%)
.PRECIOUS: $(GEN_FILES)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(GEN_FILES): | $(GEN_DIR)
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
#
# Rules
#
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
debug: libgbinder-debug $(DEBUG_EXE)
release: libgbinder-release $(RELEASE_EXE)
clean:
rm -f *~
rm -fr $(BUILD_DIR)
cleaner: clean
@$(MAKE) -C $(LIB_DIR) clean
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(GEN_DIR):
mkdir -p $@
$(GEN_DIR)/%.tab.c : $(SRC_DIR)/%.y
bison -pcmdline -bcmdline -d -o $@ $<
$(GEN_DIR)/lex.%.c : $(SRC_DIR)/%.l
flex -o $@ $<
$(DEBUG_BUILD_DIR)/%.o : $(GEN_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(RELEASE_BUILD_DIR)/%.o : $(GEN_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
ifeq ($(KEEP_SYMBOLS),0)
strip $@
endif
libgbinder-debug:
@$(MAKE) $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
libgbinder-release:
@$(MAKE) $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)
#
# Install
#
INSTALL = install
INSTALL_BIN_DIR = $(DESTDIR)/usr/bin
install: release $(INSTALL_BIN_DIR)
$(INSTALL) -m 755 $(RELEASE_EXE) $(INSTALL_BIN_DIR)
$(INSTALL_BIN_DIR):
$(INSTALL) -d $@

View File

@@ -0,0 +1,844 @@
/*
* 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:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gbinder.h>
#include <gutil_log.h>
#include <unistd.h>
#include <binder-call.h>
#include <stdlib.h>
#define RET_OK (0)
#define RET_NOTFOUND (1)
#define RET_INVARG (2)
#define RET_ERR (3)
#define DEFAULT_DEVICE GBINDER_DEFAULT_BINDER
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
#define GBINDER_INTERFACE_TRANSACTION GBINDER_TRANSACTION('N','T','F')
static const char pname[] = "binder-call";
struct transaction_and_reply* ast;
enum transaction_pass {
COMPUTE_SIZES = 0,
FILL_BUFFERS,
BUILD_TRANSACTION
};
enum reply_pass {
PRINT_REPLY = 0,
COMPUTE_SIZES_REPLY
};
static
int
go_through_transaction_ast(
App* app,
GList* node_list,
int parent_idx,
void* buf,
enum transaction_pass cur_pass,
int cont_offset)
{
GList* l;
int offset = cont_offset;
for (l = node_list; l; l = l->next) {
struct value_info* v = l->data;
switch(v->type) {
case INT8_TYPE:
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("int8 %u", (guint)(*((guint8*)v->value)));
}
if (parent_idx == -1) {
gbinder_writer_append_int8(&app->writer, *((guint8*)v->value));
} else if (cur_pass == FILL_BUFFERS) {
*((unsigned char*)(((char*)buf)+offset)) =
*((unsigned char*)v->value);
}
offset++;
break;
case INT32_TYPE:
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("int32 %d", *((int*)v->value));
}
if (parent_idx == -1) {
gbinder_writer_append_int32(&app->writer, *((int*)v->value));
} else if (cur_pass == FILL_BUFFERS) {
*((int*)(((char*)buf)+offset)) = *((int*)v->value);
}
offset += sizeof(gint32);
break;
case INT64_TYPE:
if (cur_pass == BUILD_TRANSACTION) {
GDEBUG("int64 %" 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) {
*((gint64*)(((char*)buf)+offset)) = *((gint64*)v->value);
}
offset += sizeof(gint64);
break;
case FLOAT_TYPE:
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) {
*((float*)(((char*)buf)+offset)) = *((float*)v->value);
}
offset += sizeof(float);
break;
case DOUBLE_TYPE:
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) {
*((double*)(((char*)buf)+offset)) = *((double*)v->value);
}
offset += sizeof(double);
break;
case STRING8_TYPE:
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;
case STRING16_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("string16");
gbinder_writer_append_string16(&app->writer, v->value);
/* offset not incremented since it only makes sense for hidl */
break;
case HSTRING_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("hstring");
if (parent_idx == -1) {
gbinder_writer_append_hidl_string(&app->writer, v->value);
} else {
GBinderHidlString* hidl_str = (GBinderHidlString*)
(((char*)buf)+offset);
if (cur_pass == FILL_BUFFERS) {
hidl_str->data.str = v->value;
hidl_str->len = strlen(v->value);
hidl_str->owns_buffer = TRUE;
} else if (cur_pass == BUILD_TRANSACTION) {
GBinderParent p;
p.index = parent_idx;
p.offset = offset;
gbinder_writer_append_buffer_object_with_parent
(&app->writer, hidl_str->data.str, hidl_str->len+1, &p);
}
}
offset += sizeof(GBinderHidlString);
break;
case STRUCT_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("struct");
if (!app->opt->aidl) {
if (parent_idx == -1) {
int s = go_through_transaction_ast(app, v->value, 0,
NULL, COMPUTE_SIZES, 0);
void* new_buf = gbinder_writer_malloc(&app->writer, s);
int new_parent_idx;
go_through_transaction_ast(app, v->value, 0, new_buf,
FILL_BUFFERS, 0);
new_parent_idx = gbinder_writer_append_buffer_object
(&app->writer, new_buf, s);
/*
* if parent_idx == -1 there is no need to update the
* offset, since we are processing the argument list
* and are not inside an argument.
*/
go_through_transaction_ast(app, v->value,
new_parent_idx, new_buf, BUILD_TRANSACTION, 0);
} else {
if (cur_pass == FILL_BUFFERS) {
/* fill struct mode */
offset += go_through_transaction_ast(app,
v->value, 0, ((char*)buf)+offset, cur_pass, 0);
} else if (cur_pass == BUILD_TRANSACTION) {
int s = go_through_transaction_ast(app,
v->value, 0, NULL, COMPUTE_SIZES, 0);
go_through_transaction_ast(app, v->value, 0,
buf, FILL_BUFFERS, offset);
go_through_transaction_ast(app, v->value, parent_idx,
buf, BUILD_TRANSACTION, offset);
offset += s;
} else if (cur_pass == COMPUTE_SIZES) {
offset += go_through_transaction_ast(app,
v->value, 0, NULL, cur_pass, 0);
}
}
} else {
go_through_transaction_ast(app, v->value, -1, NULL,
cur_pass, 0);
}
if (cur_pass == BUILD_TRANSACTION) GDEBUG("structend");
break;
case VECTOR_TYPE:
if (cur_pass == BUILD_TRANSACTION) GDEBUG("vector");
if (!app->opt->aidl) {
if (parent_idx == -1) {
GBinderHidlVec* vec;
int vs = go_through_transaction_ast(app,
v->value, 0, NULL, COMPUTE_SIZES, 0);
int es = go_through_transaction_ast(app,
g_list_last(v->value), 0, NULL, COMPUTE_SIZES, 0);
void* new_buf = gbinder_writer_malloc(&app->writer, vs);
int new_parent_idx;
GBinderParent vec_parent;
go_through_transaction_ast(app, v->value, 0, new_buf,
FILL_BUFFERS, 0);
vec = gbinder_writer_new0(&app->writer, GBinderHidlVec);
vec->data.ptr = new_buf;
vec->count = vs / es;
if (vec->count != g_list_length(v->value)) {
GERR("SEMANTIC ERROR VECTOR");
abort();
}
vec_parent.index = gbinder_writer_append_buffer_object
(&app->writer, vec, sizeof(*vec));
vec_parent.offset = GBINDER_HIDL_VEC_BUFFER_OFFSET;
new_parent_idx =
gbinder_writer_append_buffer_object_with_parent
(&app->writer, new_buf, vs, &vec_parent);
go_through_transaction_ast(app, v->value,
new_parent_idx, new_buf, BUILD_TRANSACTION, 0);
} else {
if (cur_pass == FILL_BUFFERS) {
/* fill struct mode */
int sl = go_through_transaction_ast(app,
v->value, 0, NULL, COMPUTE_SIZES, 0);
int es = go_through_transaction_ast(app,
g_list_last(v->value), 0, NULL, COMPUTE_SIZES, 0);
void* new_buf = gbinder_writer_malloc(&app->writer, sl);
GBinderHidlVec* vec = (GBinderHidlVec*)
(((char*)buf)+offset);
vec->data.ptr = new_buf;
vec->count = sl / es;
} else if (cur_pass == BUILD_TRANSACTION) {
int new_parent_idx;
int sl = go_through_transaction_ast(app,
v->value, 0, NULL, COMPUTE_SIZES, 0);
GBinderHidlVec* vec = (GBinderHidlVec*)
(((char*)buf)+offset);
GBinderParent p;
void* new_buf = (void*)vec->data.ptr;
go_through_transaction_ast(app, v->value, 0,
new_buf, FILL_BUFFERS, 0);
if (vec->count != g_list_length(v->value)) {
GERR("SEMANTIC ERROR VECTOR");
abort();
}
p.index = parent_idx;
p.offset = offset;
new_parent_idx =
gbinder_writer_append_buffer_object_with_parent
(&app->writer, new_buf, sl, &p);
go_through_transaction_ast(app, v->value,
new_parent_idx, new_buf, BUILD_TRANSACTION, 0);
}
offset += sizeof(GBinderHidlVec);
}
} else {
int vl = g_list_length(v->value);
gbinder_writer_append_int32(&app->writer, vl);
go_through_transaction_ast(app, v->value, -1, NULL,
cur_pass, 0);
}
if (cur_pass == BUILD_TRANSACTION) GDEBUG("vectorend");
break;
default:
GERR("unknown type: %d\n", v->type);
break;
}
}
return offset;
}
static
int
go_through_reply_ast(
App* app,
GList* node_list,
struct type_info* tt,
const void* buf,
enum reply_pass cur_pass)
{
GList* l;
int offset = 0;
for (l = node_list; l || tt; l = l->next) {
struct type_info* t = node_list ? l->data : tt;
switch(t->type) {
case INT8_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("int8");
if (cur_pass != COMPUTE_SIZES_REPLY) {
int val;
if (!buf) {
gbinder_reader_read_int32(&app->reader, &val);
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
val = *((unsigned char*)(((char*)buf)+offset));
}
printf("%d:8 ", val);
}
offset += 1;
break;
case INT32_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("int32");
if (cur_pass != COMPUTE_SIZES_REPLY) {
gint32 val;
if (!buf) {
gbinder_reader_read_int32(&app->reader, &val);
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
val = *((gint32*)(((char*)buf)+offset));
}
printf("%" G_GINT32_FORMAT " ", val);
}
offset += sizeof(gint32);
break;
case INT64_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("int64");
if (cur_pass != COMPUTE_SIZES_REPLY) {
gint64 val;
if (!buf) {
gbinder_reader_read_int64(&app->reader, &val);
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
val = *((gint64*)(((char*)buf)+offset));
}
printf("%" G_GINT64_FORMAT " ", val);
}
offset += sizeof(gint64);
break;
case FLOAT_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("float");
if (cur_pass != COMPUTE_SIZES_REPLY) {
float val;
if (!buf) {
gbinder_reader_read_float(&app->reader, &val);
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
val = *((float*)(((char*)buf)+offset));
}
printf("%f ", val);
}
offset += sizeof(float);
break;
case DOUBLE_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("double");
if (cur_pass != COMPUTE_SIZES_REPLY) {
double val;
if (!buf) {
gbinder_reader_read_double(&app->reader, &val);
} else if (cur_pass != COMPUTE_SIZES_REPLY) {
val = *((double*)(((char*)buf)+offset));
}
printf("%lfL ", val);
}
offset += sizeof(double);
break;
case STRING8_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("string8");
printf("\"%s\" ", gbinder_reader_read_string8(&app->reader));
/* offset not incremented since it only makes sense for hidl */
break;
case STRING16_TYPE: {
char* val = gbinder_reader_read_string16(&app->reader);
if (cur_pass == PRINT_REPLY) GDEBUG("string16");
printf("\"%s\"U ", val);
g_free(val);
/* offset not incremented since it only makes sense for hidl */
break;
}
case HSTRING_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("hstring");
if (cur_pass != COMPUTE_SIZES_REPLY) {
char* val = NULL;
if (!buf) {
val = gbinder_reader_read_hidl_string(&app->reader);
} else {
GBinderHidlString* hidl_str = (GBinderHidlString*)
(((char*)buf)+offset);
val = strdup(hidl_str->data.str);
}
printf("\"%s\"H ", val);
g_free(val);
}
offset += sizeof(GBinderHidlString);
break;
case STRUCT_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("struct");
if (!app->opt->aidl) {
if (cur_pass == COMPUTE_SIZES_REPLY) {
offset += go_through_reply_ast(app, t->data, NULL, NULL,
COMPUTE_SIZES_REPLY);
} else {
printf("{ ");
if (!buf) {
int sl = go_through_reply_ast(app, t->data, NULL, NULL,
COMPUTE_SIZES_REPLY);
offset += go_through_reply_ast(app, t->data, NULL,
gbinder_reader_read_hidl_struct1(&app->reader, sl),
PRINT_REPLY);
} else {
offset += go_through_reply_ast(app, t->data, NULL,
((char*)buf) + offset, PRINT_REPLY);
}
printf("} ");
}
} else {
go_through_reply_ast(app, t->data, NULL, NULL, cur_pass);
}
if (cur_pass == PRINT_REPLY) GDEBUG("structend");
break;
case VECTOR_TYPE:
if (cur_pass == PRINT_REPLY) GDEBUG("vector");
if (!app->opt->aidl) {
if (cur_pass != COMPUTE_SIZES_REPLY) {
if (!buf) {
guint i;
gsize count, elemsize;
const void* new_buf = gbinder_reader_read_hidl_vec
(&app->reader, &count, &elemsize);
printf("[ ");
for (i = 0; i < count; i++) {
/* TODO: validate elemsize somehow? */
go_through_reply_ast(app, NULL, t->data,
new_buf + elemsize*i, cur_pass);
}
printf("] ");
} else {
guint i;
gsize count;
GBinderHidlVec* vec = (GBinderHidlVec*)
(((char*)buf) + offset);
int off;
count = vec->count;
printf("[ ");
off = 0;
for (i = 0; i < count; i++) {
off += go_through_reply_ast(app, NULL, t->data,
vec->data.ptr + off, cur_pass);
}
printf("] ");
}
}
offset += sizeof(GBinderHidlVec);
} else {
guint i;
gint32 vl;
gbinder_reader_read_int32(&app->reader, &vl);
printf("[ ");
for (i = 0; i < vl; i++) {
go_through_reply_ast(app, NULL, t->data, NULL, cur_pass);
}
printf("] ");
}
if (cur_pass == PRINT_REPLY) GDEBUG("vectorend");
break;
default:
GERR("unknown type: %d\n", t->type);
break;
}
if (tt) break;
}
return offset;
}
static
void
go_through_ast(
App* app,
struct transaction_and_reply* ast,
gboolean transaction)
{
if (ast) {
if (transaction && ast->tree_transaction) {
go_through_transaction_ast(app, ast->tree_transaction, -1, NULL,
BUILD_TRANSACTION, 0);
} else if (!transaction && ast->tree_reply) {
GDEBUG("REPLY:");
go_through_reply_ast(app, ast->tree_reply, NULL, NULL, PRINT_REPLY);
printf("\n");
}
}
}
static
void
free_ast_transaction_tree(
gpointer data)
{
struct value_info* v = data;
if (v->type == STRUCT_TYPE || v->type == VECTOR_TYPE) {
g_list_free_full(v->value, free_ast_transaction_tree);
} else {
g_free(v->value);
}
g_free(v);
}
static
void
free_ast_reply_tree(
gpointer data)
{
struct type_info* t = data;
if (t->type == VECTOR_TYPE) {
free_ast_reply_tree(t->data);
} else if (t->type == STRUCT_TYPE) {
g_list_free_full(t->data, free_ast_reply_tree);
}
g_free(t);
}
static
void
free_ast(
struct transaction_and_reply* ast)
{
if (ast) {
g_list_free_full(ast->tree_transaction, free_ast_transaction_tree);
g_list_free_full(ast->tree_reply, free_ast_reply_tree);
g_free(ast);
}
}
static
void
app_run(
App* app)
{
const AppOptions* opt = app->opt;
char* iface;
int status = 0;
int rargc = 1;
char* service = opt->argv[rargc++];
int code = atoi(opt->argv[rargc++]);
GBinderClient* client;
GBinderLocalRequest* req;
GBinderRemoteReply* reply;
GBinderRemoteObject* obj;
if (!code) {
GERR("Transaction code must be > GBINDER_FIRST_CALL_TRANSACTION(=1).");
return;
}
obj = gbinder_servicemanager_get_service_sync(app->sm,
service, &status);
if (!obj) {
GERR("No such service: %s", service);
return;
}
if (strstr(service, "/") != NULL) {
iface = g_strndup(service, strchr(service, '/') - service);
} else {
GBinderReader reader;
client = gbinder_client_new(obj, NULL);
req = gbinder_client_new_request(client);
reply = gbinder_client_transact_sync_reply(client,
GBINDER_INTERFACE_TRANSACTION, req, &status);
gbinder_remote_reply_init_reader(reply, &reader);
iface = gbinder_reader_read_string16(&reader);
gbinder_local_request_unref(req);
gbinder_remote_reply_unref(reply);
gbinder_client_unref(client);
}
if (!iface) {
GERR("Failed to get interface");
return;
}
GDEBUG("Got iface: %s", iface);
client = gbinder_client_new(obj, iface);
g_free(iface);
req = gbinder_client_new_request(client);
app->rargc = rargc;
app->code = code;
cmdline_parse(app);
gbinder_local_request_init_writer(req, &app->writer);
go_through_ast(app, ast, TRUE);
if (opt->oneway) {
gbinder_client_transact_sync_oneway(client, code, req);
reply = NULL;
} else {
reply = gbinder_client_transact_sync_reply(client, code, req, &status);
}
gbinder_local_request_unref(req);
if (!reply) {
printf("NO REPLY\n");
} else {
if (ast && !ast->tree_reply) {
guchar b;
gbinder_remote_reply_init_reader(reply, &app->reader);
printf("TRANSACTION BUFFER: 0x");
while (gbinder_reader_read_byte(&app->reader, &b)) {
printf("%02X", b);
}
printf("\n");
} else {
gbinder_remote_reply_init_reader(reply, &app->reader);
go_through_ast(app, ast, FALSE);
}
gbinder_remote_reply_unref(reply);
}
gbinder_client_unref(client);
free_ast(ast);
}
static
gboolean
app_log_verbose(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
gutil_log_default.level = (gutil_log_default.level < GLOG_LEVEL_DEBUG) ?
GLOG_LEVEL_DEBUG : GLOG_LEVEL_VERBOSE;
return TRUE;
}
static
gboolean
app_log_quiet(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
gutil_log_default.level = GLOG_LEVEL_ERR;
return TRUE;
}
static
gboolean
app_init(
AppOptions* opt,
int argc,
char* argv[])
{
gboolean ok = FALSE;
GOptionEntry entries[] = {
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_verbose, "Enable verbose output", NULL },
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_quiet, "Be quiet", NULL },
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
"Binder device [" DEFAULT_DEVICE "]", "DEVICE" },
{ "oneway", 'o', 0, G_OPTION_ARG_NONE, &opt->oneway,
"Use a oneway transaction", NULL },
{ "aidl", 'a', 0, G_OPTION_ARG_NONE, &opt->aidl,
"Treat types as aidl types (default: hidl)", NULL },
{ NULL }
};
GError* error = NULL;
GOptionContext* options = g_option_context_new("NAME CODE [[VALUE1] [VALUE2] ...] [reply [TYPE1] [TYPE2] ...]");
g_option_context_set_description(options,
"Performs binder transactions from the command line.\n\n"
"NAME is the name of the object to call, registered with servicemanager.\n"
"For example \"android.hardware.sensors@1.0::ISensors/default\".\n\n"
"CODE is the transaction id (must be >=1).\n\n"
"Optional transaction arguments follow the transaction code.\n"
"Possible arguments are:\n\n"
"\t[0-9]*:8 for an 8-bit integer\n"
"\t[0-9]* for a 32-bit integer\n"
"\t[0-9]*L for an 64-bit integer\n"
"\t[0-9]*.[0-9]* for a 32-bit float\n"
"\t[0-9]*.[0-9]*L for a 64-bit double\n"
"\t\"[.*]\" for an 8-bit aidl string\n"
"\t\"[.*]\"u for an utf16 aidl string\n"
"\t\"[.*]\"h for an 8-bit hidl string\n"
"\t{ VALUE1 VALUE2 ... VALUEN } for a struct containing VALUE1, VALUE2, etc., where\n"
"\t all of these values can be any of the possible values described here.\n"
"\t[ VALUE1 VALUE2 ... VALUEN ] for a vector of length N containing VALUE1, VALUE2, etc., where\n"
"\t all of these values can be one of the possible VALUES described here.\n"
"\t They must be of the same type.\n\n"
"The structure of the reply follows the \"reply\" keyword.\n"
"The following types are accepted:\n\n"
"\ti8 for an 8-bit integer\n"
"\ti32 for a 32-bit integer\n"
"\ti64 for a 64-bit integer\n"
"\ts8 for an 8-bit aidl string\n"
"\ts16 for an utf16 aidl string\n"
"\thstr for an 8-bit hidl string\n"
"\tf|float for a 32-bit float\n"
"\td|double for a 64-bit double\n"
"\t[ TYPE ] for a vector<TYPE> where TYPE can be any of the possible types decribed here\n"
"\t{ TYPE1 TYPE2 ... TYPEN } for a struct containing TYPE1, TYPE2, etc. where\n"
"\t all of the types can be any of the possible types decribed here.\n\n"
"The following example calls getSensorsList method on \"android.hardware.sensors@1.0::ISensors/default\"\n"
"service:\n\n"
"\tbinder-call -d /dev/hwbinder android.hardware.sensors@1.0::ISensors/default 1 reply i32 \"[ { i32 i32 hstr hstr i32 i32 hstr f f f i32 i32 i32 hstr i32 i32 } ]\"\n");
g_option_context_add_main_entries(options, entries, NULL);
memset(opt, 0, sizeof(*opt));
gutil_log_timestamp = FALSE;
gutil_log_set_type(GLOG_TYPE_STDERR, pname);
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
if (g_option_context_parse(options, &argc, &argv, &error)) {
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 {
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[])
{
App app;
AppOptions opt;
memset(&app, 0, sizeof(app));
app.ret = RET_INVARG;
app.opt = &opt;
if (app_init(&opt, argc, argv)) {
app.sm = gbinder_servicemanager_new(opt.dev);
if (app.sm) {
app_run(&app);
gbinder_servicemanager_unref(app.sm);
} else {
GERR("servicemanager seems to be missing");
}
}
g_free(opt.dev);
return app.ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2021-2022 Jolla Ltd.
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BINDER_CALL_H__
#define BINDER_CALL_H__
#include <gbinder.h>
typedef struct app_options {
char* dev;
gboolean oneway;
gboolean aidl;
gint transaction;
int argc;
char** argv;
} AppOptions;
typedef struct app {
const AppOptions* opt;
GMainLoop* loop;
GBinderServiceManager* sm;
GBinderWriter writer;
GBinderReader reader;
int code;
int rargc;
int ret;
} App;
enum TYPE_INFO {
INT8_TYPE = 0,
INT32_TYPE,
INT64_TYPE,
FLOAT_TYPE,
DOUBLE_TYPE,
STRING8_TYPE,
STRING16_TYPE,
HSTRING_TYPE,
STRUCT_TYPE,
VECTOR_TYPE
};
struct type_info {
enum TYPE_INFO type;
void* data;
};
struct value_info {
enum TYPE_INFO type;
void* value;
};
struct transaction_and_reply {
GList* tree_transaction;
GList* tree_reply;
};
int
cmdline_parse(
App* app);
int
cmdlinelex(
void* args);
extern struct transaction_and_reply* ast;
#endif

View File

@@ -0,0 +1,98 @@
D [0-9]
l "l"
L "L"
u "u"
U "U"
h "h"
H "H"
COLON ":"
EIGHT "8"
INT8_SUFFIX {COLON}{EIGHT}
INT64_SUFFIX [lL]
UTF16_SUFFIX [uU]
HSTRING_SUFFIX [hH]
%{
#include <glib.h>
#include "cmdline.tab.h"
#include "binder-call.h"
#define YY_SKIP_YYWRAP
int cmdlinewrap(App* app);
#undef yywrap
#define yywrap() cmdlinewrap( (App*) args )
#define YY_DECL int cmdlinelex( void* args )
char* handle_str(char* text) {
// extract str from "str"X
char* str = g_strndup(text + 1, strlen(text) - 3);
return str;
}
char* handle_str8(char* text) {
// extract str from "str"
char* str = g_strndup(text + 1, strlen(text) - 2);
return str;
}
%}
%option never-interactive noinput nounput
%%
"i8" { return(INT8); }
"i32" { return(INT32); }
"i64" { return(INT64); }
"s8" { return(STRING8); }
"s16" { return(STRING16); }
"float" { return(FLOAT); }
"double" { return(DOUBLE); }
"f" { return(FLOAT); }
"d" { return(DOUBLE); }
"hstr" { return(HSTRING); }
"{" { return('{'); }
"}" { return('}'); }
"[" { return('['); }
"]" { return(']'); }
-?{D}+{INT8_SUFFIX} { cmdlinelval.int8_value = atoi(yytext); return(INT8_VALUE); }
-?{D}+{INT64_SUFFIX} { cmdlinelval.int64_value = atol(yytext); return(INT64_VALUE); }
-?{D}+ { cmdlinelval.int32_value = atoi(yytext); return(INT32_VALUE); }
-?{D}+"."{D}*{INT64_SUFFIX} { cmdlinelval.double_value = atof(yytext); return(DOUBLE_VALUE); }
-?{D}+"."{D}* { cmdlinelval.float_value = atof(yytext); return(FLOAT_VALUE); }
"reply" { return(REPLY); }
\".*\"{HSTRING_SUFFIX} { cmdlinelval.hstring_value = handle_str(yytext); return(HSTRING_VALUE); }
\".*\"{UTF16_SUFFIX} { cmdlinelval.string16_value = handle_str(yytext); return(STRING16_VALUE); }
\".*\" { cmdlinelval.string8_value = handle_str8(yytext); return(STRING8_VALUE); }
" " { /* eat */ }
. { fprintf(stderr, "Unrecognized character: '%c'\n", yytext[0]); }
%%
#include "binder-call.h"
int cmdlinewrap(App* app)
{
if (YY_CURRENT_BUFFER) {
yy_delete_buffer( YY_CURRENT_BUFFER );
}
if (app->rargc == app->opt->argc) {
return 1;
}
yy_scan_string(app->opt->argv[app->rargc++]);
return 0;
}
int cmdline_parse(App* app) {
if (app->opt->argc > app->rargc) {
cmdlinewrap(app);
} else {
return 1;
}
return cmdlineparse (app);
}

399
test/binder-call/cmdline.y Normal file
View File

@@ -0,0 +1,399 @@
%{
#include <glib.h>
#include "binder-call.h"
struct transaction_and_reply* make_transaction_and_reply(GList* transaction, GList* reply);
struct value_info* handle_int8(App* app, int value);
struct value_info* handle_int32(App* app, int value);
struct value_info* handle_int64(App* app, long value);
struct value_info* handle_float(App* app, float value);
struct value_info* handle_double(App* app, double value);
struct value_info* handle_string8(App* app, char* value);
struct value_info* handle_string16(App* app, char* value);
struct value_info* handle_hstring(App* app, char* value);
struct value_info* handle_vector(App* app, GList* values);
struct value_info* handle_struct(App* app, GList* values);
void cmdlineerror(App* app, char const* s);
struct type_info* handle_type_int8(App* app);
struct type_info* handle_type_int32(App* app);
struct type_info* handle_type_int64(App* app);
struct type_info* handle_type_float(App* app);
struct type_info* handle_type_double(App* app);
struct type_info* handle_type_string8(App* app);
struct type_info* handle_type_string16(App* app);
struct type_info* handle_type_hstring(App* app);
struct type_info* handle_type_vector(App* app, struct type_info* t);
struct type_info* handle_type_struct(App* app, GList* l);
%}
%union {
union {
int int8_value;
int int32_value;
long int64_value;
float float_value;
double double_value;
char* string8_value;
char* string16_value;
char* hstring_value;
};
struct value_info* value;
struct type_info* type;
GList* value_list;
GList* type_list;
GList* struct_type_list;
struct transaction_and_reply* trans_and_reply;
}
%parse-param { void* args }
%lex-param { void* args }
%token INT8 INT32 INT64 FLOAT DOUBLE STRING8 STRING16 HSTRING
%token INT8_VALUE INT32_VALUE INT64_VALUE FLOAT_VALUE DOUBLE_VALUE STRING8_VALUE STRING16_VALUE HSTRING_VALUE
%type <value> values
%type <value> struct_values
%type <value> vec_values
%type <value> value_specifiers
%type <trans_and_reply> translation_unit
%type <value_list> values_list
%type <type_list> specifiers_list
%type <type> specifiers
%type <type> type_specifier
%type <type> vec_specifier
%type <type> struct_specifier
%type <struct_type_list> struct_declaration_list
%token REPLY
%start translation_unit
%%
type_specifier
: INT8 { $$ = handle_type_int8(args); }
| INT32 { $$ = handle_type_int32(args); }
| INT64 { $$ = handle_type_int64(args); }
| STRING8 { $$ = handle_type_string8(args); }
| STRING16 { $$ = handle_type_string16(args); }
| FLOAT { $$ = handle_type_float(args); }
| DOUBLE { $$ = handle_type_double(args); }
| HSTRING { $$ = handle_type_hstring(args); }
;
values
: INT8_VALUE { $$ = handle_int8(args, cmdlinelval.int8_value); }
| INT32_VALUE { $$ = handle_int32(args, cmdlinelval.int32_value); }
| INT64_VALUE { $$ = handle_int64(args, cmdlinelval.int64_value); }
| STRING8_VALUE { $$ = handle_string8(args, cmdlinelval.string8_value); }
| STRING16_VALUE { $$ = handle_string16(args, cmdlinelval.string16_value); }
| HSTRING_VALUE { $$ = handle_hstring(args, cmdlinelval.hstring_value); }
| FLOAT_VALUE { $$ = handle_float(args, cmdlinelval.float_value); }
| DOUBLE_VALUE { $$ = handle_double(args, cmdlinelval.double_value); }
;
struct
: '{'
;
struct_end
: '}'
;
vec
: '['
;
vec_end
: ']'
;
struct_specifier
: struct struct_declaration_list struct_end { $$ = handle_type_struct(args, $2); }
;
vec_specifier
: vec specifiers vec_end { $$ = handle_type_vector(args, $2); }
;
struct_declaration_list
: specifiers { $$ = NULL; $$ = g_list_append($$, $1); }
| struct_declaration_list specifiers { $$ = g_list_append($$, $2); }
;
specifiers
: type_specifier
| struct_specifier
| vec_specifier
;
specifiers_list
: specifiers { $$ = NULL; $$ = g_list_append($$, $1); }
| specifiers_list specifiers { $$ = g_list_append($$, $2); }
;
struct_values
: struct values_list struct_end { $$ = handle_struct(args, $2); }
;
vec_values
: vec values_list vec_end { $$ = handle_vector(args, $2); }
;
value_specifiers
: values
| struct_values
| vec_values
;
values_list
: value_specifiers { $$ = NULL; $$ = g_list_append($$, $1); }
| values_list value_specifiers { $$ = g_list_append($$, $2); }
;
reply
: REPLY
;
translation_unit
: values_list reply specifiers_list { $$ = make_transaction_and_reply($1, $3); ast = $$; }
| values_list { $$ = make_transaction_and_reply($1, 0); ast = $$; }
| reply specifiers_list { $$ = make_transaction_and_reply(0, $2); ast = $$; }
;
%%
#include <stdio.h>
#include <glib.h>
#include <gutil_log.h>
#include <binder-call.h>
extern char yytext[];
struct value_info* handle_int8(App* app, int value)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = INT8_TYPE;
v->value = g_new0(unsigned char, 1);
* ((unsigned char*)v->value) = value;
return v;
}
struct value_info* handle_int32(App* app, int value)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = INT32_TYPE;
v->value = g_new0(int, 1);
* ((int*)v->value) = value;
return v;
}
struct value_info* handle_int64(App* app, long value)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = INT64_TYPE;
v->value = g_new0(long, 1);
* ((long*)v->value) = value;
return v;
}
struct value_info* handle_float(App* app, float value)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = FLOAT_TYPE;
v->value = g_new0(float, 1);
* ((float*)v->value) = value;
return v;
}
struct value_info* handle_double(App* app, double value)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = DOUBLE_TYPE;
v->value = g_new0(double, 1);
* ((double*)v->value) = value;
return v;
}
struct value_info* handle_string8(App* app, char* value)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = STRING8_TYPE;
v->value = value;
return v;
}
struct value_info* handle_string16(App* app, char* value)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = STRING16_TYPE;
v->value = value;
return v;
}
struct value_info* handle_hstring(App* app, char* value)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = HSTRING_TYPE;
v->value = value;
return v;
}
struct value_info* handle_vector(App* app, GList* values)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = VECTOR_TYPE;
v->value = values;
return v;
}
struct value_info* handle_struct(App* app, GList* values)
{
struct value_info* v = g_new0(struct value_info, 1);
v->type = STRUCT_TYPE;
v->value = values;
return v;
}
struct type_info* handle_type_int8(App* app)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = INT8_TYPE;
info->data = 0;
return info;
}
struct type_info* handle_type_int32(App* app)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = INT32_TYPE;
info->data = 0;
return info;
}
struct type_info* handle_type_int64(App* app)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = INT64_TYPE;
info->data = 0;
return info;
}
struct type_info* handle_type_float(App* app)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = FLOAT_TYPE;
info->data = 0;
return info;
}
struct type_info* handle_type_double(App* app)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = DOUBLE_TYPE;
info->data = 0;
return info;
}
struct type_info* handle_type_string8(App* app)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = STRING8_TYPE;
info->data = 0;
return info;
}
struct type_info* handle_type_string16(App* app)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = STRING16_TYPE;
info->data = 0;
return info;
}
struct type_info* handle_type_hstring(App* app)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = HSTRING_TYPE;
info->data = 0;
return info;
}
struct type_info* handle_type_vector(App* app, struct type_info* t)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = VECTOR_TYPE;
info->data = t;
return info;
}
struct type_info* handle_type_struct(App* app, GList* l)
{
struct type_info* info = g_new0(struct type_info, 1);
info->type = STRUCT_TYPE;
info->data = l;
return info;
}
struct transaction_and_reply* make_transaction_and_reply(GList* transaction, GList* reply)
{
struct transaction_and_reply* tar = g_new0(struct transaction_and_reply, 1);
tar->tree_transaction = transaction;
tar->tree_reply = reply;
return tar;
}
void cmdlineerror(App* app, char const* s)
{
fprintf(stderr, "@%d %s: %s\n", app->rargc - 1, s, app->opt->argv[app->rargc - 1]);
}

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

155
test/common/Makefile Normal file
View File

@@ -0,0 +1,155 @@
# -*- 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
#
PKG_CONFIG ?= pkg-config
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
DEFINES += -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_32 \
-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_MAX_ALLOWED
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

@@ -2,24 +2,31 @@
all:
%:
@$(MAKE) -C unit_bridge $*
@$(MAKE) -C unit_buffer $*
@$(MAKE) -C unit_cleanup $*
@$(MAKE) -C unit_client $*
@$(MAKE) -C unit_config $*
@$(MAKE) -C unit_driver $*
@$(MAKE) -C unit_eventloop $*
@$(MAKE) -C unit_fmq $*
@$(MAKE) -C unit_ipc $*
@$(MAKE) -C unit_local_object $*
@$(MAKE) -C unit_local_reply $*
@$(MAKE) -C unit_local_request $*
@$(MAKE) -C unit_log $*
@$(MAKE) -C unit_protocol $*
@$(MAKE) -C unit_proxy_object $*
@$(MAKE) -C unit_reader $*
@$(MAKE) -C unit_remote_object $*
@$(MAKE) -C unit_remote_reply $*
@$(MAKE) -C unit_remote_request $*
@$(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 $*
@$(MAKE) -C unit_writer $*

View File

@@ -18,7 +18,31 @@ COMMON_SRC ?= test_binder.c test_main.c
# Required packages
#
PKGS += libglibutil glib-2.0 gobject-2.0
PKGS += glib-2.0 gobject-2.0
ifeq ($(LIBGLIBUTIL_PATH),)
# Assume that libglibutil devel package is installed
PKGS += libglibutil
else
# Side-by-side build
INCLUDES += -I$(LIBGLIBUTIL_PATH)/include
DEBUG_LIBS = -L$(LIBGLIBUTIL_PATH)/build/debug -lglibutil
RELEASE_LIBS = -L$(LIBGLIBUTIL_PATH)/build/release -lglibutil
DEBUG_DEPS = libglibutil_debug
RELEASE_DEPS = libglibutil_release
.PHONY: libglibutil_debug libglibutil_release
libglibutil_debug:
$(MAKE) -C $(LIBGLIBUTIL_PATH) debug
libglibutil_release:
$(MAKE) -C $(LIBGLIBUTIL_PATH) release
endif
#
# Default target
@@ -42,18 +66,21 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
# Tools and flags
#
PKG_CONFIG ?= pkg-config
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS += -Wall -Wno-deprecated-declarations
DEFINES += -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_32 \
-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_MAX_ALLOWED
INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
BASE_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS)
BASE_CFLAGS = $(BASE_FLAGS) $(CFLAGS)
FULL_CFLAGS = $(BASE_CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
$(shell $(PKG_CONFIG) --cflags $(PKGS))
FULL_LDFLAGS = $(BASE_LDFLAGS)
LIBS = $(shell pkg-config --libs $(PKGS))
QUIET_MAKE = make --no-print-directory
LIBS = $(shell $(PKG_CONFIG) --libs $(PKGS)) -lpthread
QUIET_MAKE = $(MAKE) --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =
COVERAGE_FLAGS = -g
@@ -74,9 +101,9 @@ DEBUG_LIB = $(LIB_DIR)/$(DEBUG_LIB_FILE)
RELEASE_LIB = $(LIB_DIR)/$(RELEASE_LIB_FILE)
COVERAGE_LIB = $(LIB_DIR)/$(COVERAGE_LIB_FILE)
DEBUG_LIBS = $(DEBUG_LIB) $(LIBS)
RELEASE_LIBS = $(RELEASE_LIB) $(LIBS)
COVERAGE_LIBS = $(COVERAGE_LIB) $(LIBS)
DEBUG_LIBS += $(DEBUG_LIB) $(LIBS)
RELEASE_LIBS += $(RELEASE_LIB) $(LIBS)
COVERAGE_LIBS += $(COVERAGE_LIB) $(LIBS)
#
# Files
@@ -107,8 +134,8 @@ $(DEBUG_LIB): | debug_lib
$(RELEASE_LIB): | release_lib
$(COVERAGE_LIB): | coverage_lib
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR) $(DEBUG_DEPS)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR) $(RELEASE_DEPS)
$(COVERAGE_OBJS): | $(COVERAGE_BUILD_DIR)
#
@@ -132,7 +159,7 @@ unitclean:
clean: unitclean
cleaner: unitclean
@make -C $(LIB_DIR) clean
@$(MAKE) -C $(LIB_DIR) clean
test_banner:
@echo "===========" $(EXE) "=========== "

File diff suppressed because it is too large Load Diff

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:
*
@@ -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,29 +126,23 @@ 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);
test_binder_ignore_dead_object(
int fd);
void
test_binder_br_reply_status_later(
int
test_binder_handle(
int fd,
gint32 status);
GBinderLocalObject* obj);
void
test_binder_set_looper_enabled(
GBinderLocalObject*
test_binder_object(
int fd,
gboolean enabled);
void
test_binder_set_passthrough(
int fd,
gboolean passthrough);
guint handle)
G_GNUC_WARN_UNUSED_RESULT; /* Need to unref */
guint
test_binder_register_object(
@@ -143,7 +164,8 @@ test_binder_set_destroy(
void
test_binder_exit_wait(
void);
const TestOpt* opt,
GMainLoop* loop);
#endif /* TEST_BINDER_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-2023 Slava Monich <slava@monich.com>
* Copyright (C) 2018-2021 Jolla Ltd.
*
* You may use this file under the terms of BSD license as follows:
*
@@ -40,6 +40,13 @@ typedef struct test_opt {
int flags;
} TestOpt;
typedef struct test_config {
const char* default_config_dir;
const char* default_config_file;
char* config_dir;
char* non_existent_config_file;
} TestConfig;
/* Should be invoked after g_test_init */
void
test_init(
@@ -47,6 +54,16 @@ test_init(
int argc,
char* argv[]);
/* Creates empty test config dir */
void
test_config_init(
TestConfig* config,
const char* template);
void
test_config_cleanup(
TestConfig* config);
/* Run loop with a timeout */
void
test_run(
@@ -64,11 +81,26 @@ test_quit_later_n(
GMainLoop* loop,
guint n);
/*
* Makes sure that we own the context for the entire duration of the test.
* That prevents many race conditions - all callbacks that are supposed to
* be invoked on the main thread, are actually invoked on the main thread
* (rather than a random worker thread which happens to acquire the context).
*/
void
test_run_in_context(
const TestOpt* opt,
GTestFunc func);
#define TEST_TIMEOUT_SEC (20)
/* 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) \
@@ -80,6 +112,10 @@ test_quit_later_n(
(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) \

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