Compare commits

...

352 Commits

Author SHA1 Message Date
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
Slava Monich
e5f11aafc1 Version 1.1.2 2020-12-23 12:40:10 +02:00
Slava Monich
f262c77b17 Merge pull request #58 from monich/unit-wait
Fix random unit text failures
2020-12-23 12:29:35 +02:00
Slava Monich
3ef00effc5 [unit] Call gbinder_ipc_exit() when appropriate. Fixes JB#52595
If a test calls test_binder_set_looper_enabled(fd, TRUE) to enable
processing of incoming data by the looper thread, the same thread
may get picked up by the next test and swallow the reply before the
transaction (for which the reply was intended) has been submitted.
Which may cause that next test to either fail or (if the transaction
was synchronous) block forever, stalling the build.

Calling gbinder_ipc_exit() makes sure that looper thread terminates
before the next test starts.
2020-12-22 23:50:37 +02:00
Slava Monich
1ce13bea91 [unit] Speed up test_binder_exit_wait()
Use condition variable to signal closure of the last descriptor.
2020-12-22 23:40:56 +02:00
Slava Monich
eaab366dcb Version 1.1.1 2020-12-22 15:19:03 +02:00
Slava Monich
784f06c415 Merge pull request #57 from monich/sm-test
A few minor tweaks and another unit test
2020-12-22 15:13:09 +02:00
Slava Monich
4b07e80a8f [gbinder] Added couple more looper checks
We must have looper running in order to receive death notifications.
2020-12-19 01:42:42 +02:00
Slava Monich
9f7fac407d [unit] Added unit_servicemanager_aidl. JB#42956
And refactored binder simulator, it can now simulate a lot
more sophisticated scenarious.
2020-12-08 05:03:15 +02:00
Slava Monich
47b6668876 [gbinder] Added internal gbinder_ipc_set_max_threads(). JB#42956
It's needed by unit tests to make sure that asynchronous requests
get executed sequentially. Our binder simulation is too primitive
to handle truely overlapping requests.
2020-12-08 05:02:57 +02:00
Slava Monich
951977961b [gbinder] Pass 0x0f priority to service list request. JB#42956
Based on examination of servicemanager source code, it seems to be
a better idea because it's interpreted as a bitmask.
2020-12-07 18:56:04 +02:00
Slava Monich
f069c3a595 [gbinder] Corner cases for abandoned loopers. JB#42956
If the last GBinderIpc reference was dropped by the looper thread,
the exit flag wasn't set by gbinder_ipc_looper_stop() and such
looper thread kept hanging forever. Also, that flag wasn't checked
by gbinder_driver_read(), and even though it's even less likely
to cause any trouble in real life, let's fix that too.
2020-12-07 05:19:14 +02:00
Slava Monich
b84194e8c7 Version 1.1.0 2020-12-04 13:50:42 +02:00
Slava Monich
e06e989aa5 [gbinder] Updated README 2020-12-04 13:44:41 +02:00
Slava Monich
ab75505437 Merge pull request #56 from monich/config
Make protocol and service managers configurable per binder device
2020-12-04 13:33:10 +02:00
Slava Monich
e97663b58e [gbinder] Added support for API level presets. JB#51844
API level can be configured via libgbinder config file like this:

  [General]
  ApiLevel = 28

and that adds protocol and servicemanager values appropriate for
the specified Android API level.

Presets are currently defined for API levels 28 and 29.
2020-12-04 03:09:37 +02:00
Slava Monich
a92f57a30c [gbinder] Added "aidl2" variant of RPC protocol. JB#51844
It first appeared in Android 10 (API level 29)
2020-12-03 20:57:09 +02:00
Slava Monich
ebb9381e46 [gbinder] Added "aidl2" variant of service manager. JB#51844
It first appeared in Android 9 (API level 28)
2020-12-03 20:26:50 +02:00
Slava Monich
5fb441fb81 [gbinder] Support for multiple config files. JB#51844
In additions to loading /etc/gbinder.conf, directory /etc/gbinder.d is
searched for .conf files and those overwrite the configuration found
in /etc/gbinder.conf (or more likely, provide entries of their own)
2020-12-03 20:25:21 +02:00
Slava Monich
f3a00fe8a2 [gbinder] Made service managers configurable. JB#51844
Custom device-to-protocol mapping can be provided via /etc/gbinder.conf
and the default config looks like this:

  [ServiceManager]
  Default = aidl
  /dev/binder = aidl
  /dev/hwbinder = hidl

gbinder_defaultservicemanager_new() and gbinder_hwservicemanager_new()
have beed deprecated and should no longer be used. They will keep
returning the same original servicemanagers no matter what's specified
in the configuration files.

Those calls should be replaced with gbinder_servicemanager_new() which
picks the right servicemanager implementation for the specified device.
2020-12-03 20:22:06 +02:00
Slava Monich
573494570c [gbinder] Renamed service managers. JB#51844
It's become clear that more of those are coming, consistent naming
scheme is needed. For now it's just this:

  defaultservicemanager => servicemanager_aidl
  hwservicemanager => servicemanager_hidl
2020-12-03 20:15:47 +02:00
Slava Monich
92392f5c9a [gbinder] Made RPC protocol configurable per device. JB#51844
Custom device-to-protocol mapping can be provided via /etc/gbinder.conf
and the default config looks like this:

  [Protocol]
  Default = aidl
  /dev/binder = aidl
  /dev/hwbinder = hidl
2020-12-03 20:15:33 +02:00
Slava Monich
8a634a0d95 Version 1.0.47 2020-09-19 20:17:50 +03:00
Slava Monich
23c5d48b5d Merge pull request #55 from rinigus/permissions
Install library as executable
2020-09-19 20:12:01 +03:00
Rinigus
f000b344dd [packaging] Install library as executable. JB#51013
Installs the library with exe permissions, as expected on RPM systems.

Signed-off-by: Rinigus <rinigus.git@gmail.com>
2020-09-19 20:05:37 +03:00
Slava Monich
42177e1ff2 Version 1.0.46 2020-07-31 02:06:28 +03:00
Slava Monich
091ca483e7 Merge pull request #52 from monich/wakeup_err
WARNING! Failed to wake up the looper
2020-07-31 02:01:13 +03:00
Slava Monich
42ce4f8821 Merge pull request #54 from monich/tools
Package binder-list and binder-ping utilities
2020-07-31 01:59:42 +03:00
Slava Monich
9a1781765b [packaging] Package binder-list and binder-ping tools. JB#42956
Package those as a separate package which won't be getting installed
by default, but will be easy enough to pull in, if needed. They are
quite useful as development tools.
2020-07-31 01:28:51 +03:00
Slava Monich
544b8181e5 [binder-list] Use /dev/hwbinder by default. JB#42956
It's become far more common use case recently.
2020-07-31 00:42:35 +03:00
Slava Monich
82ea37ead9 Version 1.0.45 2020-07-27 23:20:41 +03:00
Slava Monich
882ef93084 Merge pull request #53 from monich/null_vec
Fix long-standing issue with NULL vectors
2020-07-27 22:45:40 +03:00
Slava Monich
881469ab7f [gbinder] Always provide data buffer for hidl vector. JB#42956
Every vector, even the one without data, requires two buffer objects.
That's what generated stubs expect.
2020-07-27 20:53:01 +03:00
Slava Monich
d7834650ae [gbinder] Make sure we drop fds that are going to be closed. JB#50224
Even if for whatever reason the transaction thread doesn't get woken up
by the transaction handler, it (the transaction thread) still needs to
drop the transaction pipe fds unless all other references have already
been dropped. Otherwise those fds are going to be closed by whoever
drops the last reference to GBinderIpcLooperTx and become invalid.
2020-07-16 17:45:17 +03:00
Slava Monich
20bf183a10 [gbinder] Better diagnostics for polling failures. JB#50224
Something fishy is going on sometimes, which results in transaction
pipe descriptors being closed and yet still being used. Let's see
if this sheds any light on it.
2020-07-09 01:40:16 +03:00
Slava Monich
c990ac66da Version 1.0.44 2020-06-29 17:07:25 +03:00
Slava Monich
0964163a35 Merge pull request #51 from monich/jb49615
Never drop valid incoming transactions
2020-06-29 17:01:08 +03:00
Slava Monich
fc980b1bc9 [unit] Added GBinderIpc tests. JB#49615
Simulate simultaneous two-way transactions.
2020-06-26 16:10:22 +03:00
Slava Monich
e76c8a3ba7 [gbinder] Never drop valid incoming transactions. Fixes JB#49615
Incoming transactions were being rejected if they were received
while we were waiting for completion of our own transaction.
That wasn't right.
2020-06-26 16:09:17 +03:00
Slava Monich
5805290369 Version 1.0.43 2020-06-03 15:16:40 +03:00
Slava Monich
7dd9623929 Merge pull request #48 from krnlyng/jb49520
Allow strip command to be replaced through external environment variable STRIP
2020-06-03 15:07:57 +03:00
Slava Monich
95ac07e4de Merge pull request #49 from monich/lib64
Respect arch specific lib dir
2020-06-03 15:04:36 +03:00
Slava Monich
92cd463b34 [gbinder] Respect arch specific lib dir. JB#49681 2020-06-03 01:47:58 +03:00
Slava Monich
6832546dca [gbinder] Hide internal symbols. JB#42956 2020-06-03 01:33:23 +03:00
Franz-Josef Haider
049042b134 libgbinder: allow strip command to be replaced through external environment variable STRIP.
[libgbinder] allow strip command to be replaced through external environment variable STRIP. JB#49520
2020-05-29 12:22:40 +00:00
Slava Monich
6d2f2efe31 Version 1.0.42 2020-05-05 20:01:45 +03:00
Slava Monich
bcce4831e3 Merge pull request #47 from monich/multi-client
Support for multiple versions of hwbinder interfaces
2020-05-05 19:55:06 +03:00
Slava Monich
7fb3053135 [unit] Added test for the GBinderClient API. JB#49360 2020-05-05 19:45:36 +03:00
Slava Monich
00359a0fc8 [gbinder] Allow GBinderClient to use more than one interface. JB#49360
Or more likely, multiple versions of the same interface. For example,
first N transaction codes may be associated with version 1.0 of the
interface, the next M codes with version 1.1 and so on.

The following new functions have been introduced:

  gbinder_client_new2
  gbinder_client_interface2
  gbinder_client_new_request2

Note that a similar functionality could be achieved by allocating
a separate client for each version of the interface. This is just
a more convenient way of doing pretty much the same thing.

The old API still works, just assumes the same interface for all
transaction codes.
2020-05-05 19:44:14 +03:00
Slava Monich
ccf3e1237c Version 1.0.41 2020-04-14 12:40:05 +03:00
Slava Monich
e02f00fd41 Merge pull request #45 from monich/idle-pool
Stop using GUtilIdlePool
2020-04-14 12:34:42 +03:00
Slava Monich
e45e640f3c [gbinder] Stop using GUtilIdlePool. JB#49512
It won't work with a non-glib event loop. And one of those objects
turned out to actually be unused.
2020-04-11 02:26:46 +03:00
Slava Monich
75e8015c43 [gbinder] Added internal event loop utilities. JB#49512
gbinder_idle_callback_schedule_new = gbinder_idle_callback_new +
and gbinder_idle_callback_schedule

gbinder_idle_callback_destroy = gbinder_idle_callback_cancel +
gbinder_idle_callback_unref
2020-04-11 02:22:22 +03:00
Slava Monich
2c52fcc156 Version 1.0.40 2020-04-09 17:24:06 +03:00
Slava Monich
dc5b51a41f Merge pull request #44 from monich/event-loop
Pluggable event loop integration
2020-04-09 17:18:29 +03:00
Slava Monich
d12cee4690 [unit] Added eventloop test. JB#49512 2020-04-06 17:22:55 +03:00
Slava Monich
a74c4ac148 [gbinder] Virtualize event loop. JB#49512
This makes it possible to make libgbinder work with e.g. Qt event loop
based on QEventDispatcherUNIX (rather than QEventDispatcherGlib).
2020-04-04 20:26:06 +03:00
Slava Monich
53e50a8107 Version 1.0.39 2020-04-02 18:08:05 +03:00
Slava Monich
e896ba94cc Merge pull request #43 from mer-hybris/side-by-side-linking
Fix linking for side-by-side builds
2020-04-02 18:04:56 +03:00
Matti Lehtimäki
87ff990c73 [build] Fix linking for side-by-side builds. JB#49231 2020-04-02 14:48:16 +00:00
Slava Monich
e406162be2 Version 1.0.38 2020-04-02 00:13:53 +03:00
Slava Monich
2de4120f25 Merge pull request #42 from monich/default_log
Allow to configure log level via environment
2020-04-02 00:10:19 +03:00
Slava Monich
d8dc58a133 [unit] Added gbinder_log test. JB#42956 2020-04-01 21:00:51 +03:00
Slava Monich
8684bffe97 [gbinder] Allow to configure log level via environment. JB#42956
GBINDER_DEFAULT_LOG_LEVEL environment variable configures default
libgbinder log level. Valid (inclusive) range is from -1 (inherit
libglibutil defaults) to 5 (verbose).
2020-04-01 17:35:44 +03:00
Slava Monich
a08513ade0 Version 1.0.37 2020-03-17 20:16:33 +02:00
Slava Monich
1a57e01e07 [gbinder] Fixed compilation warnings. JB#42956 2020-03-17 20:12:45 +02:00
Slava Monich
6d4faf19b8 [build] Allow side-by-side linking with libglibutil. JB#49231 2020-03-17 19:57:22 +02:00
Slava Monich
96e6845e16 Version 1.0.36 2020-03-16 16:16:58 +02:00
Slava Monich
b33adeb708 Merge pull request #41 from krnlyng/jb48037
Allow overwriting CC with a predefined one
2020-03-16 16:13:00 +02:00
Frajo Haider
ea0e294a74 [gbinder] Allow overwriting CC with a predefined one. JB#48037 2020-03-16 16:10:40 +02:00
Slava Monich
2d878c2391 Version 1.0.35 2020-02-25 14:02:35 +02:00
Slava Monich
6dec867cd3 [license] Freshened up copyright 2020-02-25 14:01:52 +02:00
Slava Monich
d8bd7b9366 Merge pull request #40 from monich/master
Add binder-ping
2020-02-25 13:55:50 +02:00
Slava Monich
b52e4c6dee [test] Added binder-ping. JB#42956 2020-02-24 23:57:21 +02:00
Slava Monich
21046af42f Version 1.0.34 2019-12-16 12:28:07 +02:00
Slava Monich
3cbe1d6ac8 Merge pull request #39 from monich/exit
Drop remote refs and shutdown loopers on unload
2019-12-16 12:22:28 +02:00
Slava Monich
b4b1a99a27 [unit] Added unit test for gbinder_ipc_exit. JB#48435 2019-12-16 03:13:57 +02:00
Slava Monich
f5a2d481e3 [gbinder] Fixed rare memory leak in GBinderServiceManager
Result needs to be freed even it completion callback never runs.
2019-12-16 03:12:52 +02:00
Slava Monich
da57a15852 [gbinder] Cancel outstanding transactions on unload. JB#48435 2019-12-16 03:11:46 +02:00
Slava Monich
9d0ac624c5 [unit] Housekeeping. JB#48413
Removed unused variable
2019-12-15 18:52:27 +02:00
Slava Monich
b8ccc80b87 [unit] Housekeeping. JB#48413
Fixed compilation warning: duplicate 'const' declaration specifier
2019-12-15 18:50:15 +02:00
Slava Monich
27e2dac22e [gbinder] Drop remote refs and shutdown loopers on unload. JB#48435
That prevents crashes when libgbinder.so is being unloaded. Which
went unnoticed because it typically happens when process exits anyway.

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

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

  gbinder_servicemanager_wait()

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

  gbinder_servicemanager_is_present()
  gbinder_servicemanager_add_presence_handler()

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

Added gbinder_reader_skip_hidl_string() macro.

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

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

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

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

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

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

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

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

The polling interval is 2 seconds.

It doesn't affect hwservicemanager implementation which relies
on notifications, no polling there.
2018-12-04 23:43:49 +02:00
Slava Monich
6ea0d6c631 [unit] Added test for HIDL_PING_TRANSACTION 2018-12-04 15:07:27 +02:00
Slava Monich
31c6c05c1e [unit] Added unit_servicemanager test 2018-12-04 13:31:18 +02:00
Slava Monich
d855d695db Version 1.0.14 2018-11-27 17:21:33 +02:00
Slava Monich
922cc82029 Merge pull request #15 from monich/bool
Change bool padding from 0xff to 0x00
2018-11-27 17:15:57 +02:00
Slava Monich
80498378f2 [gbinder] Change bool padding from 0xff to 0x00. JB#42956
That should make it compatible with both java and hidl variants of
encoding (Android's libbinder vs libhwbinder)
2018-11-27 16:59:11 +02:00
Slava Monich
51856865df Version 1.0.13 2018-11-17 01:58:33 +02:00
Slava Monich
d26dcca37e [gbinder] Make sure looper is started
... before gbinder_ipc_looper_new() returns.
2018-11-17 01:49:50 +02:00
Slava Monich
5ac02fcb2e Merge pull request #14 from monich/registration
Support for service registration notifications
2018-11-17 01:47:28 +02:00
Slava Monich
110cd65779 [gbinder] Support for service registration notifications. JB#43815
android.hidl.manager@1.0::IServiceManager provides registration
notifications via android.hidl.manager@1.0::IServiceNotification
callback.

Sailfish OS services that talk to Android services via binder should
use this mechanism to wait for their Android counterpart at startup.
2018-11-17 01:41:02 +02:00
Slava Monich
67e665b619 Version 1.0.12 2018-10-31 17:07:45 +03:00
Slava Monich
d1c431c370 Acknowledge contributions 2018-10-31 17:03:44 +03:00
Slava Monich
2167a82c73 Housekeeping 2018-10-31 17:01:00 +03:00
Slava Monich
d113d3bf4a Merge pull request #12 from jusa/byte_array
Add byte array reader and writer.
2018-10-31 16:40:33 +03:00
Juho Hämäläinen
b2206adae5 [gbinder] Add byte array reader and writer. JB#43536
New functions gbinder_reader_read_byte_array() and
gbinder_writer_append_byte_array()
2018-10-30 07:28:19 +02:00
Slava Monich
8075cce1b1 Version 1.0.11 2018-10-24 18:59:30 +03:00
Slava Monich
29e4c79f75 Merge pull request #11 from krnlyng/jb43524
Make sure NULL objects are passed as BINDER_TYPE_WEAK_HANDLE
2018-10-24 18:53:58 +03:00
Franz-Josef Haider
3b299d3345 [local_object] Make sure NULL objects are passed as BINDER_TYPE_WEAK_HANDLE. Contributes to JB#43524
See also: https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/Parcel.cpp#264
2018-10-24 15:41:27 +00:00
Slava Monich
7421fff380 Updated README 2018-10-11 12:04:04 +03:00
Slava Monich
694aad637b Version 1.0.10 2018-10-10 14:46:40 +03:00
Slava Monich
c8c7222e06 [unit] Plugged memory leak in unit_reader. JB#42956 2018-10-10 14:44:25 +03:00
Slava Monich
9c6e31ef41 Merge pull request #10 from monich/deps
Fix dependencies for unit tests
2018-10-10 14:39:17 +03:00
Slava Monich
6a8d5c0c6e [unit] Fixed dependencies for unit tests. JB#42691 2018-10-10 14:38:38 +03:00
Slava Monich
96ca10396b Version 1.0.9 2018-10-08 11:43:53 +03:00
Slava Monich
61cef824e8 Merge pull request #9 from monich/read_hidl_struct
Add gbinder_reader_read_hidl_struct() and other macros
2018-10-08 11:20:13 +03:00
Slava Monich
972517d32d Merge pull request #8 from monich/strong_refs
Respect strong refs to GBinderLocalObject
2018-10-08 11:17:00 +03:00
Slava Monich
217a03642a [unit] Added test for new gbinder_reader_read_hidl_struct() 2018-10-08 11:13:00 +03:00
Slava Monich
f14783b8cf [gbinder] Add gbinder_reader_read_hidl_struct() macro. JB#42956
As well as two macros for reading arrays:

   gbinder_reader_read_hidl_type_vec() - vec<type>
   gbinder_reader_read_hidl_byte_vec() - vec<uint8_t>

These convenient for pulling structures and arrays from hwbinder
requests and responses.

Note that data are not being copied, all these macros return pointers
to the memory buffer passed to us by the kernel. Such pointers remain
valid as long the associated remote request/response is alive.
2018-10-06 18:07:39 +03:00
Slava Monich
4f75c6e37b [gbinder] Respect strong refs to GBinderLocalObject. JB#42956
This lets kernel to keep the object alive for a long time, after the
creator of the object drops its last reference.

That makes it even more important very important that creator drops
its last reference by calling gbinder_local_object_drop() rather than
gbinder_local_object_unref() to make sure that the handler function
doesn't get called anymore.
2018-10-06 11:39:02 +03:00
Slava Monich
4eb3b66a0e Version 1.0.8 2018-09-25 01:09:53 +03:00
Slava Monich
6b74d5faed Merge pull request #7 from monich/hidl_vec
Add gbinder_writer_append_hidl_vec() and gbinder_reader_read_hidl_vec()
2018-09-25 01:05:39 +03:00
Slava Monich
10d72ec42c [unit] Added test for gbinder_reader_read_hidl_vec() 2018-09-24 03:33:42 +03:00
Slava Monich
9eae4ef819 [gbinder] Added gbinder_reader_read_hidl_vec(). JB#42956
This provides a generic way to read any array of any primitive
types or structures. Note that it doesn't copy the data and
directly returns the pointer provided by the kernel.
2018-09-24 03:14:33 +03:00
Slava Monich
b3657e396f [unit] Added test for gbinder_writer_append_hidl_vec() 2018-09-24 00:48:56 +03:00
Slava Monich
a69885d05f [gbinder] Added gbinder_writer_append_hidl_vec(). JB#42956
This provides a generic way to write hidl-style array of any primitive
types or any structures as long as they don't contain pointers.
2018-09-24 00:47:14 +03:00
Slava Monich
306d08112b Version 1.0.7 2018-09-23 22:49:16 +03:00
Slava Monich
b489becf51 Merge pull request #5 from monich/forward
Add gbinder_remote_request_copy_to_local() and gbinder_remote_reply_copy_to_local()
2018-09-23 22:44:27 +03:00
Slava Monich
8a27829af3 [gbinder] Make sure RPC protocol matches servicemanager type
This makes it easier to use non-standard binder device name.
2018-09-22 12:15:20 +03:00
Slava Monich
d67b73502e [unit] Added test for gbinder_remote_reply_copy_to_local() 2018-09-22 12:15:20 +03:00
Slava Monich
4ecf3ae24d [gbinder] Added gbinder_remote_reply_copy_to_local(). JB#42956 2018-09-22 12:15:20 +03:00
Slava Monich
d0542e759d [unit] Added test for gbinder_remote_request_copy_to_local() 2018-09-22 12:15:20 +03:00
Slava Monich
ffa44ac5b3 [gbinder] Added gbinder_remote_request_copy_to_local(). JB#42956
This function could be useful for proxy services, as an easy way to
forward an incoming request. To complete the picture, we should also
have gbinder_remote_reply_copy_to_local() for forwarding replies.
2018-09-22 12:15:20 +03:00
Slava Monich
6509e5dac8 Version 1.0.6 2018-09-21 21:16:29 +03:00
Slava Monich
6b956c0d3c Merge pull request #6 from monich/ref_count
Fix GBinderServiceManager lifecycle management
2018-09-21 21:14:01 +03:00
Slava Monich
3b10a08bad [gbinder] Fixed GBinderServiceManager lifecycle management. Fixes JB#43018
Dispose callback is invoked with refcount 1
2018-09-21 20:27:40 +03:00
162 changed files with 29300 additions and 2596 deletions

14
.gitignore vendored
View File

@@ -1,13 +1,13 @@
*~
debian/files
debian/libgbinder-dev.debhelper.log
debian/libgbinder-dev.substvars
debian/libgbinder-dev
debian/libgbinder.debhelper.log
debian/libgbinder.postinst.debhelper
debian/libgbinder.postrm.debhelper
debian/libgbinder.substvars
debian/libgbinder
debian/libgbinder-dev
debian/libgbinder-tools
debian/*.debhelper.log
debian/*.debhelper
debian/*.substvars
debian/libgbinder.install
debian/libgbinder-dev.install
debian/tmp
documentation.list
installroot

View File

@@ -1,2 +1,10 @@
Slava Monich <slava.monich@jolla.com>
Matti Lehtimäki <matti.lehtimaki@gmail.com>
Franz-Josef Haider <franz.haider@jolla.com>
Juho Hämäläinen <juho.hamalainen@jolla.com>
Andrew Branson <andrew.branson@jolla.com>
Rinigus <rinigus.git@gmail.com>
George Hopkins <george-hopkins@null.net>
Bart Ribbers <bribbers@disroot.org>
Gary Wang <gary.wang@canonical.com>
Eugenio Paolantonio <me@medesimo.eu>

10
LICENSE
View File

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

145
Makefile
View File

@@ -1,16 +1,25 @@
# -*- Mode: makefile-gmake -*-
#
# LIBGLIBUTIL_PATH can be defined to point to libglibutil root directory
# for side-by-side build.
#
.PHONY: clean all debug release test
.PHONY: print_debug_so print_release_so
.PHONY: print_debug_lib print_release_lib
.PHONY: print_debug_lib print_release_lib print_coverage_lib
.PHONY: print_debug_link print_release_link
.PHONY: print_debug_path print_release_path
#
# Required packages
# Library version
#
PKGS = libglibutil glib-2.0 gobject-2.0
VERSION_MAJOR = 1
VERSION_MINOR = 1
VERSION_RELEASE = 19
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
#
# Default target
@@ -19,15 +28,34 @@ PKGS = libglibutil glib-2.0 gobject-2.0
all: debug release pkgconfig
#
# Library version
# Required packages
#
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_RELEASE = 5
PKGS = glib-2.0 gobject-2.0
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
ifeq ($(LIBGLIBUTIL_PATH),)
# Assume that libglibutil devel package is installed
PKGS += libglibutil
else
# Side-by-side build
INCLUDES += -I$(LIBGLIBUTIL_PATH)/include
DEBUG_LIBS = -L$(LIBGLIBUTIL_PATH)/build/debug -lglibutil
RELEASE_LIBS = -L$(LIBGLIBUTIL_PATH)/build/release -lglibutil
DEBUG_DEPS = libglibutil_debug
RELEASE_DEPS = libglibutil_release
.PHONY: libglibutil_debug libglibutil_release
libglibutil_debug:
make -C $(LIBGLIBUTIL_PATH) debug
libglibutil_release:
make -C $(LIBGLIBUTIL_PATH) release
endif
#
# Library name
@@ -47,27 +75,37 @@ 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 \
gbinder_local_object.c \
gbinder_local_reply.c \
gbinder_local_request.c \
gbinder_log.c \
gbinder_proxy_object.c \
gbinder_reader.c \
gbinder_remote_object.c \
gbinder_remote_reply.c \
gbinder_remote_request.c \
gbinder_rpc_protocol.c \
gbinder_servicename.c \
gbinder_servicepoll.c \
gbinder_writer.c
SRC += \
gbinder_defaultservicemanager.c \
gbinder_hwservicemanager.c \
gbinder_servicemanager.c
gbinder_servicemanager.c \
gbinder_servicemanager_aidl.c \
gbinder_servicemanager_aidl2.c \
gbinder_servicemanager_aidl3.c \
gbinder_servicemanager_hidl.c
SRC += \
gbinder_system.c
@@ -87,10 +125,11 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
STRIP ?= strip
LD = $(CC)
WARNINGS = -Wall -Wstrict-aliasing -Wunused-result
INCLUDES = -I$(INCLUDE_DIR)
INCLUDES += -I$(INCLUDE_DIR)
BASE_FLAGS = -fPIC
FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) \
-MMD -MP $(shell pkg-config --cflags $(PKGS))
@@ -100,16 +139,13 @@ DEBUG_FLAGS = -g
RELEASE_FLAGS =
COVERAGE_FLAGS = -g
ifndef KEEP_SYMBOLS
KEEP_SYMBOLS = 0
endif
KEEP_SYMBOLS ?= 0
ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
endif
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_LIBS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_LIBS) $(RELEASE_FLAGS)
DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
@@ -123,6 +159,16 @@ DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
COVERAGE_OBJS = $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
DEBUG_SO = $(DEBUG_BUILD_DIR)/$(LIB_SO)
RELEASE_SO = $(RELEASE_BUILD_DIR)/$(LIB_SO)
DEBUG_LINK = $(DEBUG_BUILD_DIR)/$(LIB_SYMLINK1)
RELEASE_LINK = $(RELEASE_BUILD_DIR)/$(LIB_SYMLINK1)
DEBUG_DEV_LINK = $(DEBUG_BUILD_DIR)/$(LIB_DEV_SYMLINK)
RELEASE_DEV_LINK = $(RELEASE_BUILD_DIR)/$(LIB_DEV_SYMLINK)
DEBUG_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
COVERAGE_LIB = $(COVERAGE_BUILD_DIR)/$(LIB)
#
# Dependencies
#
@@ -135,25 +181,22 @@ endif
endif
$(PKGCONFIG): | $(BUILD_DIR)
$(DEBUG_OBJS) $(DEBUG_SO): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS) $(RELEASE_SO): | $(RELEASE_BUILD_DIR)
$(DEBUG_OBJS) $(DEBUG_SO): | $(DEBUG_BUILD_DIR) $(DEBUG_DEPS)
$(RELEASE_OBJS) $(RELEASE_SO): | $(RELEASE_BUILD_DIR) $(RELEASE_DEPS)
$(COVERAGE_OBJS) $(COVERAGE_LIB): | $(COVERAGE_BUILD_DIR)
$(DEBUG_LINK): | $(DEBUG_LIB)
$(RELEASE_LINK): | $(RELEASE_LIB)
$(DEBUG_DEV_LINK): | $(DEBUG_LINK)
$(RELEASE_DEV_LINK): | $(RELEASE_LINK)
#
# Rules
#
DEBUG_SO = $(DEBUG_BUILD_DIR)/$(LIB_SO)
RELEASE_SO = $(RELEASE_BUILD_DIR)/$(LIB_SO)
DEBUG_LINK = $(DEBUG_BUILD_DIR)/$(LIB_SYMLINK1)
RELEASE_LINK = $(RELEASE_BUILD_DIR)/$(LIB_SYMLINK1)
DEBUG_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
COVERAGE_LIB = $(COVERAGE_BUILD_DIR)/$(LIB)
debug: $(DEBUG_SO) $(DEBUG_LINK) $(DEBUG_DEV_LINK)
debug: $(DEBUG_SO)
release: $(RELEASE_SO)
release: $(RELEASE_SO) $(RELEASE_LINK) $(RELEASE_DEV_LINK)
debug_lib: $(DEBUG_LIB)
@@ -199,6 +242,7 @@ clean:
rm -fr debian/tmp debian/libgbinder debian/libgbinder-dev
rm -f documentation.list debian/files debian/*.substvars
rm -f debian/*.debhelper.log debian/*.debhelper debian/*~
rm -f debian/libgbinder.install debian/libgbinder-dev.install
test:
make -C unit test
@@ -226,13 +270,11 @@ $(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(DEBUG_SO): $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) -o $@
ln -sf $(LIB_SO) $(DEBUG_LINK)
$(RELEASE_SO): $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) -o $@
ln -sf $(LIB_SO) $(RELEASE_LINK)
ifeq ($(KEEP_SYMBOLS),0)
strip $@
$(STRIP) $@
endif
$(DEBUG_LIB): $(DEBUG_OBJS)
@@ -243,12 +285,35 @@ $(RELEASE_LIB): $(RELEASE_OBJS)
$(AR) rc $@ $?
ranlib $@
$(DEBUG_LINK):
ln -sf $(LIB_SO) $@
$(RELEASE_LINK):
ln -sf $(LIB_SO) $@
$(DEBUG_DEV_LINK):
ln -sf $(LIB_SYMLINK1) $@
$(RELEASE_DEV_LINK):
ln -sf $(LIB_SYMLINK1) $@
$(COVERAGE_LIB): $(COVERAGE_OBJS)
$(AR) rc $@ $?
ranlib $@
$(PKGCONFIG): $(LIB_NAME).pc.in
sed -e 's/\[version\]/'$(PCVERSION)/g $< > $@
#
# LIBDIR usually gets substituted with arch specific dir.
# It's relative in deb build and can be whatever in rpm build.
#
LIBDIR ?= usr/lib
ABS_LIBDIR := $(shell echo /$(LIBDIR) | sed -r 's|/+|/|g')
$(PKGCONFIG): $(LIB_NAME).pc.in Makefile
sed -e 's|@version@|$(PCVERSION)|g' -e 's|@libdir@|$(ABS_LIBDIR)|g' $< > $@
debian/%.install: debian/%.install.in
sed 's|@LIBDIR@|$(LIBDIR)|g' $< > $@
#
# Install
@@ -260,12 +325,12 @@ INSTALL = install
INSTALL_DIRS = $(INSTALL) -d
INSTALL_FILES = $(INSTALL) -m $(INSTALL_PERM)
INSTALL_LIB_DIR = $(DESTDIR)/usr/lib
INSTALL_LIB_DIR = $(DESTDIR)$(ABS_LIBDIR)
INSTALL_INCLUDE_DIR = $(DESTDIR)/usr/include/$(NAME)
INSTALL_PKGCONFIG_DIR = $(DESTDIR)/usr/lib/pkgconfig
INSTALL_PKGCONFIG_DIR = $(DESTDIR)$(ABS_LIBDIR)/pkgconfig
install: $(INSTALL_LIB_DIR)
$(INSTALL_FILES) $(RELEASE_SO) $(INSTALL_LIB_DIR)
$(INSTALL) -m 755 $(RELEASE_SO) $(INSTALL_LIB_DIR)
ln -sf $(LIB_SO) $(INSTALL_LIB_DIR)/$(LIB_SYMLINK2)
ln -sf $(LIB_SYMLINK2) $(INSTALL_LIB_DIR)/$(LIB_SYMLINK1)

45
README
View File

@@ -1 +1,46 @@
GLib-style interface to binder (Android IPC mechanism)
Key features:
1. Integration with GLib event loop
2. Detection of 32 vs 64 bit kernel at runtime
3. Asynchronous transactions that don't block the event thread
4. Stable service manager and low-level transaction APIs
Android keeps changing both low-level RPC and service manager
protocols from version to version. To counter that, libgbinder
implements configirable backends for different variants of those,
and yet keeping its own API unchanged.
Configuration is loaded from [Protocol] and [ServiceManager] sections
of /etc/gbinder.conf file. The keys are binder device names or the
special Default value, the value is the identifier of the protocol
or service manager variant, respectively.
In addition to reading /etc/gbinder.conf if it exists, /etc/gbinder.d
directory is scanned for .conf files, the file list is sorted, files are
loaded one by one, overwriting the entries loaded from /etc/gbinder.conf
or from the previously processed file.
Known protocol and service manager variants are aidl, aidl2, 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

438
debian/changelog vendored
View File

@@ -1,3 +1,441 @@
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) unstable; urgency=low
* Implemented support for passing object over the bridge
* Retry service name registration
* Wait for completion of the reply
* Fixed death handling by GBinderBridge
* Added gbinder_bridge_new2()
* Added -s option to binder-bridge
* Fixed invalid slice deallocation
* Made unit tests more reliable
* Make sure that libgbinder doesn't block on exit
-- Slava Monich <slava.monich@jolla.com> Tue, 02 Mar 2021 18:18:03 +0200
libgbinder (1.1.5) unstable; urgency=low
* Fixed gbinder_remote_reply_copy_to_local() for empty replies
* Improved binder simulation
* Added GBinderBridge object
* Added proxy_object and bridge unit tests
* Added binder-bridge to libgbinder-tools package
-- Slava Monich <slava.monich@jolla.com> Fri, 29 Jan 2021 04:00:09 +0200
libgbinder (1.1.4) unstable; urgency=low
* Fixed a threading issue
* Decode NULL object reference
* Added new basic HIDL types
* Set TF_ACCEPT_FDS transaction flag
* Added servicemanager_hidl unit test
-- Slava Monich <slava.monich@jolla.com> Thu, 21 Jan 2021 03:34:45 +0200
libgbinder (1.1.3) unstable; urgency=low
* Improved unit test coverage
-- Slava Monich <slava.monich@jolla.com> Wed, 23 Dec 2020 21:48:27 +0200
libgbinder (1.1.2) unstable; urgency=low
* Fixed random unit text failures
-- Slava Monich <slava.monich@jolla.com> Wed, 23 Dec 2020 12:39:22 +0200
libgbinder (1.1.1) unstable; urgency=low
* Handle corner cases for abandoned loopers
* Pass 0x0f priority to aidl2 service list request.
* Improved binder simulation for unit tests
* Added servicemanager_aidl unit test
-- Slava Monich <slava.monich@jolla.com> Tue, 22 Dec 2020 15:15:10 +0200
libgbinder (1.1.0) unstable; urgency=low
* Made RPC protocol configurable per binder device
* Made service managers configurable per binder device
* Added support for multiple config files
* Added "aidl2" variant of service manager
* Added "aidl2" variant of RPC protocol
* Added support for API level presets
-- Slava Monich <slava.monich@jolla.com> Fri, 04 Dec 2020 13:47:26 +0200
libgbinder (1.0.47) unstable; urgency=low
* Make library executable on RPM based systems
-- Slava Monich <slava.monich@jolla.com> Sat, 19 Sep 2020 20:14:20 +0300
libgbinder (1.0.46) unstable; urgency=low
* Make sure we drop fds that are going to be closed
* Better diagnostics for polling failures
* Package binder-list and binder-ping utilities
-- Slava Monich <slava.monich@jolla.com> Fri, 31 Jul 2020 02:04:38 +0300
libgbinder (1.0.45) unstable; urgency=low
* Always provide data buffer for hidl vector
-- Slava Monich <slava.monich@jolla.com> Mon, 27 Jul 2020 23:19:25 +0300
libgbinder (1.0.44) unstable; urgency=low
* Never drop valid incoming transactions
-- Slava Monich <slava.monich@jolla.com> Mon, 29 Jun 2020 17:05:22 +0300
libgbinder (1.0.43) unstable; urgency=low
* Hide internal symbols
* Respect arch specific lib dir
* Allow strip command to be replaced via environment variable
-- Slava Monich <slava.monich@jolla.com> Wed, 03 Jun 2020 15:15:40 +0300
libgbinder (1.0.42) unstable; urgency=low
* Allow GBinderClient to use multiple interfaces
-- Slava Monich <slava.monich@jolla.com> Tue, 05 May 2020 19:56:39 +0300
libgbinder (1.0.41) unstable; urgency=low
* Stop using GUtilIdlePool
-- Slava Monich <slava.monich@jolla.com> Tue, 14 Apr 2020 12:36:54 +0300
libgbinder (1.0.40) unstable; urgency=low
* Support integration with non-glib event loops
-- Slava Monich <slava.monich@jolla.com> Thu, 09 Apr 2020 17:22:12 +0300
libgbinder (1.0.39) unstable; urgency=low
* Adapted to side-by-side linking
-- Slava Monich <slava.monich@jolla.com> Thu, 02 Apr 2020 18:07:16 +0300
libgbinder (1.0.38) unstable; urgency=low
* Allow to configure log level via environment
-- Slava Monich <slava.monich@jolla.com> Thu, 02 Apr 2020 00:12:01 +0300
libgbinder (1.0.37) unstable; urgency=low
* Allow side-by-side linking with libglibutil
* Fixed compilation warnings
-- Slava Monich <slava.monich@jolla.com> Tue, 17 Mar 2020 20:15:11 +0200
libgbinder (1.0.36) unstable; urgency=low
* Allow overwriting CC
-- Slava Monich <slava.monich@jolla.com> Mon, 16 Mar 2020 16:15:24 +0200
libgbinder (1.0.35) unstable; urgency=low
* Added binder-ping example
-- Slava Monich <slava.monich@jolla.com> Tue, 25 Feb 2020 13:58:19 +0200
libgbinder (1.0.34) unstable; urgency=low
* Better cleanup on unload to prevent crashes on exit
* Fixed rare memory leak in GBinderServiceManager
-- Slava Monich <slava.monich@jolla.com> Mon, 16 Dec 2019 12:25:56 +0200
libgbinder (1.0.33) unstable; urgency=low
* Reuse loopers
-- Slava Monich <slava.monich@jolla.com> Fri, 13 Sep 2019 15:57:47 +0300
libgbinder (1.0.32) unstable; urgency=low
* Refuse to perform transactions with dead objects
-- Slava Monich <slava.monich@jolla.com> Fri, 17 May 2019 15:57:30 +0300
libgbinder (1.0.31) unstable; urgency=low
* Invalidate handle when remote object dies
-- Slava Monich <slava.monich@jolla.com> Mon, 13 May 2019 18:05:35 +0300
libgbinder (1.0.30) unstable; urgency=low
* Added gbinder_local_object_new()
* Added gbinder_remote_object_ipc()
-- Slava Monich <slava.monich@jolla.com> Wed, 20 Feb 2019 11:59:08 +0200
libgbinder (1.0.29) unstable; urgency=low
* Added gbinder_servicemanager_new_local_object2()
-- Slava Monich <slava.monich@jolla.com> Thu, 14 Feb 2019 18:17:53 +0300
libgbinder (1.0.28) unstable; urgency=low
* Set type for local nulls to BINDER_TYPE_WEAK_BINDER
-- Slava Monich <slava.monich@jolla.com> Tue, 29 Jan 2019 02:49:10 +0200
libgbinder (1.0.27) unstable; urgency=low
* Fixed outgoing oneway transactions
-- Slava Monich <slava.monich@jolla.com> Thu, 24 Jan 2019 18:55:16 +0200
libgbinder (1.0.26) unstable; urgency=low
* Implement PING and INTERFACE transactions
* Add GBinderServiceName API
* Added gbinder_reader_read_string16_utf16()
-- Slava Monich <slava.monich@jolla.com> Wed, 23 Jan 2019 17:43:41 +0200
libgbinder (1.0.25) unstable; urgency=low
* Added ServiceManager presence API
gbinder_servicemanager_wait()
gbinder_servicemanager_is_present()
gbinder_servicemanager_add_presence_handler()
-- Slava Monich <slava.monich@jolla.com> Tue, 22 Jan 2019 16:03:57 +0200
libgbinder (1.0.24) unstable; urgency=low
* Revert "Make sure NULL objects are passed as BINDER_TYPE_WEAK_HANDLE"
-- Slava Monich <slava.monich@jolla.com> Fri, 18 Jan 2019 21:36:32 +0200
libgbinder (1.0.23) unstable; urgency=low
* Added gbinder_reader_read_hidl_string_c()
-- Slava Monich <slava.monich@jolla.com> Tue, 15 Jan 2019 15:16:41 +0200
libgbinder (1.0.22) unstable; urgency=low
* Added gbinder_client_interface()
-- Slava Monich <slava.monich@jolla.com> Thu, 10 Jan 2019 14:09:44 +0300
libgbinder (1.0.21) unstable; urgency=low
* Added API to overwrite prefix length
-- Slava Monich <slava.monich@jolla.com> Tue, 18 Dec 2018 14:05:14 +0200
libgbinder (1.0.20) unstable; urgency=low
* Added API to block incoming requests
-- Slava Monich <slava.monich@jolla.com> Mon, 17 Dec 2018 16:06:43 +0200
libgbinder (1.0.19) unstable; urgency=low
* Added GBinderWriter memory allocation and cleanup API
-- Slava Monich <slava.monich@jolla.com> Fri, 14 Dec 2018 16:27:51 +0200
libgbinder (1.0.18) unstable; urgency=low
* Implemented support for file descritors
* Allow GBinderClient without RPC header
* Added binder-dump test
-- Slava Monich <slava.monich@jolla.com> Mon, 10 Dec 2018 13:17:22 +0200
libgbinder (1.0.17) unstable; urgency=low
* Added gbinder_writer_append_string16_utf16()
* Added gbinder_reader_read_nullable_string16_utf16()
-- Slava Monich <slava.monich@jolla.com> Fri, 07 Dec 2018 02:54:07 +0200
libgbinder (1.0.16) unstable; urgency=low
* Added GBinderHidlVec and GBinderHidlString types
* Added gbinder_reader_copy()
-- Slava Monich <slava.monich@jolla.com> Thu, 06 Dec 2018 19:03:32 +0200
libgbinder (1.0.15) unstable; urgency=low
* Implemented service polling for old servicemanager
* Added new tests and improved coverage for existing ones
-- Slava Monich <slava.monich@jolla.com> Wed, 05 Dec 2018 12:11:34 +0200
libgbinder (1.0.14) unstable; urgency=low
* Changed bool padding from 0xff to 0x00
-- Slava Monich <slava.monich@jolla.com> Tue, 27 Nov 2018 17:20:18 +0200
libgbinder (1.0.13) unstable; urgency=low
* Support for service registration notifications
* Make sure looper is started before gbinder_ipc_looper_new() returns
-- Slava Monich <slava.monich@jolla.com> Sat, 17 Nov 2018 01:52:28 +0200
libgbinder (1.0.12) unstable; urgency=low
* Add byte array reader and writer
-- Slava Monich <slava.monich@jolla.com> Wed, 31 Oct 2018 17:04:38 +0300
libgbinder (1.0.11) unstable; urgency=low
* Use BINDER_TYPE_WEAK_HANDLE for NULL objects
-- Slava Monich <slava.monich@jolla.com> Wed, 24 Oct 2018 18:57:28 +0300
libgbinder (1.0.10) unstable; urgency=low
* Fixed dependencies for unit tests
* Plugged memory leak in unit_reader
-- Slava Monich <slava.monich@jolla.com> Wed, 10 Oct 2018 14:44:44 +0300
libgbinder (1.0.9) unstable; urgency=low
* Respect strong refs to GBinderLocalObject
* Added gbinder_reader_read_hidl_struct macro
* Added gbinder_reader_read_hidl_type_vec macro
* Added gbinder_reader_read_hidl_byte_vec macro
-- Slava Monich <slava.monich@jolla.com> Mon, 08 Oct 2018 11:41:33 +0300
libgbinder (1.0.8) unstable; urgency=low
* Added gbinder_writer_append_hidl_vec()
* Added Added gbinder_reader_read_hidl_vec()
-- Slava Monich <slava.monich@jolla.com> Tue, 25 Sep 2018 01:08:54 +0300
libgbinder (1.0.7) unstable; urgency=low
* Added gbinder_remote_request_copy_to_local()
* Added gbinder_remote_reply_copy_to_local()
* Make sure RPC protocol matches servicemanager type
-- Slava Monich <slava.monich@jolla.com> Sun, 23 Sep 2018 22:47:16 +0300
libgbinder (1.0.6) unstable; urgency=low
* Fixed GBinderServiceManager lifecycle management
-- Slava Monich <slava.monich@jolla.com> Fri, 21 Sep 2018 21:15:28 +0300
libgbinder (1.0.5) unstable; urgency=low
* Added double and float support

10
debian/control vendored
View File

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

10
debian/copyright vendored
View File

@@ -1,5 +1,5 @@
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:
@@ -12,9 +12,9 @@ are met:
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Jolla Ltd nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
3. Neither the names of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

View File

@@ -1,3 +0,0 @@
debian/tmp/usr/lib/libgbinder.so usr/lib
include/*.h usr/include/gbinder
build/libgbinder.pc usr/lib/pkgconfig

3
debian/libgbinder-dev.install.in vendored Normal file
View File

@@ -0,0 +1,3 @@
debian/tmp/@LIBDIR@/libgbinder.so @LIBDIR@
debian/tmp/@LIBDIR@/pkgconfig/libgbinder.pc @LIBDIR@/pkgconfig
debian/tmp/usr/include/* usr/include

1
debian/libgbinder-tools.install vendored Normal file
View File

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

View File

@@ -1 +0,0 @@
debian/tmp/usr/lib/libgbinder.so.* usr/lib

1
debian/libgbinder.install.in vendored Normal file
View File

@@ -0,0 +1 @@
debian/tmp/@LIBDIR@/libgbinder.so.* @LIBDIR@

15
debian/rules vendored
View File

@@ -4,8 +4,21 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
LIBDIR=usr/lib/$(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
override_dh_auto_build:
dh_auto_build -- LIBDIR=$(LIBDIR) release pkgconfig debian/libgbinder.install debian/libgbinder-dev.install
dh_auto_build -- -C test/binder-bridge release
dh_auto_build -- -C test/binder-call release
dh_auto_build -- -C test/binder-list release
dh_auto_build -- -C test/binder-ping release
override_dh_auto_install:
dh_auto_install -- install-dev
dh_auto_install -- LIBDIR=$(LIBDIR) install-dev
dh_auto_install -- -C test/binder-bridge
dh_auto_install -- -C test/binder-call
dh_auto_install -- -C test/binder-list
dh_auto_install -- -C test/binder-ping
%:
dh $@

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
@@ -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"
@@ -44,6 +46,7 @@
#include "gbinder_remote_object.h"
#include "gbinder_remote_reply.h"
#include "gbinder_remote_request.h"
#include "gbinder_servicename.h"
#include "gbinder_servicemanager.h"
#include "gbinder_writer.h"

89
include/gbinder_bridge.h Normal file
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 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -37,6 +37,11 @@
G_BEGIN_DECLS
typedef struct gbinder_client_iface_info {
const char* iface;
guint32 last_code;
} GBinderClientIfaceInfo;
typedef
void
(*GBinderClientReplyFunc)(
@@ -50,6 +55,12 @@ gbinder_client_new(
GBinderRemoteObject* object,
const char* iface);
GBinderClient*
gbinder_client_new2(
GBinderRemoteObject* object,
const GBinderClientIfaceInfo* ifaces,
gsize count); /* since 1.0.42 */
GBinderClient*
gbinder_client_ref(
GBinderClient* client);
@@ -58,10 +69,29 @@ void
gbinder_client_unref(
GBinderClient* client);
const char*
gbinder_client_interface(
GBinderClient* client); /* since 1.0.22 */
const char*
gbinder_client_interface2(
GBinderClient* client,
guint32 code); /* since 1.0.42 */
GBytes*
gbinder_client_rpc_header(
GBinderClient* client,
guint32 code); /* since 1.1.14 */
GBinderLocalRequest*
gbinder_client_new_request(
GBinderClient* client);
GBinderLocalRequest*
gbinder_client_new_request2(
GBinderClient* client,
guint32 code); /* since 1.0.42 */
GBinderRemoteReply*
gbinder_client_transact_sync_reply(
GBinderClient* client,

194
include/gbinder_eventloop.h Normal file
View File

@@ -0,0 +1,194 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_EVENTLOOP_H
#define GBINDER_EVENTLOOP_H
#include "gbinder_types.h"
G_BEGIN_DECLS
/* Since 1.0.40 */
typedef struct gbinder_eventloop_integration GBinderEventLoopIntegration;
typedef void (*GBinderEventLoopCallbackFunc)(gpointer data);
typedef struct gbinder_eventloop_timeout {
const GBinderEventLoopIntegration* eventloop;
} GBinderEventLoopTimeout;
typedef struct gbinder_eventloop_callback {
const GBinderEventLoopIntegration* eventloop;
} GBinderEventLoopCallback;
/**
* Main event loop integration. There is only one main event loop in the
* process (by definition).
*
* By default, GLib event loop is being used for callbacks and timeouts.
*
* It may be necessary to replace it with e.g. Qt event loop. Quite often
* Qt event loop is implemented by QEventDispatcherGlib which is sitting
* on top of GLib event and therefore works with the default implementation.
* But it won't work with e.g. QEventDispatcherUNIX.
*
* For Qt programs that use QEventDispatcherUNIX, it needs to be replaced
* with the one provided by libqbinder.
*/
typedef struct gbinder_eventloop_integration {
/**
* timeout_add
*
* Sets a function to be called at regular intervals (in milliseconds).
* If the function returns G_SOURCE_REMOVE, timeout is automatically
* destroyed (you must not call timeout_remove in this case). If the
* function returns G_SOURCE_CONTINUE, it will be called again after
* the same interval.
*/
GBinderEventLoopTimeout* (*timeout_add)(guint millis, GSourceFunc func,
gpointer data);
/**
* timeout_remove
*
* Removes a pending timeout and destroys it. The caller makes sure that
* argument is not NULL. Note that timeout is automatically destroyed if
* the callback function returns G_SOURCE_REMOVE.
*/
void (*timeout_remove)(GBinderEventLoopTimeout* timeout);
/**
* callback_new
*
* Creates a callback object. It returns you a reference, you must
* eventually pass the returned object to callback_unref to drop
* this reference.
*
* Note that it doesn't automatically schedule the callback. You
* must explicitly call callback_schedule to actually schedule it.
* The finalize function is invoked regardless of whether callback
* was cancelled or not.
*/
GBinderEventLoopCallback* (*callback_new)(GBinderEventLoopCallbackFunc fun,
gpointer data, GDestroyNotify finalize);
/**
* callback_ref
*
* Increments the reference count. That prevents the object from being
* deleted before you drop this reference. The caller makes sure that
* argument is not NULL.
*/
void (*callback_ref)(GBinderEventLoopCallback* cb);
/**
* callback_unref
*
* Decrements the reference count (drops the reference). When reference
* count reaches zero, the object gets deleted. The caller makes sure
* that argument is not NULL.
*
* Note that calling callback_schedule temporarily adds an internal
* reference until the callback is invoked or callback_cancel is called,
* whichever happens first.
*/
void (*callback_unref)(GBinderEventLoopCallback* cb);
/**
* callback_schedule
*
* Schedules the callback to be invoked in the main loop at some point
* in the future (but as soon as possible). The caller makes sure that
* argument is not NULL.
*
* This adds an internal reference to the GBinderEventLoopCallback object
* until the callback is invoked or callback_cancel is called, whichever
* happens first.
*/
void (*callback_schedule)(GBinderEventLoopCallback* cb);
/**
* callback_cancel
*
* Makes sure that callback won't be invoked (if it hasn't been
* invoked yet) and drops the internal reference. Does nothing
* if the callback has already been invoked. The caller makes sure that
* argument is not NULL.
*/
void (*callback_cancel)(GBinderEventLoopCallback* cb);
/**
* cleanup
*
* This function is called when event loop integration is being replaced
* with a different one, or libgbinder is being unloaded.
*/
void (*cleanup)(void);
/* Padding for future expansion */
void (*_reserved1)(void);
void (*_reserved2)(void);
void (*_reserved3)(void);
void (*_reserved4)(void);
void (*_reserved5)(void);
void (*_reserved6)(void);
void (*_reserved7)(void);
void (*_reserved8)(void);
void (*_reserved9)(void);
/*
* api_level will remain zero (and ignored) until we run out of
* the above placeholders. Hopefully, forever.
*/
int api_level;
} GBinderEventLoopIntegration;
/**
* gbinder_eventloop_set should be called before libgbinder creates any of
* its internal threads. And it must be done from the main thread.
*/
void
gbinder_eventloop_set(
const GBinderEventLoopIntegration* loop);
G_END_DECLS
#endif /* GBINDER_EVENTLOOP_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

154
include/gbinder_fmq.h Normal file
View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-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 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:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -53,7 +53,7 @@ struct gbinder_reader {
gboolean
gbinder_reader_at_end(
GBinderReader* reader);
const GBinderReader* reader);
gboolean
gbinder_reader_read_byte(
@@ -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,
@@ -95,6 +115,15 @@ gbinder_reader_read_double(
GBinderReader* reader,
gdouble* value);
int
gbinder_reader_read_fd(
GBinderReader* reader); /* Since 1.0.18 */
int
gbinder_reader_read_dup_fd(
GBinderReader* reader) /* Since 1.0.18 */
G_GNUC_WARN_UNUSED_RESULT;
gboolean
gbinder_reader_read_nullable_object(
GBinderReader* reader,
@@ -113,11 +142,48 @@ 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,
gsize size); /* Since 1.0.9 */
#define gbinder_reader_read_hidl_struct(reader,type) \
((const type*)gbinder_reader_read_hidl_struct1(reader, sizeof(type)))
const void*
gbinder_reader_read_hidl_vec(
GBinderReader* reader,
gsize* count,
gsize* elemsize);
const void*
gbinder_reader_read_hidl_vec1(
GBinderReader* reader,
gsize* count,
guint expected_elemsize); /* Since 1.0.9 */
#define gbinder_reader_read_hidl_type_vec(reader,type,count) \
((const type*)gbinder_reader_read_hidl_vec1(reader, count, sizeof(type)))
#define gbinder_reader_read_hidl_byte_vec(reader,count) /* vec<uint8_t> */ \
gbinder_reader_read_hidl_type_vec(reader,guint8,count)
char*
gbinder_reader_read_hidl_string(
GBinderReader* reader)
G_GNUC_WARN_UNUSED_RESULT;
const char*
gbinder_reader_read_hidl_string_c(
GBinderReader* reader); /* Since 1.0.23 */
#define gbinder_reader_skip_hidl_string(reader) \
(gbinder_reader_read_hidl_string_c(reader) != NULL)
char**
gbinder_reader_read_hidl_string_vec(
GBinderReader* reader);
@@ -140,17 +206,43 @@ gbinder_reader_read_nullable_string16(
GBinderReader* reader,
char** out);
gboolean
gbinder_reader_read_nullable_string16_utf16(
GBinderReader* reader,
const gunichar2** out,
gsize* len); /* Since 1.0.17 */
const gunichar2*
gbinder_reader_read_string16_utf16(
GBinderReader* reader,
gsize* len); /* Since 1.0.26 */
gboolean
gbinder_reader_skip_string16(
GBinderReader* reader);
const void*
gbinder_reader_read_byte_array(
GBinderReader* reader,
gsize* len); /* Since 1.0.12 */
const void*
gbinder_reader_get_data(
const GBinderReader* reader,
gsize* size); /* Since 1.1.14 */
gsize
gbinder_reader_bytes_read(
GBinderReader* reader);
const GBinderReader* reader);
gsize
gbinder_reader_bytes_remaining(
GBinderReader* reader);
const GBinderReader* reader);
void
gbinder_reader_copy(
GBinderReader* dest,
const GBinderReader* src); /* Since 1.0.16 */
G_END_DECLS

View File

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

View File

@@ -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
@@ -50,6 +50,11 @@ gbinder_remote_reply_init_reader(
GBinderRemoteReply* reply,
GBinderReader* reader);
GBinderLocalReply*
gbinder_remote_reply_copy_to_local(
GBinderRemoteReply* reply) /* since 1.0.6 */
G_GNUC_WARN_UNUSED_RESULT;
/* Convenience function to decode replies with just one data item */
gboolean

View File

@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -62,6 +62,21 @@ uid_t
gbinder_remote_request_sender_euid(
GBinderRemoteRequest* req); /* since 1.0.2 */
GBinderLocalRequest*
gbinder_remote_request_copy_to_local(
GBinderRemoteRequest* req) /* since 1.0.6 */
G_GNUC_WARN_UNUSED_RESULT;
void
gbinder_remote_request_block(
GBinderRemoteRequest* req); /* Since 1.0.20 */
void
gbinder_remote_request_complete(
GBinderRemoteRequest* req,
GBinderLocalReply* reply,
int status); /* Since 1.0.20 */
/* Convenience function to decode requests with just one data item */
gboolean

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:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -37,6 +37,12 @@
G_BEGIN_DECLS
typedef
void
(*GBinderServiceManagerFunc)(
GBinderServiceManager* sm,
void* user_data);
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
* list, otherwise the caller will deallocate it. */
typedef
@@ -61,24 +67,42 @@ void
int status,
void* user_data);
typedef
void
(*GBinderServiceManagerRegistrationFunc)(
GBinderServiceManager* sm,
const char* name,
void* user_data);
GBinderServiceManager*
gbinder_servicemanager_new(
const char* dev);
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev);
const char* dev)
G_DEPRECATED_FOR(gbinder_servicemanager_new);
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev);
const char* dev)
G_DEPRECATED_FOR(gbinder_servicemanager_new);
GBinderLocalObject*
gbinder_servicemanager_new_local_object(
GBinderServiceManager* sm,
const char* iface,
GBinderLocalTransactFunc handler,
void* user_data);
void* user_data)
G_GNUC_WARN_UNUSED_RESULT;
GBinderLocalObject*
gbinder_servicemanager_new_local_object2(
GBinderServiceManager* sm,
const char* const* ifaces,
GBinderLocalTransactFunc handler,
void* user_data) /* Since 1.0.29 */
G_GNUC_WARN_UNUSED_RESULT;
GBinderServiceManager*
gbinder_servicemanager_ref(
@@ -88,6 +112,19 @@ 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 */
gboolean
gbinder_servicemanager_wait(
GBinderServiceManager* sm,
long max_wait_ms); /* Since 1.0.25 */
gulong
gbinder_servicemanager_list(
GBinderServiceManager* sm,
@@ -96,7 +133,9 @@ gbinder_servicemanager_list(
char**
gbinder_servicemanager_list_sync(
GBinderServiceManager* sm);
GBinderServiceManager* sm)
G_GNUC_WARN_UNUSED_RESULT
G_GNUC_MALLOC;
gulong
gbinder_servicemanager_get_service(
@@ -130,6 +169,33 @@ gbinder_servicemanager_cancel(
GBinderServiceManager* sm,
gulong id);
gulong
gbinder_servicemanager_add_presence_handler(
GBinderServiceManager* sm,
GBinderServiceManagerFunc func,
void* user_data); /* Since 1.0.25 */
gulong
gbinder_servicemanager_add_registration_handler(
GBinderServiceManager* sm,
const char* name,
GBinderServiceManagerRegistrationFunc func,
void* user_data); /* Since 1.0.13 */
void
gbinder_servicemanager_remove_handler(
GBinderServiceManager* sm,
gulong id); /* Since 1.0.13 */
void
gbinder_servicemanager_remove_handlers(
GBinderServiceManager* sm,
gulong* ids,
guint count); /* Since 1.0.25 */
#define gbinder_servicemanager_remove_all_handlers(sm,ids) \
gbinder_servicemanager_remove_handlers(sm, ids, G_N_ELEMENTS(ids))
G_END_DECLS
#endif /* GBINDER_SERVICEMANAGER_H */

View File

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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -59,8 +59,11 @@ 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;
typedef struct gbinder_local_request GBinderLocalRequest;
@@ -68,10 +71,80 @@ typedef struct gbinder_reader GBinderReader;
typedef struct gbinder_remote_object GBinderRemoteObject;
typedef struct gbinder_remote_reply GBinderRemoteReply;
typedef struct gbinder_remote_request GBinderRemoteRequest;
typedef struct gbinder_servicename GBinderServiceName;
typedef struct gbinder_servicemanager GBinderServiceManager;
typedef struct gbinder_writer GBinderWriter;
typedef struct gbinder_parent GBinderParent;
/* Basic HIDL types */
#define GBINDER_ALIGNED(x) __attribute__ ((aligned(x)))
typedef struct gbinder_hidl_vec {
union {
guint64 value;
const void* ptr;
} data;
guint32 count;
guint8 owns_buffer;
guint8 pad[3];
} GBinderHidlVec;
#define GBINDER_HIDL_VEC_BUFFER_OFFSET (0)
G_STATIC_ASSERT(sizeof(GBinderHidlVec) == 16);
typedef struct gbinder_hidl_string {
union {
guint64 value;
const char* str;
} data;
guint32 len;
guint8 owns_buffer;
guint8 pad[3];
} GBinderHidlString;
#define GBINDER_HIDL_STRING_BUFFER_OFFSET (0)
G_STATIC_ASSERT(sizeof(GBinderHidlString) == 16);
typedef struct gbinder_fds {
guint32 version GBINDER_ALIGNED(4);
guint32 num_fds GBINDER_ALIGNED(4);
guint32 num_ints GBINDER_ALIGNED(4);
} GBINDER_ALIGNED(4) GBinderFds; /* Since 1.1.4 */
/* Actual fds immediately follow GBinderFds: */
#define gbinder_fds_get_fd(fds,i) (((const int*)((fds) + 1))[i])
#define GBINDER_HIDL_FDS_VERSION (12)
G_STATIC_ASSERT(sizeof(GBinderFds) == GBINDER_HIDL_FDS_VERSION);
typedef struct gbinder_hidl_handle {
union {
guint64 value;
const GBinderFds* fds;
} data;
guint8 owns_handle;
guint8 pad[7];
} GBinderHidlHandle; /* Since 1.1.4 */
#define GBINDER_HIDL_HANDLE_VALUE_OFFSET (0)
G_STATIC_ASSERT(sizeof(GBinderHidlHandle) == 16);
typedef struct gbinder_hidl_memory {
union {
guint64 value;
const GBinderFds* fds;
} data;
guint8 owns_buffer;
guint8 pad[7];
guint64 size;
GBinderHidlString name;
} GBinderHidlMemory; /* Since 1.1.4 */
#define GBINDER_HIDL_MEMORY_PTR_OFFSET (0)
#define GBINDER_HIDL_MEMORY_NAME_OFFSET (24)
G_STATIC_ASSERT(sizeof(GBinderHidlMemory) == 40);
/*
* Each RPC call is identified by the interface name returned
* by gbinder_remote_request_interface() the transaction code.

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:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -55,6 +55,16 @@ struct gbinder_parent {
guint32 offset;
};
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,
@@ -86,6 +96,12 @@ gbinder_writer_append_string16_len(
const char* utf8,
gssize num_bytes);
void
gbinder_writer_append_string16_utf16(
GBinderWriter* writer,
const gunichar2* utf16,
gssize length); /* Since 1.0.17 */
void
gbinder_writer_append_string8(
GBinderWriter* writer,
@@ -108,6 +124,17 @@ gbinder_writer_append_bytes(
const void* data,
gsize size);
void
gbinder_writer_append_fd(
GBinderWriter* writer,
int fd); /* Since 1.0.18 */
void
gbinder_writer_append_fds(
GBinderWriter* writer,
const GBinderFds* fds,
const GBinderParent* parent); /* Since 1.1.14 */
guint
gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* writer,
@@ -121,11 +148,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 */
void
gbinder_writer_append_hidl_string(
GBinderWriter* writer,
const char* str);
void
gbinder_writer_append_hidl_string_copy(
GBinderWriter* writer,
const char* str); /* Since 1.1.13 */
void
gbinder_writer_append_hidl_string_vec(
GBinderWriter* writer,
@@ -142,6 +187,67 @@ gbinder_writer_append_remote_object(
GBinderWriter* writer,
GBinderRemoteObject* obj);
void
gbinder_writer_append_byte_array(
GBinderWriter* writer,
const void* byte_array,
gint32 len); /* Since 1.0.12 */
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 */
void*
gbinder_writer_malloc0(
GBinderWriter* writer,
gsize size); /* Since 1.0.19 */
#define gbinder_writer_new(writer,type) \
((type*) gbinder_writer_malloc(writer, sizeof(type)))
#define gbinder_writer_new0(writer,type) \
((type*) gbinder_writer_malloc0(writer, sizeof(type)))
void
gbinder_writer_add_cleanup(
GBinderWriter* writer,
GDestroyNotify destroy,
gpointer data); /* Since 1.0.19 */
void*
gbinder_writer_memdup(
GBinderWriter* writer,
const void* buf,
gsize size); /* Since 1.0.19 */
char*
gbinder_writer_strdup(
GBinderWriter* writer,
const char* str); /* Since 1.1.13 */
G_END_DECLS
#endif /* GBINDER_WRITER_H */

View File

@@ -1,10 +1,10 @@
name=gbinder
libdir=/usr/lib
libdir=@libdir@
includedir=/usr/include
Name: libgbinder
Description: Binder client library
Version: [version]
Requires: glib-2.0 libglibutil
Version: @version@
Requires.private: glib-2.0 libglibutil
Libs: -L${libdir} -l${name}
Cflags: -I${includedir} -I${includedir}/${name}

View File

@@ -1,14 +1,25 @@
Name: libgbinder
Version: 1.0.5
Version: 1.1.19
Release: 0
Summary: Binder client library
Group: Development/Libraries
License: BSD
URL: https://github.com/mer-hybris/libgbinder
Source: %{name}-%{version}.tar.bz2
Requires: libglibutil >= 1.0.29
%define libglibutil_version 1.0.52
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libglibutil) >= 1.0.29
BuildRequires: pkgconfig(libglibutil) >= %{libglibutil_version}
BuildRequires: pkgconfig
BuildRequires: bison
BuildRequires: flex
# license macro requires rpm >= 4.11
BuildRequires: pkgconfig(rpm)
%define license_support %(pkg-config --exists 'rpm >= 4.11'; echo $?)
Requires: libglibutil >= %{libglibutil_version}
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
@@ -18,7 +29,6 @@ C interfaces for Android binder
%package devel
Summary: Development library for %{name}
Requires: %{name} = %{version}
Requires: pkgconfig
%description devel
This package contains the development library for %{name}.
@@ -27,11 +37,19 @@ This package contains the development library for %{name}.
%setup -q
%build
make KEEP_SYMBOLS=1 release pkgconfig
make %{_smp_mflags} LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig
make -C test/binder-bridge KEEP_SYMBOLS=1 release
make -C test/binder-list KEEP_SYMBOLS=1 release
make -C test/binder-ping KEEP_SYMBOLS=1 release
make -C test/binder-call KEEP_SYMBOLS=1 release
%install
rm -rf %{buildroot}
make install-dev DESTDIR=%{buildroot}
make LIBDIR=%{_libdir} DESTDIR=%{buildroot} install-dev
make -C test/binder-bridge DESTDIR=%{buildroot} install
make -C test/binder-list DESTDIR=%{buildroot} install
make -C test/binder-ping DESTDIR=%{buildroot} install
make -C test/binder-call DESTDIR=%{buildroot} install
%check
make -C unit test
@@ -43,9 +61,28 @@ make -C unit test
%files
%defattr(-,root,root,-)
%{_libdir}/%{name}.so.*
%if %{license_support} == 0
%license LICENSE
%endif
%files devel
%defattr(-,root,root,-)
%{_libdir}/pkgconfig/*.pc
%{_libdir}/%{name}.so
%{_includedir}/gbinder/*.h
# Tools
%package tools
Summary: Binder tools
Requires: %{name} >= %{version}
%description tools
Binder command line utilities
%files tools
%defattr(-,root,root,-)
%{_bindir}/binder-bridge
%{_bindir}/binder-list
%{_bindir}/binder-ping
%{_bindir}/binder-call

272
src/gbinder_bridge.c Normal file
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-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
@@ -36,55 +36,62 @@
#include <gutil_macros.h>
typedef struct gbinder_buffer_memory {
struct gbinder_buffer_contents {
gint refcount;
void* buffer;
gsize size;
void** objects;
GBinderDriver* driver;
} GBinderBufferMemory;
};
typedef struct gbinder_buffer_priv {
GBinderBuffer pub;
GBinderBufferMemory* memory;
GBinderBufferContents* contents;
} GBinderBufferPriv;
static inline GBinderBufferPriv* gbinder_buffer_cast(GBinderBuffer* buf)
{ return G_CAST(buf, GBinderBufferPriv, pub); }
/*==========================================================================*
* GBinderBufferMemory
* GBinderBufferContents
*==========================================================================*/
static
GBinderBufferMemory*
gbinder_buffer_memory_new(
GBinderBufferContents*
gbinder_buffer_contents_new(
GBinderDriver* driver,
void* buffer,
gsize size)
gsize size,
void** objects)
{
GBinderBufferMemory* self = g_slice_new0(GBinderBufferMemory);
GBinderBufferContents* self = g_slice_new0(GBinderBufferContents);
g_atomic_int_set(&self->refcount, 1);
self->buffer = buffer;
self->size = size;
self->objects = objects;
self->driver = gbinder_driver_ref(driver);
return self;
}
static
void
gbinder_buffer_memory_free(
GBinderBufferMemory* self)
gbinder_buffer_contents_free(
GBinderBufferContents* self)
{
if (self->objects) {
gbinder_driver_close_fds(self->driver, self->objects,
((guint8*)self->buffer) + self->size);
g_free(self->objects);
}
gbinder_driver_free_buffer(self->driver, self->buffer);
gbinder_driver_unref(self->driver);
g_slice_free(GBinderBufferMemory, self);
g_slice_free(GBinderBufferContents, self);
}
static
GBinderBufferMemory*
gbinder_buffer_memory_ref(
GBinderBufferMemory* self)
GBinderBufferContents*
gbinder_buffer_contents_ref(
GBinderBufferContents* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
@@ -93,19 +100,59 @@ gbinder_buffer_memory_ref(
return self;
}
static
void
gbinder_buffer_memory_unref(
GBinderBufferMemory* self)
gbinder_buffer_contents_unref(
GBinderBufferContents* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_buffer_memory_free(self);
gbinder_buffer_contents_free(self);
}
}
}
/*==========================================================================*
* GBinderBufferContentsList
* It's actually a GSList containing GBinderBufferContents refs.
*==========================================================================*/
GBinderBufferContentsList*
gbinder_buffer_contents_list_add(
GBinderBufferContentsList* list,
GBinderBufferContents* contents)
{
/* Prepend rather than append for better efficiency */
return contents ? (GBinderBufferContentsList*) g_slist_prepend((GSList*)
list, gbinder_buffer_contents_ref(contents)) : list;
}
GBinderBufferContentsList*
gbinder_buffer_contents_list_dup(
GBinderBufferContentsList* list)
{
GSList* out = NULL;
if (list) {
GSList* l = (GSList*) list;
/* The order gets reversed but it doesn't matter */
while (l) {
out = g_slist_prepend(out, gbinder_buffer_contents_ref(l->data));
l = l->next;
}
}
return (GBinderBufferContentsList*) out;
}
void
gbinder_buffer_contents_list_free(
GBinderBufferContentsList* list)
{
g_slist_free_full((GSList*) list, (GDestroyNotify)
gbinder_buffer_contents_unref);
}
/*==========================================================================*
* GBinderBuffer
*==========================================================================*/
@@ -113,14 +160,14 @@ gbinder_buffer_memory_unref(
static
GBinderBuffer*
gbinder_buffer_alloc(
GBinderBufferMemory* memory,
GBinderBufferContents* contents,
void* data,
gsize size)
{
GBinderBufferPriv* priv = g_slice_new0(GBinderBufferPriv);
GBinderBuffer* self = &priv->pub;
priv->memory = memory;
priv->contents = contents;
self->data = data;
self->size = size;
return self;
@@ -133,7 +180,7 @@ gbinder_buffer_free(
if (G_LIKELY(self)) {
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
gbinder_buffer_memory_unref(priv->memory);
gbinder_buffer_contents_unref(priv->contents);
g_slice_free(GBinderBufferPriv, priv);
}
}
@@ -142,10 +189,12 @@ GBinderBuffer*
gbinder_buffer_new(
GBinderDriver* driver,
void* data,
gsize size)
gsize size,
void** objects)
{
return gbinder_buffer_alloc((driver && data) ?
gbinder_buffer_memory_new(driver, data, size) : NULL, data, size);
gbinder_buffer_contents_new(driver, data, size, objects) : NULL,
data, size);
}
GBinderBuffer*
@@ -155,10 +204,30 @@ gbinder_buffer_new_with_parent(
gsize size)
{
return gbinder_buffer_alloc(parent ?
gbinder_buffer_memory_ref(gbinder_buffer_cast(parent)->memory) : NULL,
gbinder_buffer_contents_ref(gbinder_buffer_contents(parent)) : NULL,
data, size);
}
gconstpointer
gbinder_buffer_data(
GBinderBuffer* self,
gsize* size)
{
GBinderBufferContents* contents = gbinder_buffer_contents(self);
if (G_LIKELY(contents)) {
if (size) {
*size = contents->size;
}
return contents->buffer;
} else {
if (size) {
*size = 0;
}
return NULL;
}
}
GBinderDriver*
gbinder_buffer_driver(
GBinderBuffer* self)
@@ -166,13 +235,43 @@ gbinder_buffer_driver(
if (G_LIKELY(self)) {
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
if (priv->memory) {
return priv->memory->driver;
if (priv->contents) {
return priv->contents->driver;
}
}
return NULL;
}
const GBinderIo*
gbinder_buffer_io(
GBinderBuffer* buf)
{
GBinderDriver* driver = gbinder_buffer_driver(buf);
return driver ? gbinder_driver_io(driver) : NULL;
}
void**
gbinder_buffer_objects(
GBinderBuffer* self)
{
if (G_LIKELY(self)) {
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
if (priv->contents) {
return priv->contents->objects;
}
}
return NULL;
}
GBinderBufferContents*
gbinder_buffer_contents(
GBinderBuffer* self)
{
return G_LIKELY(self) ? gbinder_buffer_cast(self)->contents : NULL;
}
/*
* Local Variables:
* mode: C

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -41,20 +41,68 @@ GBinderBuffer*
gbinder_buffer_new(
GBinderDriver* driver,
void* data,
gsize size);
gsize size,
void** objects)
GBINDER_INTERNAL;
GBinderBuffer*
gbinder_buffer_new_with_parent(
GBinderBuffer* parent,
void* data,
gsize size);
gsize size)
GBINDER_INTERNAL;
GBinderDriver*
gbinder_buffer_driver(
GBinderBuffer* buf);
GBinderBuffer* buf)
GBINDER_INTERNAL;
#define gbinder_buffer_io(buf) \
gbinder_driver_io(gbinder_buffer_driver(buf))
GBinderBufferContents*
gbinder_buffer_contents(
GBinderBuffer* buf)
GBINDER_INTERNAL;
gconstpointer
gbinder_buffer_data(
GBinderBuffer* buf,
gsize* size)
GBINDER_INTERNAL;
const GBinderIo*
gbinder_buffer_io(
GBinderBuffer* buf)
GBINDER_INTERNAL;
void**
gbinder_buffer_objects(
GBinderBuffer* buffer)
GBINDER_INTERNAL;
GBinderBufferContents*
gbinder_buffer_contents_ref(
GBinderBufferContents* contents)
GBINDER_INTERNAL;
void
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

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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -37,13 +37,20 @@
void
gbinder_cleanup_free(
GBinderCleanup* cleanup);
GBinderCleanup* cleanup)
GBINDER_INTERNAL;
void
gbinder_cleanup_reset(
GBinderCleanup* cleanup)
GBINDER_INTERNAL;
GBinderCleanup*
gbinder_cleanup_add(
GBinderCleanup* cleanup,
GDestroyNotify destroy,
gpointer pointer);
gpointer pointer)
GBINDER_INTERNAL;
#endif /* GBINDER_CLEANUP_H */

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
@@ -41,14 +41,22 @@
#include <gutil_macros.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
typedef struct gbinder_client_iface_range {
char* iface;
GBytes* rpc_header;
GBinderLocalRequest* basic_req;
guint32 last_code;
} GBinderClientIfaceRange;
typedef struct gbinder_client_priv {
GBinderClient pub;
guint32 refcount;
char* iface;
GBytes* rpc_header;
GBinderLocalRequest* basic_req;
GBinderClientIfaceRange* ranges;
guint nr;
} GBinderClientPriv;
typedef struct gbinder_client_tx {
@@ -65,17 +73,79 @@ static inline GBinderClientPriv* gbinder_client_cast(GBinderClient* client)
* Implementation
*==========================================================================*/
static
const GBinderClientIfaceRange*
gbinder_client_find_range(
GBinderClientPriv* priv,
guint32 code)
{
guint i;
for (i = 0; i < priv->nr; i++) {
const GBinderClientIfaceRange* r = priv->ranges + i;
if (r->last_code >= code) {
return r;
}
}
return NULL;
}
/*
* Generates basic request (without additional parameters) for the
* specified interface and pulls header data out of it. The basic
* request can be reused for those transactions which have no
* additional parameters. The header data are needed for building
* non-trivial requests.
*/
static
void
gbinder_client_init_range(
GBinderClientIfaceRange* r,
GBinderDriver* driver,
const GBinderClientIfaceInfo* info)
{
GBinderOutputData* hdr;
r->basic_req = gbinder_driver_local_request_new(driver, info->iface);
hdr = gbinder_local_request_data(r->basic_req);
r->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
r->iface = g_strdup(info->iface);
r->last_code = info->last_code;
}
static
int
gbinder_client_sort_ranges(
const void* p1,
const void* p2)
{
const GBinderClientIfaceRange* r1 = p1;
const GBinderClientIfaceRange* r2 = p2;
return (r1->last_code < r2->last_code) ? (-1) :
(r1->last_code > r2->last_code) ? 1 : 0;
}
static
void
gbinder_client_free(
GBinderClientPriv* priv)
{
GBinderClient* self = &priv->pub;
guint i;
for (i = 0; i < priv->nr; i++) {
GBinderClientIfaceRange* r = priv->ranges + i;
gbinder_local_request_unref(r->basic_req);
g_free(r->iface);
if (r->rpc_header) {
g_bytes_unref(r->rpc_header);
}
}
g_free(priv->ranges);
gbinder_remote_object_unref(self->remote);
gbinder_local_request_unref(priv->basic_req);
g_free(priv->iface);
g_bytes_unref(priv->rpc_header);
g_slice_free(GBinderClientPriv, priv);
}
@@ -108,38 +178,127 @@ gbinder_client_transact_destroy(
g_slice_free(GBinderClientTx, tx);
}
/*==========================================================================*
* Internal interface
*==========================================================================*/
GBinderRemoteReply*
gbinder_client_transact_sync_reply2(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
int* status,
const GBinderIpcSyncApi* api)
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
if (r) {
req = r->basic_req;
}
}
if (req) {
return api->sync_reply(obj->ipc, obj->handle, code, req,
status);
} else {
GWARN("Unable to build empty request for tx code %u", code);
}
} else {
GDEBUG("Refusing to perform transaction with a dead object");
}
}
return NULL;
}
int
gbinder_client_transact_sync_oneway2(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
const GBinderIpcSyncApi* api)
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
/* Default empty request (just the header, no parameters) */
if (r) {
req = r->basic_req;
}
}
if (req) {
return api->sync_oneway(obj->ipc, obj->handle, code, req);
} else {
GWARN("Unable to build empty request for tx code %u", code);
}
} else {
GDEBUG("Refusing to perform transaction with a dead object");
return (-ESTALE);
}
}
return (-EINVAL);
}
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderClient*
gbinder_client_new2(
GBinderRemoteObject* remote,
const GBinderClientIfaceInfo* ifaces,
gsize count)
{
if (G_LIKELY(remote)) {
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
GBinderClient* self = &priv->pub;
GBinderDriver* driver = remote->ipc->driver;
g_atomic_int_set(&priv->refcount, 1);
self->remote = gbinder_remote_object_ref(remote);
if (count > 0) {
gsize i;
priv->nr = count;
priv->ranges = g_new(GBinderClientIfaceRange, priv->nr);
for (i = 0; i < count; i++) {
gbinder_client_init_range(priv->ranges + i, driver, ifaces + i);
}
qsort(priv->ranges, count, sizeof(GBinderClientIfaceRange),
gbinder_client_sort_ranges);
} else {
/* No interface info */
priv->nr = 1;
priv->ranges = g_new0(GBinderClientIfaceRange, 1);
priv->ranges[0].last_code = UINT_MAX;
priv->ranges[0].basic_req = gbinder_local_request_new
(gbinder_driver_io(driver), NULL);
}
return self;
}
return NULL;
}
GBinderClient*
gbinder_client_new(
GBinderRemoteObject* remote,
const char* iface)
{
if (G_LIKELY(remote) && G_LIKELY(iface)) {
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
GBinderClient* self = &priv->pub;
GBinderIpc* ipc = remote->ipc;
GBinderOutputData* hdr;
GBinderClientIfaceInfo info;
g_atomic_int_set(&priv->refcount, 1);
/*
* Generate basic request (without additional parameters) and pull
* header data out of it. The basic request can be reused for those
* transactions which has no additional parameters. The header data
* are needed for building non-trivial requests.
*/
priv->basic_req = gbinder_driver_local_request_new(ipc->driver, iface);
hdr = gbinder_local_request_data(priv->basic_req);
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
self->remote = gbinder_remote_object_ref(remote);
self->iface = priv->iface = g_strdup(iface);
return self;
}
return NULL;
info.iface = iface;
info.last_code = UINT_MAX;
return gbinder_client_new2(remote, &info, 1);
}
GBinderClient*
@@ -169,6 +328,45 @@ gbinder_client_unref(
}
}
const char*
gbinder_client_interface(
GBinderClient* self) /* since 1.0.22 */
{
return G_LIKELY(self) ? gbinder_client_cast(self)->ranges->iface : NULL;
}
const char*
gbinder_client_interface2(
GBinderClient* self,
guint32 code) /* since 1.0.42 */
{
if (G_LIKELY(self)) {
const GBinderClientIfaceRange* r =
gbinder_client_find_range(gbinder_client_cast(self), code);
if (r) {
return r->iface;
}
}
return NULL;
}
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)
@@ -176,7 +374,27 @@ gbinder_client_new_request(
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
const GBinderIo* io = gbinder_driver_io(self->remote->ipc->driver);
return gbinder_local_request_new(io, priv->rpc_header);
return gbinder_local_request_new(io, priv->ranges->rpc_header);
}
return NULL;
}
GBinderLocalRequest*
gbinder_client_new_request2(
GBinderClient* self,
guint32 code) /* since 1.0.42 */
{
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
const GBinderClientIfaceRange* r = gbinder_client_find_range
(priv, code);
if (r) {
const GBinderIo* io = gbinder_driver_io(self->remote->ipc->driver);
return gbinder_local_request_new(io, r->rpc_header);
}
}
return NULL;
}
@@ -188,17 +406,8 @@ gbinder_client_transact_sync_reply(
GBinderLocalRequest* req,
int* status)
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
}
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
code, req, status);
}
return NULL;
return gbinder_client_transact_sync_reply2(self, code, req, status,
&gbinder_ipc_sync_main);
}
int
@@ -207,18 +416,8 @@ gbinder_client_transact_sync_oneway(
guint32 code,
GBinderLocalRequest* req)
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
}
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
code, req);
} else {
return (-EINVAL);
}
return gbinder_client_transact_sync_oneway2(self, code, req,
&gbinder_ipc_sync_main);
}
gulong
@@ -233,23 +432,35 @@ gbinder_client_transact(
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
tx->client = gbinder_client_ref(self);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
if (G_LIKELY(!obj->dead)) {
if (!req) {
const GBinderClientIfaceRange* r = gbinder_client_find_range
(gbinder_client_cast(self), code);
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
/* Default empty request (just the header, no parameters) */
if (r) {
req = r->basic_req;
}
}
if (req) {
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
tx->client = gbinder_client_ref(self);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
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");
}
return gbinder_ipc_transact(obj->ipc, obj->handle, code, flags, req,
gbinder_client_transact_reply, gbinder_client_transact_destroy, tx);
} else {
return 0;
}
return 0;
}
void

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
@@ -38,10 +38,27 @@
#include "gbinder_types_p.h"
struct gbinder_client {
const char* iface;
GBinderRemoteObject* remote;
};
GBinderRemoteReply*
gbinder_client_transact_sync_reply2(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
int* status,
const GBinderIpcSyncApi* api)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
int
gbinder_client_transact_sync_oneway2(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
const GBinderIpcSyncApi* api)
GBINDER_INTERNAL;
#define gbinder_client_ipc(client) ((client)->remote->ipc)
#endif /* GBINDER_CLIENT_PRIVATE_H */

405
src/gbinder_config.c Normal file
View File

@@ -0,0 +1,405 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_config.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_log.h"
#include <gutil_strv.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/*
* The contents of the config file is queried from (at least) two places,
* and pretty much always this happens the same stack. Which means that
* we can avoid reading the same file twice if we delay dereferencing of
* GKeyFile until the next idle loop.
*/
static GKeyFile* gbinder_config_keyfile = NULL;
static GBinderEventLoopCallback* gbinder_config_autorelease = NULL;
static const char gbinder_config_suffix[] = ".conf";
static const char gbinder_config_default_file[] = "/etc/gbinder.conf";
static const char gbinder_config_default_dir[] = "/etc/gbinder.d";
const char* gbinder_config_file = gbinder_config_default_file;
const char* gbinder_config_dir = gbinder_config_default_dir;
/*
* Presets for particular API level can be chosen with ApiLevel
* setting, e.g.
*
* [General]
* ApiLevel=29
*
*/
static const char CONF_GENERAL[] = "General";
static const char CONG_API_LEVEL[] = "ApiLevel";
typedef struct gbinder_config_preset_entry {
const char* key;
const char* value;
} GBinderConfigPresetEntry;
typedef struct gbinder_config_preset_group {
const char* name;
const GBinderConfigPresetEntry* entries;
} GBinderConfigPresetGroup;
typedef struct gbinder_config_preset {
guint api_level;
const GBinderConfigPresetGroup* groups;
} GBinderConfigPreset;
/* API level 28 */
static const GBinderConfigPresetEntry gbinder_config_28_servicemanager[] = {
{ "/dev/binder", "aidl2" },
{ "/dev/vndbinder", "aidl2" },
{ NULL, NULL }
};
static const GBinderConfigPresetGroup gbinder_config_28[] = {
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_28_servicemanager },
{ NULL, NULL }
};
/* API level 29 */
static const GBinderConfigPresetEntry gbinder_config_29_protocol[] = {
{ "/dev/binder", "aidl2" },
{ "/dev/vndbinder", "aidl2" },
{ NULL, NULL }
};
#define gbinder_config_29_servicemanager gbinder_config_28_servicemanager
static const GBinderConfigPresetGroup gbinder_config_29[] = {
{ GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_29_protocol },
{ GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_29_servicemanager },
{ NULL, NULL }
};
/* 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 }
};
/* Presets sorted by API level in descending order */
static const GBinderConfigPreset gbinder_config_presets[] = {
{ 30, gbinder_config_30 },
{ 29, gbinder_config_29 },
{ 28, gbinder_config_28 }
};
static
char**
gbinder_config_collect_files(
const char* path,
const char* suffix)
{
/*
* Returns sorted list of regular files in the directory,
* optionally having the specified suffix (e.g. ".conf").
* Returns NULL if nothing appropriate has been found.
*/
char** files = NULL;
if (path) {
GDir* dir = g_dir_open(path, 0, NULL);
if (dir) {
GPtrArray* list = g_ptr_array_new();
const gchar* name;
while ((name = g_dir_read_name(dir)) != NULL) {
if (g_str_has_suffix(name, suffix)) {
char* fullname = g_build_filename(path, name, NULL);
struct stat st;
if (!stat(fullname, &st) && S_ISREG(st.st_mode)) {
g_ptr_array_add(list, fullname);
} else {
g_free(fullname);
}
}
}
if (list->len > 0) {
g_ptr_array_add(list, NULL);
files = (char**) g_ptr_array_free(list, FALSE);
gutil_strv_sort(files, TRUE);
} else {
g_ptr_array_free(list, TRUE);
}
g_dir_close(dir);
}
}
return files;
}
static
GKeyFile*
gbinder_config_merge_keyfiles(
GKeyFile* dest,
GKeyFile* src)
{
gsize i, ngroups;
gchar** groups = g_key_file_get_groups(src, &ngroups);
for (i = 0; i < ngroups; i++) {
gsize k, nkeys;
const char* group = groups[i];
char** keys = g_key_file_get_keys(src, group, &nkeys, NULL);
for (k = 0; k < nkeys; k++) {
const char* key = keys[k];
char* value = g_key_file_get_value(src, group, key, NULL);
g_key_file_set_value(dest, group, key, value);
g_free(value);
}
g_strfreev(keys);
}
g_strfreev(groups);
return dest;
}
static
void
gbinder_config_apply_presets(
GKeyFile* config,
const GBinderConfigPreset* preset)
{
const GBinderConfigPresetGroup* g;
GDEBUG("Applying presets for API level %d", preset->api_level);
for (g = preset->groups; g->name; g++) {
const GBinderConfigPresetEntry* e;
for (e = g->entries; e->key; e++) {
if (!g_key_file_has_key(config, g->name, e->key, NULL)) {
g_key_file_set_value(config, g->name, e->key, e->value);
}
}
}
}
static
GKeyFile*
gbinder_config_load_files()
{
GError* error = NULL;
GKeyFile* out = NULL;
char** files = gbinder_config_collect_files(gbinder_config_dir,
gbinder_config_suffix);
if (gbinder_config_file &&
g_file_test(gbinder_config_file, G_FILE_TEST_EXISTS)) {
out = g_key_file_new();
if (g_key_file_load_from_file(out, gbinder_config_file,
G_KEY_FILE_NONE, &error)) {
GDEBUG("Loaded %s", gbinder_config_file);
} else {
GERR("Error loading %s: %s", gbinder_config_file, error->message);
g_error_free(error);
error = NULL;
gbinder_config_file = NULL; /* Don't retry */
g_key_file_unref(out);
out = NULL;
}
}
/* Files in the config directory overwrite /etc/gbinder.conf */
if (files) {
char** ptr;
GKeyFile* override = NULL;
for (ptr = files; *ptr; ptr++) {
const char* file = *ptr;
if (!override) {
override = g_key_file_new();
}
if (g_key_file_load_from_file(override, file,
G_KEY_FILE_NONE, &error)) {
GDEBUG("Loaded %s", file);
if (!out) {
out = override;
override = NULL;
} else {
out = gbinder_config_merge_keyfiles(out, override);
}
} else {
GERR("Error loading %s: %s", file, error->message);
g_error_free(error);
error = NULL;
}
}
g_strfreev(files);
if (override) {
g_key_file_unref(override);
}
}
if (out) {
/* Apply presets */
const int api_level = g_key_file_get_integer(out,
CONF_GENERAL, CONG_API_LEVEL, NULL);
if (api_level > 0) {
int i;
GDEBUG("API level %d", api_level);
for (i = 0; i < G_N_ELEMENTS(gbinder_config_presets); i++) {
const GBinderConfigPreset* preset = gbinder_config_presets + i;
if (api_level >= preset->api_level) {
gbinder_config_apply_presets(out, preset);
break;
}
}
}
}
return out;
}
static
void
gbinder_config_autorelease_cb(
gpointer data)
{
GASSERT(gbinder_config_keyfile == data);
gbinder_config_keyfile = NULL;
g_key_file_unref(data);
}
GKeyFile* /* autoreleased */
gbinder_config_get()
{
if (!gbinder_config_keyfile &&
(gbinder_config_file || gbinder_config_dir)) {
gbinder_config_keyfile = gbinder_config_load_files();
if (gbinder_config_keyfile) {
/* See the comment at the top of the file why this is needed */
gbinder_config_autorelease = gbinder_idle_callback_schedule_new
(gbinder_config_autorelease_cb, gbinder_config_keyfile, NULL);
}
}
return gbinder_config_keyfile;
}
/* Helper for loading config group in device = ident format */
GHashTable*
gbinder_config_load(
const char* group,
GBinderConfigValueMapFunc mapper)
{
GKeyFile* k = gbinder_config_get();
GHashTable* map = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
if (k) {
gsize n;
char** devs = g_key_file_get_keys(k, group, &n, NULL);
if (devs) {
gsize i;
for (i = 0; i < n; i++) {
char* dev = devs[i];
char* sval = g_key_file_get_value(k, group, dev, NULL);
gconstpointer val = mapper(sval);
if (val) {
g_hash_table_replace(map, dev, (gpointer) val);
} else {
GWARN("Unknown gbinder config '%s' for %s in group [%s]",
sval, dev, group);
g_free(dev);
}
g_free(sval);
}
/* Shallow delete (contents got stolen or freed) */
g_free(devs);
}
}
return map;
}
void
gbinder_config_exit()
{
if (gbinder_config_autorelease) {
gbinder_idle_callback_destroy(gbinder_config_autorelease);
gbinder_config_autorelease = NULL;
}
if (gbinder_config_keyfile) {
g_key_file_unref(gbinder_config_keyfile);
gbinder_config_keyfile = NULL;
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

78
src/gbinder_config.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_CONFIG_H
#define GBINDER_CONFIG_H
#include "gbinder_types_p.h"
typedef
gconstpointer
(*GBinderConfigValueMapFunc)(
const char* value);
GHashTable*
gbinder_config_load(
const char* group,
GBinderConfigValueMapFunc map)
GBINDER_INTERNAL;
GKeyFile* /* autoreleased */
gbinder_config_get(
void)
GBINDER_INTERNAL;
/* This one declared strictly for unit tests */
void
gbinder_config_exit(
void)
GBINDER_INTERNAL
GBINDER_DESTRUCTOR;
/* And these too */
extern const char* gbinder_config_file GBINDER_INTERNAL;
extern const char* gbinder_config_dir GBINDER_INTERNAL;
/* Configuration groups and special value */
#define GBINDER_CONFIG_GROUP_PROTOCOL "Protocol"
#define GBINDER_CONFIG_GROUP_SERVICEMANAGER "ServiceManager"
#define GBINDER_CONFIG_VALUE_DEFAULT "Default"
#endif /* GBINDER_CONFIG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,180 +0,0 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_servicemanager_p.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
#include <gutil_macros.h>
#include <errno.h>
#include <pthread.h>
typedef GBinderServiceManager GBinderDefaultServiceManager;
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
G_DEFINE_TYPE(GBinderDefaultServiceManager,
gbinder_defaultservicemanager,
GBINDER_TYPE_SERVICEMANAGER)
enum gbinder_defaultservicemanager_calls {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
/* As a special case, ServiceManager's handle is zero */
#define DEFAULTSERVICEMANAGER_HANDLE (0)
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager"
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_defaultservicemanager_get_type(), dev);
}
static
GBinderLocalRequest*
gbinder_servicemanager_list_services_req(
GBinderServiceManager* self,
gint32 index)
{
return gbinder_local_request_append_int32
(gbinder_client_new_request(self->client), index);
}
static
char**
gbinder_defaultservicemanager_list(
GBinderServiceManager* self)
{
GPtrArray* list = g_ptr_array_new();
GBinderLocalRequest* req = gbinder_servicemanager_list_services_req(self,0);
GBinderRemoteReply* reply;
while ((reply = gbinder_client_transact_sync_reply(self->client,
LIST_SERVICES_TRANSACTION, req, NULL)) != NULL) {
char* service = gbinder_remote_reply_read_string16(reply);
gbinder_remote_reply_unref(reply);
if (service) {
g_ptr_array_add(list, service);
gbinder_local_request_unref(req);
req = gbinder_servicemanager_list_services_req(self, list->len);
} else {
break;
}
}
gbinder_local_request_unref(req);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
static
GBinderRemoteObject*
gbinder_defaultservicemanager_get_service(
GBinderServiceManager* self,
const char* name,
int* status)
{
GBinderRemoteObject* obj;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
reply = gbinder_client_transact_sync_reply(self->client,
CHECK_SERVICE_TRANSACTION, req, status);
obj = gbinder_remote_reply_read_object(reply);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return obj;
}
static
int
gbinder_defaultservicemanager_add_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj)
{
int status;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
reply = gbinder_client_transact_sync_reply(self->client,
ADD_SERVICE_TRANSACTION, req, &status);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return status;
}
static
void
gbinder_defaultservicemanager_init(
GBinderDefaultServiceManager* self)
{
}
static
void
gbinder_defaultservicemanager_class_init(
GBinderDefaultServiceManagerClass* klass)
{
klass->handle = DEFAULTSERVICEMANAGER_HANDLE;
klass->iface = DEFAULTSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER;
klass->list = gbinder_defaultservicemanager_list;
klass->get_service = gbinder_defaultservicemanager_get_service;
klass->add_service = gbinder_defaultservicemanager_add_service;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -39,95 +39,150 @@ struct pollfd;
GBinderDriver*
gbinder_driver_new(
const char* dev);
const char* dev,
const GBinderRpcProtocol* protocol)
GBINDER_INTERNAL;
GBinderDriver*
gbinder_driver_ref(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
void
gbinder_driver_unref(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
void
gbinder_driver_close(
GBinderDriver* driver)
GBINDER_INTERNAL;
int
gbinder_driver_fd(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
int
gbinder_driver_poll(
GBinderDriver* driver,
struct pollfd* pollfd);
struct pollfd* pollfd)
GBINDER_INTERNAL;
const char*
gbinder_driver_dev(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
const GBinderIo*
gbinder_driver_io(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
const GBinderRpcProtocol*
gbinder_driver_protocol(
GBinderDriver* driver)
GBINDER_INTERNAL;
gboolean
gbinder_driver_acquire_done(
GBinderDriver* driver,
GBinderLocalObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_dead_binder_done(
GBinderDriver* driver,
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_request_death_notification(
GBinderDriver* driver,
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_clear_death_notification(
GBinderDriver* driver,
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
gboolean
gbinder_driver_increfs(
GBinderDriver* driver,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
gboolean
gbinder_driver_decrefs(
GBinderDriver* driver,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
gboolean
gbinder_driver_acquire(
GBinderDriver* driver,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
gboolean
gbinder_driver_release(
GBinderDriver* driver,
guint32 handle);
guint32 handle)
GBINDER_INTERNAL;
void
gbinder_driver_close_fds(
GBinderDriver* driver,
void** objects,
const void* end)
GBINDER_INTERNAL;
void
gbinder_driver_free_buffer(
GBinderDriver* driver,
void* buffer);
void* buffer)
GBINDER_INTERNAL;
gboolean
gbinder_driver_enter_looper(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
gboolean
gbinder_driver_exit_looper(
GBinderDriver* driver);
GBinderDriver* driver)
GBINDER_INTERNAL;
int
gbinder_driver_read(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
GBinderHandler* handler);
GBinderHandler* handler)
GBINDER_INTERNAL;
int
gbinder_driver_transact(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
GBinderHandler* handler,
guint32 handle,
guint32 code,
GBinderLocalRequest* request,
GBinderRemoteReply* reply);
GBinderRemoteReply* reply)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_driver_local_request_new(
GBinderDriver* self,
const char* iface);
GBinderDriver* driver,
const char* iface)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_driver_local_request_new_ping(
GBinderDriver* self)
GBINDER_INTERNAL;
#endif /* GBINDER_DRIVER_H */

405
src/gbinder_eventloop.c Normal file
View File

@@ -0,0 +1,405 @@
/*
* Copyright (C) 2020-2021 Jolla Ltd.
* Copyright (C) 2020-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_eventloop_p.h"
#include <gutil_macros.h>
typedef struct gbinder_idle_callback_data {
GBinderEventLoopCallback* cb;
GBinderEventLoopCallbackFunc func;
GDestroyNotify destroy;
gpointer data;
} GBinderIdleCallbackData;
#define GBINDER_DEFAULT_EVENTLOOP (&gbinder_eventloop_glib)
static const GBinderEventLoopIntegration gbinder_eventloop_glib;
/*==========================================================================*
* GLib event loop integration
*==========================================================================*/
typedef struct gbinder_eventloop_glib_timeout {
GBinderEventLoopTimeout timeout;
guint id;
GSourceFunc func;
gpointer data;
} GBinderEventLoopTimeoutGLib;
typedef struct gbinder_eventloop_glib_callback {
GSource source;
GBinderEventLoopCallback callback;
} GBinderEventLoopCallbackGLib;
static
inline
GBinderEventLoopTimeoutGLib*
gbinder_eventloop_glib_timeout_cast(
GBinderEventLoopTimeout* timeout)
{
return G_CAST(timeout,GBinderEventLoopTimeoutGLib,timeout);
}
static
inline
GSource*
gbinder_eventloop_glib_callback_source(
GBinderEventLoopCallback* callback)
{
return &(G_CAST(callback,GBinderEventLoopCallbackGLib,callback)->source);
}
static
gboolean
gbinder_eventloop_glib_timeout_callback(
gpointer data)
{
GBinderEventLoopTimeoutGLib* timeout = data;
return timeout->func(timeout->data);
}
static
void
gbinder_eventloop_glib_timeout_finalize(
gpointer data)
{
g_slice_free1(sizeof(GBinderEventLoopTimeoutGLib), data);
}
static
GBinderEventLoopTimeout*
gbinder_eventloop_glib_timeout_add(
guint interval,
GSourceFunc func,
gpointer data)
{
GBinderEventLoopTimeoutGLib* impl =
g_slice_new(GBinderEventLoopTimeoutGLib);
impl->timeout.eventloop = &gbinder_eventloop_glib;
impl->func = func;
impl->data = data;
impl->id = g_timeout_add_full(G_PRIORITY_DEFAULT, interval,
gbinder_eventloop_glib_timeout_callback, impl,
gbinder_eventloop_glib_timeout_finalize);
return &impl->timeout;
}
static
void
gbinder_eventloop_glib_timeout_remove(
GBinderEventLoopTimeout* timeout)
{
g_source_remove(gbinder_eventloop_glib_timeout_cast(timeout)->id);
}
static
gboolean
gbinder_eventloop_glib_callback_prepare(
GSource* source,
gint* timeout)
{
*timeout = 0;
return TRUE;
}
static
gboolean
gbinder_eventloop_glib_callback_check(
GSource* source)
{
return TRUE;
}
static
gboolean
gbinder_eventloop_glib_callback_dispatch(
GSource* source,
GSourceFunc callback,
gpointer user_data)
{
((GBinderEventLoopCallbackFunc)callback)(user_data);
return G_SOURCE_REMOVE;
}
static
GBinderEventLoopCallback*
gbinder_eventloop_glib_callback_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify finalize)
{
static GSourceFuncs callback_funcs = {
gbinder_eventloop_glib_callback_prepare,
gbinder_eventloop_glib_callback_check,
gbinder_eventloop_glib_callback_dispatch
};
GBinderEventLoopCallbackGLib* impl = (GBinderEventLoopCallbackGLib*)
g_source_new(&callback_funcs, sizeof(GBinderEventLoopCallbackGLib));
impl->callback.eventloop = &gbinder_eventloop_glib;
g_source_set_callback(&impl->source, (GSourceFunc) func, data, finalize);
return &impl->callback;
}
static
void
gbinder_eventloop_glib_callback_ref(
GBinderEventLoopCallback* cb)
{
g_source_ref(gbinder_eventloop_glib_callback_source(cb));
}
static
void
gbinder_eventloop_glib_callback_unref(
GBinderEventLoopCallback* cb)
{
g_source_unref(gbinder_eventloop_glib_callback_source(cb));
}
static
void
gbinder_eventloop_glib_callback_schedule(
GBinderEventLoopCallback* cb)
{
static GMainContext* context = NULL;
if (!context) context = g_main_context_default();
g_source_attach(gbinder_eventloop_glib_callback_source(cb), context);
}
static
void
gbinder_eventloop_glib_callback_cancel(
GBinderEventLoopCallback* cb)
{
g_source_destroy(gbinder_eventloop_glib_callback_source(cb));
}
static
void
gbinder_eventloop_glib_cleanup(
void)
{
}
static const GBinderEventLoopIntegration gbinder_eventloop_glib = {
gbinder_eventloop_glib_timeout_add,
gbinder_eventloop_glib_timeout_remove,
gbinder_eventloop_glib_callback_new,
gbinder_eventloop_glib_callback_ref,
gbinder_eventloop_glib_callback_unref,
gbinder_eventloop_glib_callback_schedule,
gbinder_eventloop_glib_callback_cancel,
gbinder_eventloop_glib_cleanup
};
/*==========================================================================*
* Implementation
*==========================================================================*/
static
void
gbinder_idle_callback_invoke_proc(
void* user_data)
{
GBinderIdleCallbackData* idle = user_data;
if (idle->func) {
idle->func(idle->data);
}
gbinder_idle_callback_unref(idle->cb);
}
static
void
gbinder_idle_callback_invoke_done(
void* user_data)
{
GBinderIdleCallbackData* idle = user_data;
if (idle->destroy) {
idle->destroy(idle->data);
}
gutil_slice_free(idle);
}
/*==========================================================================*
* Internal interface
*==========================================================================*/
static const GBinderEventLoopIntegration* gbinder_eventloop =
GBINDER_DEFAULT_EVENTLOOP;
GBinderEventLoopTimeout*
gbinder_timeout_add(
guint interval,
GSourceFunc function,
gpointer data)
{
return gbinder_eventloop->timeout_add(interval, function, data);
}
GBinderEventLoopTimeout*
gbinder_idle_add(
GSourceFunc function,
gpointer data)
{
return gbinder_eventloop->timeout_add(0, function, data);
}
void
gbinder_timeout_remove(
GBinderEventLoopTimeout* timeout)
{
if (timeout) {
timeout->eventloop->timeout_remove(timeout);
}
}
GBinderEventLoopCallback*
gbinder_idle_callback_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify finalize)
{
return gbinder_eventloop->callback_new(func, data, finalize);
}
GBinderEventLoopCallback*
gbinder_idle_callback_schedule_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify finalize)
{
GBinderEventLoopCallback* cb =
gbinder_eventloop->callback_new(func, data, finalize);
gbinder_idle_callback_schedule(cb);
return cb;
}
GBinderEventLoopCallback*
gbinder_idle_callback_ref(
GBinderEventLoopCallback* cb)
{
if (cb) {
cb->eventloop->callback_ref(cb);
return cb;
}
return NULL;
}
void
gbinder_idle_callback_unref(
GBinderEventLoopCallback* cb)
{
if (cb) {
cb->eventloop->callback_unref(cb);
}
}
void
gbinder_idle_callback_schedule(
GBinderEventLoopCallback* cb)
{
if (cb) {
cb->eventloop->callback_schedule(cb);
}
}
void
gbinder_idle_callback_cancel(
GBinderEventLoopCallback* cb)
{
if (cb) {
cb->eventloop->callback_cancel(cb);
}
}
void
gbinder_idle_callback_destroy(
GBinderEventLoopCallback* cb)
{
if (cb) {
const GBinderEventLoopIntegration* eventloop = cb->eventloop;
eventloop->callback_cancel(cb);
eventloop->callback_unref(cb);
}
}
/* Non-cancellable callback */
void
gbinder_idle_callback_invoke_later(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
{
GBinderIdleCallbackData* idle = g_slice_new(GBinderIdleCallbackData);
idle->func = func;
idle->data = data;
idle->destroy = destroy;
idle->cb = gbinder_idle_callback_new(gbinder_idle_callback_invoke_proc,
idle, gbinder_idle_callback_invoke_done);
gbinder_idle_callback_schedule(idle->cb);
}
/*==========================================================================*
* Public interface
*==========================================================================*/
void
gbinder_eventloop_set(
const GBinderEventLoopIntegration* loop)
{
if (!loop) loop = GBINDER_DEFAULT_EVENTLOOP;
if (gbinder_eventloop != loop) {
const GBinderEventLoopIntegration* prev = gbinder_eventloop;
gbinder_eventloop = loop;
prev->cleanup();
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

115
src/gbinder_eventloop_p.h Normal file
View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2020-2021 Jolla Ltd.
* Copyright (C) 2020-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_EVENTLOOP_PRIVATE_H
#define GBINDER_EVENTLOOP_PRIVATE_H
#include "gbinder_types_p.h"
#include "gbinder_eventloop.h"
GBinderEventLoopTimeout*
gbinder_timeout_add(
guint millis,
GSourceFunc func,
gpointer data)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
GBinderEventLoopTimeout*
gbinder_idle_add(
GSourceFunc func,
gpointer data)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
void
gbinder_timeout_remove(
GBinderEventLoopTimeout* timeout)
GBINDER_INTERNAL;
GBinderEventLoopCallback*
gbinder_idle_callback_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
GBinderEventLoopCallback*
gbinder_idle_callback_schedule_new(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
G_GNUC_WARN_UNUSED_RESULT
GBINDER_INTERNAL;
GBinderEventLoopCallback*
gbinder_idle_callback_ref(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_unref(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_schedule(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_cancel(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_destroy(
GBinderEventLoopCallback* cb)
GBINDER_INTERNAL;
void
gbinder_idle_callback_invoke_later(
GBinderEventLoopCallbackFunc func,
gpointer data,
GDestroyNotify destroy)
GBINDER_INTERNAL;
#endif /* GBINDER_EVENTLOOP_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

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 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -36,6 +36,7 @@
#include "gbinder_types_p.h"
typedef struct gbinder_handler_functions {
gboolean (*can_loop)(GBinderHandler* handler);
GBinderLocalReply* (*transact)(GBinderHandler* handler,
GBinderLocalObject* obj, GBinderRemoteRequest* req, guint code,
guint flags, int* status);
@@ -47,6 +48,14 @@ struct gbinder_handler {
/* Inline wrappers */
GBINDER_INLINE_FUNC
gboolean
gbinder_handler_can_loop(
GBinderHandler* self)
{
return self && self->f->can_loop && self->f->can_loop(self);
}
GBINDER_INLINE_FUNC
GBinderLocalReply*
gbinder_handler_transact(

View File

@@ -1,199 +0,0 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_servicemanager_p.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
#include <gbinder_reader.h>
#include <errno.h>
#include <pthread.h>
typedef GBinderServiceManager GBinderHwServiceManager;
typedef GBinderServiceManagerClass GBinderHwServiceManagerClass;
G_DEFINE_TYPE(GBinderHwServiceManager,
gbinder_hwservicemanager,
GBINDER_TYPE_SERVICEMANAGER)
enum gbinder_hwservicemanager_calls {
GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
ADD_TRANSACTION,
GET_TRANSPORT_TRANSACTION,
LIST_TRANSACTION,
LIST_BY_INTERFACE_TRANSACTION,
REGISTER_FOR_NOTIFICATIONS_TRANSACTION,
DEBUG_DUMP_TRANSACTION,
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
};
/* As a special case, ServiceManager's handle is zero */
#define HWSERVICEMANAGER_HANDLE (0)
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_hwservicemanager_get_type(), dev);
}
static
char**
gbinder_hwservicemanager_list(
GBinderHwServiceManager* self)
{
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply
(self->client, LIST_TRANSACTION, req, NULL);
gbinder_local_request_unref(req);
if (reply) {
GBinderReader reader;
char** result = NULL;
int status = -1;
gbinder_remote_reply_init_reader(reply, &reader);
/* Read status */
GVERIFY(gbinder_reader_read_int32(&reader, &status));
GASSERT(status == GBINDER_STATUS_OK);
/* Followed by hidl_vec<string> */
result = gbinder_reader_read_hidl_string_vec(&reader);
gbinder_remote_reply_unref(reply);
return result;
}
return NULL;
}
static
GBinderRemoteObject*
gbinder_hwservicemanager_get_service(
GBinderServiceManager* self,
const char* fqinstance,
int* status)
{
/* e.g. "android.hardware.radio@1.1::IRadio/slot1" */
const char* sep = strchr(fqinstance, '/');
GBinderRemoteObject* obj = NULL;
if (sep) {
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
char* fqname = g_strndup(fqinstance, sep - fqinstance);
const char* name = sep + 1;
gbinder_local_request_append_hidl_string(req, fqname);
gbinder_local_request_append_hidl_string(req, name);
reply = gbinder_client_transact_sync_reply(self->client,
GET_TRANSACTION, req, status);
if (reply) {
GBinderReader reader;
int status = -1;
gbinder_remote_reply_init_reader(reply, &reader);
/* Read status */
GVERIFY(gbinder_reader_read_int32(&reader, &status));
GASSERT(status == GBINDER_STATUS_OK);
/* Read the object */
obj = gbinder_reader_read_object(&reader);
gbinder_remote_reply_unref(reply);
}
gbinder_local_request_unref(req);
g_free(fqname);
} else {
GERR("Invalid instance \"%s\"", fqinstance);
if (status) *status = (-EINVAL);
}
return obj;
}
static
int
gbinder_hwservicemanager_add_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj)
{
int status;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
/* add(string name, interface service) generates (bool success); */
gbinder_local_request_append_hidl_string(req, name);
gbinder_local_request_append_local_object(req, obj);
reply = gbinder_client_transact_sync_reply(self->client,
ADD_TRANSACTION, req, &status);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return status;
}
static
void
gbinder_hwservicemanager_init(
GBinderHwServiceManager* self)
{
}
static
void
gbinder_hwservicemanager_class_init(
GBinderHwServiceManagerClass* klass)
{
klass->handle = HWSERVICEMANAGER_HANDLE;
klass->iface = HWSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->list = gbinder_hwservicemanager_list;
klass->get_service = gbinder_hwservicemanager_get_service;
klass->add_service = gbinder_hwservicemanager_add_service;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

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
@@ -90,6 +90,51 @@ GBINDER_IO_FN(write_read)(
return ret;
}
/* Returns size of the object */
static
gsize
GBINDER_IO_FN(object_size)(
const void* obj)
{
if (obj) {
const struct binder_object_header* hdr = obj;
switch (hdr->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER:
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE:
return sizeof(struct flat_binder_object);
case BINDER_TYPE_FD:
return sizeof(struct binder_fd_object);
case BINDER_TYPE_FDA:
return sizeof(struct binder_fd_array_object);
case BINDER_TYPE_PTR:
return sizeof(struct binder_buffer_object);
}
}
return 0;
}
/* Returns size of the object's extra data */
static
gsize
GBINDER_IO_FN(object_data_size)(
const void* obj)
{
if (obj) {
const struct binder_object_header* hdr = obj;
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 */
static
guint
@@ -103,7 +148,20 @@ GBINDER_IO_FN(encode_pointer)(
return sizeof(*dest);
}
/* Encodes flat_buffer_object */
/* Writes cookie to the buffer */
static
guint
GBINDER_IO_FN(encode_cookie)(
void* out,
guint64 cookie)
{
binder_uintptr_t* dest = out;
*dest = (uintptr_t)cookie;
return sizeof(*dest);
}
/* Encodes flat_binder_object */
static
guint
GBINDER_IO_FN(encode_local_object)(
@@ -113,9 +171,13 @@ GBINDER_IO_FN(encode_local_object)(
struct flat_binder_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_BINDER;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
if (obj) {
dest->hdr.type = BINDER_TYPE_BINDER;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
} else {
dest->hdr.type = BINDER_TYPE_WEAK_BINDER;
}
return sizeof(*dest);
}
@@ -138,6 +200,38 @@ GBINDER_IO_FN(encode_remote_object)(
return sizeof(*dest);
}
static
guint
GBINDER_IO_FN(encode_fd_object)(
void* out,
int fd)
{
struct binder_fd_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_FD;
dest->pad_flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->fd = fd;
return sizeof(*dest);
}
static
guint
GBINDER_IO_FN(encode_fda_object)(
void* out,
const GBinderFds *fds,
const GBinderParent* parent)
{
struct binder_fd_array_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_FDA;
dest->num_fds = fds->num_fds;
dest->parent = parent->index;
dest->parent_offset = parent->offset;
return sizeof(*dest);
}
/* Encodes binder_buffer_object */
static
guint
@@ -163,7 +257,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)
{
@@ -175,7 +269,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)(
@@ -183,7 +291,7 @@ GBINDER_IO_FN(fill_transaction_data)(
guint32 handle,
guint32 code,
const GByteArray* payload,
guint flags,
guint tx_flags,
GUtilIntArray* offsets,
void** offsets_buf)
{
@@ -192,9 +300,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);
@@ -210,6 +316,7 @@ GBINDER_IO_FN(fill_transaction_data)(
}
}
/* Encodes BC_TRANSACTION data */
static
guint
GBINDER_IO_FN(encode_transaction)(
@@ -223,7 +330,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);
}
@@ -244,13 +352,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)(
@@ -338,7 +486,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;
@@ -348,6 +496,24 @@ GBINDER_IO_FN(decode_binder_ptr_cookie)(
return (void*)(uintptr_t)ptr->ptr;
}
static
guint
GBINDER_IO_FN(decode_binder_handle)(
const void* data,
guint32* handle)
{
const struct flat_binder_object* obj = data;
/* Caller guarantees that data points to an object */
if (obj->hdr.type == BINDER_TYPE_HANDLE) {
if (handle) {
*handle = obj->handle;
}
return sizeof(*obj);
}
return 0;
}
static
guint
GBINDER_IO_FN(decode_binder_object)(
@@ -362,9 +528,19 @@ GBINDER_IO_FN(decode_binder_object)(
switch (obj->hdr.type) {
case BINDER_TYPE_HANDLE:
if (out) {
*out = gbinder_object_registry_get_remote(reg, obj->handle);
*out = gbinder_object_registry_get_remote(reg, obj->handle,
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE);
}
return sizeof(*obj);
case BINDER_TYPE_BINDER:
if (!obj->binder) {
/* That's a NULL reference */
if (out) {
*out = NULL;
}
return sizeof(*obj);
}
/* fallthrough */
default:
GERR("Unsupported binder object type 0x%08x", obj->hdr.type);
break;
@@ -379,7 +555,7 @@ guint
GBINDER_IO_FN(decode_buffer_object)(
GBinderBuffer* buf,
gsize offset,
GBinderBuffer** out)
GBinderIoBufferObject* out)
{
const void* data = (guint8*)buf->data + offset;
const gsize size = (offset < buf->size) ? (buf->size - offset) : 0;
@@ -387,12 +563,36 @@ GBINDER_IO_FN(decode_buffer_object)(
if (size >= sizeof(*flat) && flat->hdr.type == BINDER_TYPE_PTR) {
if (out) {
*out = gbinder_buffer_new_with_parent(buf,
(void*)(uintptr_t)flat->buffer, flat->length);
out->data = (void*)(uintptr_t)flat->buffer;
out->size = (gsize)flat->length;
out->parent_offset = (gsize)flat->parent_offset;
out->has_parent = (flat->flags & BINDER_BUFFER_FLAG_HAS_PARENT) ?
TRUE : FALSE;
}
return sizeof(*flat);
}
if (out) *out = NULL;
return 0;
}
static
guint
GBINDER_IO_FN(decode_fd_object)(
const void* data,
gsize size,
int* fd)
{
const struct flat_binder_object* obj = data;
if (size >= sizeof(*obj)) {
switch (obj->hdr.type) {
case BINDER_TYPE_FD:
if (fd) *fd = obj->handle;
return sizeof(*obj);
default:
break;
}
}
if (fd) *fd = -1;
return 0;
}
@@ -445,22 +645,33 @@ 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),
/* ioctl wrappers */
.write_read = GBINDER_IO_FN(write_read)
@@ -470,10 +681,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 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
@@ -43,6 +43,13 @@ typedef struct gbinder_io_buf {
gsize consumed;
} GBinderIoBuf;
typedef struct gbinder_io_buffer_object {
void* data;
gsize size;
gsize parent_offset;
gboolean has_parent;
} GBinderIoBufferObject;
typedef struct gbinder_io_tx_data {
int status;
guint32 code;
@@ -118,59 +125,83 @@ struct gbinder_io {
guint failed_reply;
} br;
/* Size of the object and its extra data */
gsize (*object_size)(const void* obj);
gsize (*object_data_size)(const void* obj);
/* Writes pointer to the buffer. The destination buffer must have
* at least GBINDER_IO_MAX_POINTER_SIZE bytes available. The
* actual size is returned. */
#define GBINDER_MAX_POINTER_SIZE (8)
guint (*encode_pointer)(void* out, const void* pointer);
/* Writes cookie to the buffer. The destination buffer must have
* at least GBINDER_IO_MAX_COOKIE_SIZE bytes available. The
* actual size is returned. */
#define GBINDER_MAX_COOKIE_SIZE GBINDER_MAX_POINTER_SIZE
guint (*encode_cookie)(void* out, guint64 cookie);
/* Encode flat_buffer_object */
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
guint (*encode_fd_object)(void* out, int fd);
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);
guint (*decode_binder_object)(const void* data, gsize size,
GBinderObjectRegistry* reg, GBinderRemoteObject** obj);
GBinderObjectRegistry* reg, GBinderRemoteObject** obj);
guint (*decode_buffer_object)(GBinderBuffer* buf, gsize offset,
GBinderBuffer** out);
GBinderIoBufferObject* out);
guint (*decode_fd_object)(const void* data, gsize size, int* fd);
/* ioctl wrappers */
int (*write_read)(int fd, GBinderIoBuf* write, GBinderIoBuf* read);
};
extern const GBinderIo gbinder_io_32;
extern const GBinderIo gbinder_io_64;
extern const GBinderIo gbinder_io_32 GBINDER_INTERNAL;
extern const GBinderIo gbinder_io_64 GBINDER_INTERNAL;
#endif /* GBINDER_IO_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-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:
*
@@ -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
@@ -42,7 +42,6 @@ struct gbinder_ipc {
GObject object;
GBinderIpcPriv* priv;
GBinderDriver* driver;
GUtilIdlePool* pool;
const char* dev;
};
@@ -60,6 +59,12 @@ struct gbinder_ipc_tx {
void* user_data;
};
typedef
gboolean
(*GBinderIpcLocalObjectCheckFunc)(
GBinderLocalObject* obj,
void* user_data);
typedef
void
(*GBinderIpcReplyFunc)(
@@ -68,53 +73,104 @@ void
int status,
void* user_data);
GBinderIpc*
gbinder_ipc_new(
const char* dev);
GBinderIpc*
gbinder_ipc_ref(
GBinderIpc* ipc);
void
gbinder_ipc_unref(
GBinderIpc* ipc);
void
gbinder_ipc_looper_check(
GBinderIpc* ipc);
GBinderObjectRegistry*
gbinder_ipc_object_registry(
GBinderIpc* ipc);
GBinderLocalObject*
gbinder_ipc_new_local_object(
GBinderIpc* ipc,
const char* iface,
GBinderLocalTransactFunc txproc,
void* data);
GBinderRemoteObject*
gbinder_ipc_get_remote_object(
GBinderIpc* ipc,
guint32 handle);
typedef
GBinderRemoteReply*
gbinder_ipc_transact_sync_reply(
(*GBinderIpcSyncReplyFunc)(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req,
int* status);
typedef
int
gbinder_ipc_transact_sync_oneway(
(*GBinderIpcSyncOnewayFunc)(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req);
struct gbinder_ipc_sync_api {
GBinderIpcSyncReplyFunc sync_reply;
GBinderIpcSyncOnewayFunc sync_oneway;
};
extern const GBinderIpcSyncApi gbinder_ipc_sync_main GBINDER_INTERNAL;
extern const GBinderIpcSyncApi gbinder_ipc_sync_worker GBINDER_INTERNAL;
GBinderIpc*
gbinder_ipc_new(
const char* dev)
GBINDER_INTERNAL;
GBinderIpc*
gbinder_ipc_ref(
GBinderIpc* ipc)
GBINDER_INTERNAL;
void
gbinder_ipc_unref(
GBinderIpc* ipc)
GBINDER_INTERNAL;
const char*
gbinder_ipc_name(
GBinderIpc* ipc)
GBINDER_INTERNAL;
void
gbinder_ipc_looper_check(
GBinderIpc* ipc)
GBINDER_INTERNAL;
GBinderObjectRegistry*
gbinder_ipc_object_registry(
GBinderIpc* ipc)
GBINDER_INTERNAL;
const GBinderIo*
gbinder_ipc_io(
GBinderIpc* ipc)
GBINDER_INTERNAL;
const GBinderRpcProtocol*
gbinder_ipc_protocol(
GBinderIpc* ipc)
GBINDER_INTERNAL;
GBinderLocalObject*
gbinder_ipc_find_local_object(
GBinderIpc* ipc,
GBinderIpcLocalObjectCheckFunc func,
void* user_data)
GBINDER_INTERNAL
G_GNUC_WARN_UNUSED_RESULT;
void
gbinder_ipc_register_local_object(
GBinderIpc* ipc,
GBinderLocalObject* obj)
GBINDER_INTERNAL;
GBinderRemoteObject*
gbinder_ipc_get_service_manager(
GBinderIpc* ipc)
GBINDER_INTERNAL
G_GNUC_WARN_UNUSED_RESULT;
void
gbinder_ipc_invalidate_remote_handle(
GBinderIpc* ipc,
guint32 handle)
GBINDER_INTERNAL;
int
gbinder_ipc_ping_sync(
GBinderIpc* ipc,
guint32 handle,
const GBinderIpcSyncApi* api)
GBINDER_INTERNAL;
gulong
gbinder_ipc_transact(
GBinderIpc* ipc,
@@ -124,7 +180,8 @@ gbinder_ipc_transact(
GBinderLocalRequest* req,
GBinderIpcReplyFunc func,
GDestroyNotify destroy,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
gulong
gbinder_ipc_transact_custom(
@@ -132,24 +189,48 @@ gbinder_ipc_transact_custom(
GBinderIpcTxFunc exec,
GBinderIpcTxFunc done,
GDestroyNotify destroy,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
void
gbinder_ipc_cancel(
GBinderIpc* ipc,
gulong id);
gulong id)
GBINDER_INTERNAL;
/* Internal for GBinderLocalObject */
void
gbinder_ipc_local_object_disposed(
GBinderIpc* self,
GBinderLocalObject* obj);
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,
GBinderRemoteObject* obj);
GBinderIpc* ipc,
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
/* Needed by unit tests */
gboolean
gbinder_ipc_set_max_threads(
GBinderIpc* ipc,
gint max_threads)
GBINDER_INTERNAL;
/* Declared for unit tests */
void
gbinder_ipc_exit(
void)
GBINDER_INTERNAL
GBINDER_DESTRUCTOR;
#endif /* GBINDER_IPC_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:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -30,29 +30,48 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_buffer_p.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_remote_request.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_writer.h"
#include "gbinder_log.h"
#include <gutil_strv.h>
#include <gutil_macros.h>
#include <errno.h>
struct gbinder_local_object_priv {
GMainContext* context;
char* iface;
char** ifaces;
GBinderLocalTransactFunc txproc;
void* user_data;
};
typedef struct gbinder_local_object_acquire_data {
GBinderLocalObject* object;
GBinderBufferContentsList* bufs;
} GBinderLocalObjectAcquireData;
G_DEFINE_TYPE(GBinderLocalObject, gbinder_local_object, G_TYPE_OBJECT)
#define PARENT_CLASS gbinder_local_object_parent_class
#define GBINDER_LOCAL_OBJECT_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_LOCAL_OBJECT, \
GBinderLocalObjectClass)
typedef
GBinderLocalReply*
(*GBinderLocalObjectTxHandler)(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
int* status);
enum gbinder_local_object_signal {
SIGNAL_WEAK_REFS_CHANGED,
SIGNAL_STRONG_REFS_CHANGED,
@@ -78,6 +97,9 @@ gbinder_local_object_default_can_handle_transaction(
guint code)
{
switch (code) {
case GBINDER_PING_TRANSACTION:
case GBINDER_INTERFACE_TRANSACTION:
return GBINDER_LOCAL_TRANSACTION_LOOPER;
case HIDL_PING_TRANSACTION:
case HIDL_GET_DESCRIPTOR_TRANSACTION:
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
@@ -110,6 +132,39 @@ gbinder_local_object_default_handle_transaction(
}
}
static
GBinderLocalReply*
gbinder_local_object_ping_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
int* status)
{
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GVERBOSE(" PING_TRANSACTION");
gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK);
*status = GBINDER_STATUS_OK;
return reply;
}
static
GBinderLocalReply*
gbinder_local_object_interface_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
int* status)
{
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalObjectPriv* priv = self->priv;
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GVERBOSE(" INTERFACE_TRANSACTION");
gbinder_local_reply_append_string16(reply, priv->ifaces[0]);
*status = GBINDER_STATUS_OK;
return reply;
}
static
GBinderLocalReply*
gbinder_local_object_hidl_ping_transaction(
@@ -120,12 +175,10 @@ gbinder_local_object_hidl_ping_transaction(
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
GVERBOSE(" HIDL_PING_TRANSACTION \"%s\"",
gbinder_remote_request_interface(req));
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -139,6 +192,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
{
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalObjectPriv* priv = self->priv;
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
@@ -146,8 +200,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
gbinder_remote_request_interface(req));
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_hidl_string(&writer, self->iface ? self->iface :
hidl_base_interface);
gbinder_writer_append_hidl_string(&writer, priv->ifaces[0]);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -163,17 +216,14 @@ gbinder_local_object_hidl_descriptor_chain_transaction(
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
const char* chain[2];
int n = 0;
GVERBOSE(" HIDL_DESCRIPTOR_CHAIN_TRANSACTION \"%s\"",
gbinder_remote_request_interface(req));
if (self->iface) chain[n++] = self->iface;
chain[n++] = hidl_base_interface;
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_hidl_string_vec(&writer, chain, n);
gbinder_writer_append_hidl_string_vec(&writer, (const char**)
self->ifaces, -1);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -187,91 +237,142 @@ gbinder_local_object_default_handle_looper_transaction(
guint flags,
int* status)
{
GBinderLocalObjectTxHandler handler = NULL;
switch (code) {
case GBINDER_PING_TRANSACTION:
handler = gbinder_local_object_ping_transaction;
break;
case GBINDER_INTERFACE_TRANSACTION:
handler = gbinder_local_object_interface_transaction;
break;
case HIDL_PING_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_ping_transaction
(self, req, status);
handler = gbinder_local_object_hidl_ping_transaction;
break;
case HIDL_GET_DESCRIPTOR_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_get_descriptor_transaction
(self, req, status);
handler = gbinder_local_object_hidl_get_descriptor_transaction;
break;
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_descriptor_chain_transaction
(self, req, status);
handler = gbinder_local_object_hidl_descriptor_chain_transaction;
break;
default:
if (status) *status = (-EBADMSG);
return NULL;
}
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return handler(self, req, status);
}
static
void
gbinder_local_object_default_drop(
GBinderLocalObject* self)
{
GBinderLocalObjectPriv* priv = self->priv;
/* Clear the transaction callback */
priv->txproc = NULL;
priv->user_data = NULL;
}
static
void
gbinder_local_object_handle_later(
GBinderLocalObject* self,
GSourceFunc function)
GBinderEventLoopCallbackFunc function)
{
if (G_LIKELY(self)) {
GBinderLocalObjectPriv* priv = self->priv;
g_main_context_invoke_full(priv->context, G_PRIORITY_DEFAULT, function,
gbinder_idle_callback_invoke_later(function,
gbinder_local_object_ref(self), g_object_unref);
}
}
static
gboolean
gbinder_local_object_handle_increfs_proc(
gpointer local)
void
gbinder_local_object_increfs_proc(
gpointer user_data)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(user_data);
self->weak_refs++;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_WEAK_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_decrefs_proc(
gpointer local)
void
gbinder_local_object_decrefs_proc(
gpointer user_data)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(user_data);
GASSERT(self->weak_refs > 0);
self->weak_refs--;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_WEAK_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_acquire_proc(
gpointer local)
void
gbinder_local_object_default_acquire(
GBinderLocalObject* self)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
self->strong_refs++;
gbinder_local_object_ref(self);
GVERBOSE_("%p => %d", self, self->strong_refs);
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_release_proc(
gpointer local)
void
gbinder_local_object_acquire_proc(
gpointer user_data)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObjectAcquireData* data = user_data;
GBinderLocalObject* self = data->object;
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->acquire(self);
}
static
void
gbinder_local_object_acquire_done(
gpointer user_data)
{
GBinderLocalObjectAcquireData* data = user_data;
GBinderLocalObject* self = data->object;
gbinder_driver_acquire_done(self->ipc->driver, self);
gbinder_local_object_unref(self);
gbinder_buffer_contents_list_free(data->bufs);
return gutil_slice_free(data);
}
static
void
gbinder_local_object_default_release(
GBinderLocalObject* self)
{
GASSERT(self->strong_refs > 0);
self->strong_refs--;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
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);
}
/*==========================================================================*
@@ -281,23 +382,66 @@ gbinder_local_object_handle_release_proc(
GBinderLocalObject*
gbinder_local_object_new(
GBinderIpc* ipc,
const char* iface,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data) /* Since 1.0.30 */
{
return gbinder_local_object_new_with_type(GBINDER_TYPE_LOCAL_OBJECT,
ipc, ifaces, txproc, user_data);
}
GBinderLocalObject*
gbinder_local_object_new_with_type(
GType type,
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* arg)
{
if (G_LIKELY(ipc)) {
GBinderLocalObject* obj = g_object_new(type, NULL);
gbinder_local_object_init_base(obj, ipc, ifaces, txproc, arg);
gbinder_ipc_register_local_object(ipc, obj);
return obj;
}
return NULL;
}
void
gbinder_local_object_init_base(
GBinderLocalObject* self,
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
{
/* Should only be called from gbinder_ipc_new_local_local_object() */
if (G_LIKELY(ipc)) {
GBinderLocalObject* self = g_object_new
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
GBinderLocalObjectPriv* priv = self->priv;
GBinderLocalObjectPriv* priv = self->priv;
guint i = 0, n = gutil_strv_length((char**)ifaces);
gboolean append_base_interface;
self->ipc = gbinder_ipc_ref(ipc);
self->iface = priv->iface = g_strdup(iface);
priv->txproc = txproc;
priv->user_data = user_data;
return self;
if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
append_base_interface = TRUE;
n++;
} else {
append_base_interface = FALSE;
}
return NULL;
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;
}
GBinderLocalObject*
@@ -326,11 +470,7 @@ gbinder_local_object_drop(
GBinderLocalObject* self)
{
if (G_LIKELY(self)) {
GBinderLocalObjectPriv* priv = self->priv;
/* Clear the transaction callback */
priv->txproc = NULL;
priv->user_data = NULL;
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->drop(self);
g_object_unref(GBINDER_LOCAL_OBJECT(self));
}
}
@@ -424,32 +564,49 @@ void
gbinder_local_object_handle_increfs(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_increfs_proc);
gbinder_local_object_handle_later(self, gbinder_local_object_increfs_proc);
}
void
gbinder_local_object_handle_decrefs(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_decrefs_proc);
gbinder_local_object_handle_later(self, gbinder_local_object_decrefs_proc);
}
void
gbinder_local_object_handle_acquire(
GBinderLocalObject* self)
GBinderLocalObject* self,
GBinderBufferContentsList* bufs)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_acquire_proc);
if (G_LIKELY(self)) {
GBinderLocalObjectAcquireData* data =
g_slice_new(GBinderLocalObjectAcquireData);
/*
* This is a bit complicated :)
* GBinderProxyObject derived from GBinderLocalObject acquires a
* reference to the remote object in addition to performing the
* default GBinderLocalObject action later on the main thread.
* We must ensure that remote object doesn't go away before we
* acquire our reference to it. One of the references to that
* remote object (possibly the last one) may be associated with
* the transaction buffer contained in GBinderBufferContentsList.
* We don't know exactly which one we need, so we keep all those
* buffers alive until we are done with BR_ACQUIRE.
*/
data->object = gbinder_local_object_ref(self);
data->bufs = gbinder_buffer_contents_list_dup(bufs);
gbinder_idle_callback_invoke_later(gbinder_local_object_acquire_proc,
data, gbinder_local_object_acquire_done);
}
}
void
gbinder_local_object_handle_release(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_release_proc);
gbinder_local_object_handle_later(self, gbinder_local_object_release_proc);
}
/*==========================================================================*
@@ -464,32 +621,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_free(priv->iface);
G_OBJECT_CLASS(gbinder_local_object_parent_class)->finalize(local);
g_strfreev(priv->ifaces);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
@@ -509,6 +667,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 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -40,8 +40,9 @@
#include <glib-object.h>
/*
* Some if this stuff may become public if we decide to allow the clients
* to derive their classes from GBinderLocalObject
* Some of this stuff may become public if we decide to allow the clients
* to derive their own classes from GBinderLocalObject. For now it's all
* private.
*/
typedef
@@ -55,7 +56,7 @@ struct gbinder_local_object {
GObject object;
GBinderLocalObjectPriv* priv;
GBinderIpc* ipc;
const char* iface;
const char* const* ifaces;
gint weak_refs;
gint strong_refs;
};
@@ -76,47 +77,66 @@ typedef struct gbinder_local_object_class {
GBinderLocalReply* (*handle_looper_transaction)
(GBinderLocalObject* self, GBinderRemoteRequest* req, guint code,
guint flags, int* status);
void (*acquire)(GBinderLocalObject* self);
void (*release)(GBinderLocalObject* self);
void (*drop)(GBinderLocalObject* self);
/* Need to add some placeholders if this class becomes public */
} GBinderLocalObjectClass;
GType gbinder_local_object_get_type(void);
GType gbinder_local_object_get_type(void) GBINDER_INTERNAL;
#define GBINDER_TYPE_LOCAL_OBJECT (gbinder_local_object_get_type())
#define GBINDER_LOCAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObject))
#define GBINDER_LOCAL_OBJECT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObjectClass)
#define gbinder_local_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
#define gbinder_local_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
/* Should only be called from gbinder_ipc_new_local_object() */
GBinderLocalObject*
gbinder_local_object_new(
gbinder_local_object_new_with_type(
GType type,
GBinderIpc* ipc,
const char* iface,
GBinderLocalTransactFunc handler,
void* user_data);
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
GBINDER_INTERNAL;
void
gbinder_local_object_init_base(
GBinderLocalObject* self,
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
GBINDER_INTERNAL;
gulong
gbinder_local_object_add_weak_refs_changed_handler(
GBinderLocalObject* obj,
GBinderLocalObjectFunc func,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
gulong
gbinder_local_object_add_strong_refs_changed_handler(
GBinderLocalObject* obj,
GBinderLocalObjectFunc func,
void* user_data);
void* user_data)
GBINDER_INTERNAL;
void
gbinder_local_object_remove_handler(
GBinderLocalObject* obj,
gulong id);
gulong id)
GBINDER_INTERNAL;
GBINDER_LOCAL_TRANSACTION_SUPPORT
gbinder_local_object_can_handle_transaction(
GBinderLocalObject* self,
const char* iface,
guint code);
guint code)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_local_object_handle_transaction(
@@ -124,7 +144,8 @@ gbinder_local_object_handle_transaction(
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status);
int* status)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_local_object_handle_looper_transaction(
@@ -132,23 +153,29 @@ gbinder_local_object_handle_looper_transaction(
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status);
int* status)
GBINDER_INTERNAL;
void
gbinder_local_object_handle_increfs(
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
void
gbinder_local_object_handle_decrefs(
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
void
gbinder_local_object_handle_acquire(
GBinderLocalObject* obj);
GBinderLocalObject* obj,
GBinderBufferContentsList* bufs)
GBINDER_INTERNAL;
void
gbinder_local_object_handle_release(
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_OBJECT_PRIVATE_H */

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
@@ -33,6 +33,7 @@
#include "gbinder_local_reply_p.h"
#include "gbinder_output_data.h"
#include "gbinder_writer_p.h"
#include "gbinder_buffer_p.h"
#include "gbinder_log.h"
#include <gutil_intarray.h>
@@ -42,6 +43,7 @@ struct gbinder_local_reply {
gint refcount;
GBinderWriterData data;
GBinderOutputData out;
GBinderBufferContents* contents;
};
GBINDER_INLINE_FUNC
@@ -92,6 +94,21 @@ gbinder_local_reply_new(
return NULL;
}
GBinderLocalReply*
gbinder_local_reply_set_contents(
GBinderLocalReply* self,
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
{
if (self) {
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;
}
static
void
gbinder_local_reply_free(
@@ -102,7 +119,8 @@ gbinder_local_reply_free(
gutil_int_array_free(data->offsets, TRUE);
g_byte_array_free(data->bytes, TRUE);
gbinder_cleanup_free(data->cleanup);
g_slice_free(GBinderLocalReply, self);
gbinder_buffer_contents_unref(self->contents);
gutil_slice_free(self);
}
GBinderLocalReply*
@@ -135,6 +153,13 @@ gbinder_local_reply_data(
return G_LIKELY(self) ? &self->out : NULL;
}
GBinderBufferContents*
gbinder_local_reply_contents(
GBinderLocalReply* self)
{
return G_LIKELY(self) ? self->contents : NULL;
}
void
gbinder_local_reply_cleanup(
GBinderLocalReply* self,
@@ -282,6 +307,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 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
@@ -39,11 +39,25 @@
GBinderLocalReply*
gbinder_local_reply_new(
const GBinderIo* io);
const GBinderIo* io)
GBINDER_INTERNAL;
GBinderOutputData*
gbinder_local_reply_data(
GBinderLocalReply* reply);
GBinderLocalReply* reply)
GBINDER_INTERNAL;
GBinderBufferContents*
gbinder_local_reply_contents(
GBinderLocalReply* reply)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_local_reply_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.
* 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
@@ -31,8 +31,11 @@
*/
#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"
#include "gbinder_io.h"
#include "gbinder_log.h"
#include <gutil_intarray.h>
@@ -89,6 +92,7 @@ gbinder_local_request_new(
if (init) {
gsize size;
gconstpointer data = g_bytes_get_data(init, &size);
writer->bytes = g_byte_array_sized_new(size);
g_byte_array_append(writer->bytes, data, size);
} else {
@@ -101,6 +105,49 @@ gbinder_local_request_new(
return NULL;
}
GBinderLocalRequest*
gbinder_local_request_new_iface(
const GBinderIo* io,
const GBinderRpcProtocol* protocol,
const char* iface)
{
GBinderLocalRequest* self = gbinder_local_request_new(io, NULL);
if (self && G_LIKELY(protocol) && G_LIKELY(iface)) {
GBinderWriter writer;
gbinder_local_request_init_writer(self, &writer);
protocol->write_rpc_header(&writer, iface);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_new_from_data(
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
{
GBinderLocalRequest* self = gbinder_local_request_new
(gbinder_buffer_io(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 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
@@ -40,11 +40,34 @@
GBinderLocalRequest*
gbinder_local_request_new(
const GBinderIo* io,
GBytes* init);
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);
GBinderLocalRequest* req)
GBINDER_INTERNAL;
void
gbinder_local_request_append_contents(
GBinderLocalRequest* req,
GBinderBuffer* buffer,
gsize offset,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */

62
src/gbinder_log.c Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_log.h"
#include <gutil_misc.h>
#include <stdlib.h>
/* Log module */
GLOG_MODULE_DEFINE("gbinder");
/* Initializes the default log level at startup */
void
gbinder_log_init(
void)
{
int level = GLOG_MODULE_NAME.level;
if (gutil_parse_int(getenv("GBINDER_DEFAULT_LOG_LEVEL"), 0, &level) &&
level >= GLOG_LEVEL_INHERIT && level <= GLOG_LEVEL_VERBOSE) {
GINFO("Log level %d", level);
GLOG_MODULE_NAME.level = level;
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -33,11 +33,18 @@
#ifndef GBINDER_LOG_H
#define GBINDER_LOG_H
#include "gbinder_types.h"
#include "gbinder_types_p.h"
#define GLOG_MODULE_NAME GBINDER_LOG_MODULE
#include <gutil_log.h>
/* Declared for unit tests */
__attribute__((constructor))
void
gbinder_log_init(
void)
GBINDER_INTERNAL;
#endif /* GBINDER_LOG_H */
/*

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 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -35,13 +35,19 @@
#include "gbinder_types_p.h"
typedef enum gbinder_remote_registry_create {
REMOTE_REGISTRY_DONT_CREATE,
REMOTE_REGISTRY_CAN_CREATE,
REMOTE_REGISTRY_CAN_CREATE_AND_ACQUIRE
} REMOTE_REGISTRY_CREATE;
typedef struct gbinder_object_registry_functions {
void (*ref)(GBinderObjectRegistry* reg);
void (*unref)(GBinderObjectRegistry* reg);
GBinderLocalObject* (*get_local)(GBinderObjectRegistry* reg,
void* pointer);
GBinderRemoteObject* (*get_remote)(GBinderObjectRegistry* reg,
guint32 handle);
guint32 handle, REMOTE_REGISTRY_CREATE create);
} GBinderObjectRegistryFunctions;
struct gbinder_object_registry {
@@ -81,9 +87,10 @@ GBINDER_INLINE_FUNC
GBinderRemoteObject*
gbinder_object_registry_get_remote(
GBinderObjectRegistry* reg,
guint32 handle)
guint32 handle,
REMOTE_REGISTRY_CREATE create)
{
return reg ? reg->f->get_remote(reg, handle) : NULL;
return reg ? reg->f->get_remote(reg, handle, create) : NULL;
}
#endif /* GBINDER_OBJECT_REGISTRY_H */

View File

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

422
src/gbinder_proxy_object.c Normal file
View File

@@ -0,0 +1,422 @@
/*
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_proxy_object.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_request.h"
#include "gbinder_local_reply.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_remote_request_p.h"
#include "gbinder_remote_reply_p.h"
#include "gbinder_object_converter.h"
#include "gbinder_object_registry.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
#include <errno.h>
typedef GBinderLocalObjectClass GBinderProxyObjectClass;
typedef struct gbinder_proxy_tx GBinderProxyTx;
struct gbinder_proxy_tx {
GBinderProxyTx* next;
GBinderRemoteRequest* req;
GBinderProxyObject* proxy;
gulong id;
};
struct gbinder_proxy_object_priv {
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 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:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -38,6 +38,9 @@
#include <gutil_macros.h>
#include <errno.h>
#include <fcntl.h>
typedef struct gbinder_reader_priv {
const guint8* start;
const guint8* end;
@@ -50,6 +53,8 @@ G_STATIC_ASSERT(sizeof(GBinderReader) >= sizeof(GBinderReaderPriv));
static inline GBinderReaderPriv* gbinder_reader_cast(GBinderReader* reader)
{ return (GBinderReaderPriv*)reader; }
static inline const GBinderReaderPriv* gbinder_reader_cast_c
(const GBinderReader* reader) { return (GBinderReaderPriv*)reader; }
void
gbinder_reader_init(
@@ -81,11 +86,11 @@ gbinder_reader_init(
gboolean
gbinder_reader_at_end(
GBinderReader* reader)
const GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
return p->ptr >= p->end;
return !p || p->ptr >= p->end;
}
static
@@ -133,6 +138,62 @@ gbinder_reader_read_bool(
}
}
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 */
{
/* Primitive values are supposed to be padded to 4-byte boundary */
if (value) {
guint32 padded;
if (gbinder_reader_read_uint32(reader, &padded)) {
*value = (guint8)padded;
return TRUE;
} else {
return FALSE;
}
} else {
return gbinder_reader_read_uint32(reader, NULL);
}
}
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 */
{
/* Primitive values are supposed to be padded to 4-byte boundary */
if (value) {
guint32 padded;
if (gbinder_reader_read_uint32(reader, &padded)) {
*value = (guint16)padded;
return TRUE;
} else {
return FALSE;
}
} else {
return gbinder_reader_read_uint32(reader, NULL);
}
}
gboolean
gbinder_reader_read_int32(
GBinderReader* reader,
@@ -229,16 +290,67 @@ gbinder_reader_read_double(
}
}
static
inline
gboolean
gbinder_reader_can_read_object(
GBinderReaderPriv* p)
{
const GBinderReaderData* data = p->data;
return data && data->reg &&
p->objects && p->objects[0] &&
p->ptr == p->objects[0];
}
int
gbinder_reader_read_fd(
GBinderReader* reader) /* Since 1.0.18 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
if (gbinder_reader_can_read_object(p)) {
int fd;
const guint eaten = p->data->reg->io->decode_fd_object(p->ptr,
gbinder_reader_bytes_remaining(reader), &fd);
if (eaten) {
GASSERT(fd >= 0);
p->ptr += eaten;
p->objects++;
return fd;
}
}
return -1;
}
int
gbinder_reader_read_dup_fd(
GBinderReader* reader) /* Since 1.0.18 */
{
const int fd = gbinder_reader_read_fd(reader);
if (fd >= 0) {
const int dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
if (dupfd >= 0) {
return dupfd;
} else {
GWARN("Error dupping fd %d: %s", fd, strerror(errno));
}
}
return -1;
}
gboolean
gbinder_reader_read_nullable_object(
GBinderReader* reader,
GBinderRemoteObject** out)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderData* data = p->data;
if (data && data->reg && p->objects && p->objects[0] &&
p->ptr == p->objects[0]) {
if (gbinder_reader_can_read_object(p)) {
const GBinderReaderData* data = p->data;
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
gbinder_reader_bytes_remaining(reader), data->reg, out);
@@ -264,15 +376,14 @@ gbinder_reader_read_object(
static
gboolean
gbinder_reader_read_buffer_impl(
gbinder_reader_read_buffer_object(
GBinderReader* reader,
GBinderBuffer** out)
GBinderIoBufferObject* out)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderData* data = p->data;
if (data && data->reg && p->objects && p->objects[0] &&
p->ptr == p->objects[0]) {
if (gbinder_reader_can_read_object(p)) {
const GBinderReaderData* data = p->data;
GBinderBuffer* buf = data->buffer;
const GBinderIo* io = data->reg->io;
const gsize offset = p->ptr - (guint8*)buf->data;
@@ -284,7 +395,6 @@ gbinder_reader_read_buffer_impl(
return TRUE;
}
}
if (out) *out = NULL;
return FALSE;
}
@@ -292,101 +402,212 @@ GBinderBuffer*
gbinder_reader_read_buffer(
GBinderReader* reader)
{
GBinderBuffer* buf = NULL;
GBinderIoBufferObject obj;
gbinder_reader_read_buffer_impl(reader, &buf);
return buf;
if (gbinder_reader_read_buffer_object(reader, &obj)) {
const GBinderReaderData* data = gbinder_reader_cast(reader)->data;
GBinderBuffer* buf = data->buffer;
return gbinder_buffer_new_with_parent(buf, obj.data, obj.size);
}
return NULL;
}
gboolean
gbinder_reader_skip_buffer(
GBinderReader* reader)
{
return gbinder_reader_read_buffer_impl(reader, NULL);
return gbinder_reader_read_buffer_object(reader, NULL);
}
/*
* 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(
GBinderReader* reader,
gsize size) /* Since 1.0.9 */
{
GBinderIoBufferObject obj;
if (gbinder_reader_read_buffer_object(reader, &obj) && obj.size == size) {
return obj.data;
}
return NULL;
}
/* Doesn't copy the data */
const void*
gbinder_reader_read_hidl_vec(
GBinderReader* reader,
gsize* count,
gsize* elemsize)
{
GBinderIoBufferObject obj;
const void* out = NULL;
gsize out_count = 0, out_elemsize = 0;
if (gbinder_reader_read_buffer_object(reader, &obj) &&
obj.data && obj.size == sizeof(GBinderHidlVec)) {
const GBinderHidlVec* vec = obj.data;
const void* next = vec->data.ptr;
if (next) {
if (gbinder_reader_read_buffer_object(reader, &obj) &&
obj.data == next && ((!vec->count && !obj.size) ||
(vec->count && obj.size && !(obj.size % vec->count)))) {
out_elemsize = vec->count ? (obj.size / vec->count) : 0;
out_count = vec->count;
out = obj.data;
}
} else if (!vec->count) {
/* Any non-NULL pointer just to indicate success? */
out = vec;
}
}
if (elemsize) {
*elemsize = out_elemsize;
}
if (count) {
*count = out_count;
}
return out;
}
/* Helper for gbinder_reader_read_hidl_struct_vec() macro */
const void*
gbinder_reader_read_hidl_vec1(
GBinderReader* reader,
gsize* count,
guint expected_elem_size) /* Since 1.0.9 */
{
gsize actual;
const void* data = gbinder_reader_read_hidl_vec(reader, count, &actual);
/* Actual size will be zero for an empty array */
return (data && (actual == expected_elem_size || !actual)) ? data : NULL;
}
const char*
gbinder_reader_read_hidl_string_c(
GBinderReader* reader) /* Since 1.0.23 */
{
GBinderIoBufferObject obj;
if (gbinder_reader_read_buffer_object(reader, &obj) &&
obj.data && obj.size == sizeof(GBinderHidlString)) {
const GBinderHidlString* str = obj.data;
if (gbinder_reader_read_buffer_object(reader, &obj) &&
obj.has_parent &&
obj.parent_offset == GBINDER_HIDL_STRING_BUFFER_OFFSET &&
obj.data == str->data.str &&
obj.size == str->len + 1 &&
str->data.str[str->len] == 0) {
return str->data.str;
}
}
return NULL;
}
char*
gbinder_reader_read_hidl_string(
GBinderReader* reader)
{
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
char* str = NULL;
if (buf && buf->size == sizeof(HidlString)) {
const HidlString* s = buf->data;
GBinderBuffer* sbuf = gbinder_reader_read_buffer(reader);
if (sbuf && sbuf->size == s->len + 1 &&
sbuf->data == s->data.str &&
s->data.str[s->len] == 0) {
str = g_strdup(s->data.str);
}
gbinder_buffer_free(sbuf);
}
gbinder_buffer_free(buf);
return str;
/* This function should've been called gbinder_reader_dup_hidl_string */
return g_strdup(gbinder_reader_read_hidl_string_c(reader));
}
char**
gbinder_reader_read_hidl_string_vec(
GBinderReader* reader)
{
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
GBinderIoBufferObject obj;
/* First buffer contains hidl_vector */
if (buf && buf->size == sizeof(HidlVec)) {
HidlVec* vec = buf->data;
if (gbinder_reader_read_buffer_object(reader, &obj) &&
obj.data && obj.size == sizeof(GBinderHidlVec)) {
GBinderHidlVec* vec = obj.data;
const guint n = vec->count;
const void* next = vec->data.ptr;
gbinder_buffer_free(buf);
if (!next && !n) {
char** out = g_new(char*, 1);
/* Should this be considered an error? */
return g_new0(char*, 1);
} else if (gbinder_reader_read_buffer_object(reader, &obj) &&
/* The second buffer (if any) contains n hidl_string's */
obj.parent_offset == GBINDER_HIDL_VEC_BUFFER_OFFSET &&
obj.has_parent &&
obj.data == next &&
obj.size == (sizeof(GBinderHidlString) * n)) {
const GBinderHidlString* strings = obj.data;
GPtrArray* list = g_ptr_array_sized_new(n + 1);
guint i;
out[0] = NULL;
return out;
} else {
/* The second buffer (if any) contains n hidl_string's */
buf = gbinder_reader_read_buffer(reader);
if (buf && buf->data == next && buf->size == sizeof(HidlString)*n) {
const HidlString* strings = buf->data;
GBinderBuffer* sbuf;
GPtrArray* list = g_ptr_array_new();
guint i;
/* Now we expect n buffers containing the actual data */
for (i = 0; i < n &&
gbinder_reader_read_buffer_object(reader, &obj); i++) {
const GBinderHidlString* s = strings + i;
const gsize expected_offset = (i * sizeof(*s)) +
GBINDER_HIDL_STRING_BUFFER_OFFSET;
if (obj.has_parent &&
obj.parent_offset == expected_offset &&
obj.data == s->data.str &&
obj.size == s->len + 1 &&
s->data.str[s->len] == 0) {
char* name = g_strdup(s->data.str);
/* Now we expect n buffers containing the actual data */
for (i=0; i<n &&
(sbuf = gbinder_reader_read_buffer(reader)); i++) {
const HidlString* s = strings + i;
if (sbuf->size == s->len + 1 &&
sbuf->data == s->data.str &&
s->data.str[s->len] == 0) {
char* name = g_strdup(s->data.str);
g_ptr_array_add(list, name);
GVERBOSE_("%u. %s", i + 1, name);
gbinder_buffer_free(sbuf);
} else {
GWARN("Unexpected hidl_string buffer %p/%u vs %p/%u",
sbuf->data, (guint)sbuf->size, s->data.str, s->len);
gbinder_buffer_free(sbuf);
break;
}
g_ptr_array_add(list, name);
GVERBOSE_("%u. %s", i + 1, name);
} else {
GWARN("Unexpected hidl_string buffer %p/%u vs %p/%u",
obj.data, (guint)obj.size, s->data.str, s->len);
break;
}
if (i == n) {
gbinder_buffer_free(buf);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
g_ptr_array_set_free_func(list, g_free);
g_ptr_array_free(list, TRUE);
}
if (i == n) {
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
g_ptr_array_set_free_func(list, g_free);
g_ptr_array_free(list, TRUE);
}
}
GWARN("Invalid hidl_vec<string>");
gbinder_buffer_free(buf);
return NULL;
}
@@ -418,6 +639,24 @@ gboolean
gbinder_reader_read_nullable_string16(
GBinderReader* reader,
char** out)
{
const gunichar2* str;
gsize len;
if (gbinder_reader_read_nullable_string16_utf16(reader, &str, &len)) {
if (out) {
*out = str ? g_utf16_to_utf8(str, len, NULL, NULL, NULL) : NULL;
}
return TRUE;
}
return FALSE;
}
gboolean
gbinder_reader_read_nullable_string16_utf16(
GBinderReader* reader,
const gunichar2** out,
gsize* out_len) /* Since 1.0.17 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
@@ -431,15 +670,21 @@ gbinder_reader_read_nullable_string16(
if (out) {
*out = NULL;
}
if (out_len) {
*out_len = 0;
}
return TRUE;
} else if (len >= 0) {
const guint32 padded_len = G_ALIGN4((len+1)*2);
const gunichar2* utf16 = (const gunichar2*)(p->ptr + 4);
const guint32 padded_len = G_ALIGN4((len + 1)*2);
const gunichar2* utf16 = (gunichar2*)(p->ptr + 4);
if ((p->ptr + padded_len + 4) <= p->end) {
p->ptr += padded_len + 4;
if (out) {
*out = g_utf16_to_utf8(utf16, len, NULL, NULL, NULL);
*out = utf16;
}
if (out_len) {
*out_len = len;
}
return TRUE;
}
@@ -448,6 +693,21 @@ gbinder_reader_read_nullable_string16(
return FALSE;
}
const gunichar2*
gbinder_reader_read_string16_utf16(
GBinderReader* reader,
gsize* len) /* Since 1.0.26 */
{
const gunichar2* str;
/*
* Use gbinder_reader_read_nullable_string16_utf16 to distinguish
* NULL string from a parsing failure.
*/
return gbinder_reader_read_nullable_string16_utf16(reader, &str, len) ?
str : NULL;
}
char*
gbinder_reader_read_string16(
GBinderReader* reader)
@@ -484,22 +744,85 @@ gbinder_reader_skip_string16(
return FALSE;
}
gsize
gbinder_reader_bytes_read(
GBinderReader* reader)
const void*
gbinder_reader_read_byte_array(
GBinderReader* reader,
gsize* len) /* Since 1.0.12 */
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const void* data = NULL;
const gint32* ptr;
*len = 0;
return p->ptr - p->start;
if (gbinder_reader_can_read(p, sizeof(*ptr))) {
ptr = (void*)p->ptr;
if (*ptr <= 0) {
p->ptr += sizeof(*ptr);
/* Any non-NULL pointer just to indicate success */
data = p->start;
} else if (gbinder_reader_can_read(p, sizeof(*ptr) + *ptr)) {
*len = (gsize)*ptr;
p->ptr += sizeof(*ptr);
data = p->ptr;
p->ptr += *len;
}
}
return data;
}
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 ? (p->ptr - p->start) : 0;
}
gsize
gbinder_reader_bytes_remaining(
GBinderReader* reader)
const GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderPriv* p = gbinder_reader_cast_c(reader);
return p->end - p->ptr;
return p ? (p->end - p->ptr) : 0;
}
void
gbinder_reader_copy(
GBinderReader* dest,
const GBinderReader* src)
{
if (src) {
memcpy(dest, src, sizeof(*dest));
} else {
memset(dest, 0, sizeof(*dest));
}
}
/*

View File

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

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:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -30,22 +30,26 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_servicemanager_p.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_log.h"
struct gbinder_remote_object_priv {
GMainContext* context;
gboolean acquired;
};
typedef GObjectClass GBinderRemoteObjectClass;
GType gbinder_remote_object_get_type(void) GBINDER_INTERNAL;
G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT)
GType gbinder_remote_object_get_type(void);
#define GBINDER_TYPE_REMOTE_OBJECT (gbinder_remote_object_get_type())
#define GBINDER_REMOTE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObject))
#define PARENT_CLASS gbinder_remote_object_parent_class
#define THIS_TYPE (gbinder_remote_object_get_type())
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,THIS_TYPE,GBinderRemoteObject)
enum gbinder_remote_object_signal {
SIGNAL_DEATH,
@@ -62,21 +66,100 @@ static guint gbinder_remote_object_signals[SIGNAL_COUNT] = { 0 };
static
void
gbinder_remote_object_died_on_main_thread(
GBinderRemoteObject* self)
gbinder_remote_object_handle_death_on_main_thread(
gpointer user_data)
{
GASSERT(!self->dead);
self->dead = TRUE;
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
GBinderRemoteObject* self = THIS(user_data);
if (!self->dead) {
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
GBinderRemoteObjectPriv* priv = self->priv;
self->dead = TRUE;
if (priv->acquired) {
priv->acquired = FALSE;
/* Release the dead node */
gbinder_driver_release(driver, self->handle);
}
/* ServiceManager always has the same handle, and can be reanimated. */
if (self->handle != GBINDER_SERVICEMANAGER_HANDLE) {
gbinder_ipc_invalidate_remote_handle(ipc, self->handle);
}
gbinder_driver_dead_binder_done(driver, self);
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
}
}
static
/*==========================================================================*
* Internal interface
*==========================================================================*/
gboolean
gbinder_remote_object_died_handle(
gpointer self)
gbinder_remote_object_reanimate(
GBinderRemoteObject* self)
{
gbinder_remote_object_died_on_main_thread(GBINDER_REMOTE_OBJECT(self));
return G_SOURCE_REMOVE;
/*
* Don't try to reanimate those who hasn't died yet. Reanimation is
* kind of a special case and should only be used for servicemanager
* objects.
*/
if (self->dead) {
GBinderIpc* ipc = self->ipc;
guint32 handle = self->handle;
/* Kick the horse */
GASSERT(self->handle == GBINDER_SERVICEMANAGER_HANDLE);
if (gbinder_ipc_ping_sync(ipc, handle, &gbinder_ipc_sync_main) == 0) {
GBinderRemoteObjectPriv* priv = self->priv;
GBinderDriver* driver = ipc->driver;
/* Wow, it's alive! */
self->dead = FALSE;
priv->acquired = TRUE;
gbinder_ipc_looper_check(ipc); /* For death notifications */
gbinder_driver_acquire(driver, handle);
gbinder_driver_request_death_notification(driver, self);
}
}
return !self->dead;
}
void
gbinder_remote_object_handle_death_notification(
GBinderRemoteObject* self)
{
/* This function is invoked from the looper thread, the caller has
* checked the object pointer */
GVERBOSE_("%p %u", self, self->handle);
gbinder_idle_callback_invoke_later
(gbinder_remote_object_handle_death_on_main_thread,
gbinder_remote_object_ref(self), g_object_unref);
}
void
gbinder_remote_object_commit_suicide(
GBinderRemoteObject* self)
{
/* This function is only invoked by GBinderProxyObject in context of
* the main thread, the object pointer is checked by the caller */
if (!self->dead) {
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
GBinderRemoteObjectPriv* priv = self->priv;
self->dead = TRUE;
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);
}
}
/*==========================================================================*
@@ -86,15 +169,32 @@ gbinder_remote_object_died_handle(
GBinderRemoteObject*
gbinder_remote_object_new(
GBinderIpc* ipc,
guint32 handle)
guint32 handle,
REMOTE_OBJECT_CREATE create)
{
if (G_LIKELY(ipc) && gbinder_driver_acquire(ipc->driver, handle)) {
GBinderRemoteObject* self = g_object_new
(GBINDER_TYPE_REMOTE_OBJECT, NULL);
if (G_LIKELY(ipc)) {
GBinderRemoteObject* self = g_object_new(THIS_TYPE, NULL);
GBinderRemoteObjectPriv* priv = self->priv;
self->ipc = gbinder_ipc_ref(ipc);
self->handle = handle;
gbinder_driver_request_death_notification(ipc->driver, self);
switch (create) {
case REMOTE_OBJECT_CREATE_DEAD:
self->dead = TRUE;
break;
case REMOTE_OBJECT_CREATE_ACQUIRED:
priv->acquired = TRUE;
/* fallthrough */
case REMOTE_OBJECT_CREATE_ALIVE:
break;
}
if (!self->dead) {
gbinder_ipc_looper_check(self->ipc); /* For death notifications */
if (priv->acquired) {
gbinder_driver_acquire(ipc->driver, handle);
}
gbinder_driver_request_death_notification(ipc->driver, self);
}
return self;
}
return NULL;
@@ -105,7 +205,7 @@ gbinder_remote_object_ref(
GBinderRemoteObject* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_REMOTE_OBJECT(self));
g_object_ref(THIS(self));
return self;
} else {
return NULL;
@@ -117,10 +217,17 @@ gbinder_remote_object_unref(
GBinderRemoteObject* self)
{
if (G_LIKELY(self)) {
g_object_unref(GBINDER_REMOTE_OBJECT(self));
g_object_unref(THIS(self));
}
}
GBinderIpc*
gbinder_remote_object_ipc(
GBinderRemoteObject* self) /* Since 1.0.30 */
{
return G_LIKELY(self) ? self->ipc : NULL;
}
gboolean
gbinder_remote_object_is_dead(
GBinderRemoteObject* self)
@@ -152,18 +259,6 @@ gbinder_remote_object_remove_handler(
}
}
void
gbinder_remote_object_handle_death_notification(
GBinderRemoteObject* self)
{
/* This function is invoked from the looper thread, the caller has
* checked the object pointer */
GVERBOSE_("%p %u", self, self->handle);
g_main_context_invoke_full(self->priv->context, G_PRIORITY_DEFAULT,
gbinder_remote_object_died_handle, gbinder_remote_object_ref(self),
g_object_unref);
}
/*==========================================================================*
* Internals
*==========================================================================*/
@@ -174,36 +269,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_driver_clear_death_notification(driver, self);
gbinder_driver_release(driver, self->handle);
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 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -51,14 +51,33 @@ struct gbinder_remote_object {
#define gbinder_remote_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
#define gbinder_remote_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
typedef enum gbinder_remote_object_create {
REMOTE_OBJECT_CREATE_DEAD,
REMOTE_OBJECT_CREATE_ALIVE,
REMOTE_OBJECT_CREATE_ACQUIRED
} REMOTE_OBJECT_CREATE;
GBinderRemoteObject*
gbinder_remote_object_new(
GBinderIpc* ipc,
guint32 handle);
guint32 handle,
REMOTE_OBJECT_CREATE create)
GBINDER_INTERNAL;
gboolean
gbinder_remote_object_reanimate(
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
void
gbinder_remote_object_handle_death_notification(
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
void
gbinder_remote_object_commit_suicide(
GBinderRemoteObject* self)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_OBJECT_PRIVATE_H */

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
@@ -31,9 +31,10 @@
*/
#include "gbinder_remote_reply_p.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_reader_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_buffer.h"
#include "gbinder_buffer_p.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
@@ -64,26 +65,22 @@ gbinder_remote_reply_free(
gbinder_object_registry_unref(data->reg);
gbinder_buffer_free(data->buffer);
g_free(data->objects);
g_slice_free(GBinderRemoteReply, self);
}
void
gbinder_remote_reply_set_data(
GBinderRemoteReply* self,
GBinderBuffer* buffer,
void** objects)
GBinderBuffer* buffer)
{
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
g_free(data->objects);
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = objects;
data->objects = gbinder_buffer_objects(buffer);
} else {
gbinder_buffer_free(buffer);
g_free(objects);
}
}
@@ -117,6 +114,30 @@ gbinder_remote_reply_is_empty(
return !self || !self->data.buffer || !self->data.buffer->size;
}
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;
if (reg) {
return gbinder_local_reply_set_contents
(gbinder_local_reply_new(reg->io), d->buffer, convert);
}
}
return NULL;
}
static
inline
void

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
@@ -39,17 +39,25 @@
GBinderRemoteReply*
gbinder_remote_reply_new(
GBinderObjectRegistry* reg);
GBinderObjectRegistry* reg)
GBINDER_INTERNAL;
GBinderLocalReply*
gbinder_remote_reply_convert_to_local(
GBinderRemoteReply* reply,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
void
gbinder_remote_reply_set_data(
GBinderRemoteReply* reply,
GBinderBuffer* buffer,
void** objects);
GBinderBuffer* buffer)
GBINDER_INTERNAL;
gboolean
gbinder_remote_reply_is_empty(
GBinderRemoteReply* reply);
GBinderRemoteReply* reply)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_REPLY_PRIVATE_H */

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
@@ -33,13 +33,19 @@
#include "gbinder_remote_request_p.h"
#include "gbinder_reader_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_local_request_p.h"
#include "gbinder_object_converter.h"
#include "gbinder_object_registry.h"
#include "gbinder_buffer.h"
#include "gbinder_buffer_p.h"
#include "gbinder_driver.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
struct gbinder_remote_request {
#include <errno.h>
typedef struct gbinder_remote_request_priv {
GBinderRemoteRequest pub;
gint refcount;
pid_t pid;
uid_t euid;
@@ -48,7 +54,11 @@ struct gbinder_remote_request {
char* iface2;
gsize header_size;
GBinderReaderData data;
};
} GBinderRemoteRequestPriv;
GBINDER_INLINE_FUNC GBinderRemoteRequestPriv*
gbinder_remote_request_cast(GBinderRemoteRequest* pub)
{ return G_LIKELY(pub) ? G_CAST(pub,GBinderRemoteRequestPriv,pub) : NULL; }
GBinderRemoteRequest*
gbinder_remote_request_new(
@@ -57,7 +67,7 @@ gbinder_remote_request_new(
pid_t pid,
uid_t euid)
{
GBinderRemoteRequest* self = g_slice_new0(GBinderRemoteRequest);
GBinderRemoteRequestPriv* self = g_slice_new0(GBinderRemoteRequestPriv);
GBinderReaderData* data = &self->data;
g_atomic_int_set(&self->refcount, 1);
@@ -65,28 +75,73 @@ gbinder_remote_request_new(
self->euid = euid;
self->protocol = protocol;
data->reg = gbinder_object_registry_ref(reg);
return self;
return &self->pub;
}
GBinderLocalRequest*
gbinder_remote_request_copy_to_local(
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReaderData* d = &self->data;
return gbinder_local_request_new_from_data(d->buffer, 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;
}
static
void
gbinder_remote_request_free(
GBinderRemoteRequest* self)
GBinderRemoteRequestPriv* self)
{
GBinderReaderData* data = &self->data;
GBinderRemoteRequest* req = &self->pub;
GASSERT(!req->tx);
if (req->tx) {
GWARN("Request is dropped without completing the transaction");
gbinder_remote_request_complete(req, NULL, -ECANCELED);
}
gbinder_object_registry_unref(data->reg);
gbinder_buffer_free(data->buffer);
g_free(data->objects);
g_free(self->iface2);
g_slice_free(GBinderRemoteRequest, self);
g_slice_free(GBinderRemoteRequestPriv, self);
}
static
inline
void
gbinder_remote_request_init_reader2(
GBinderRemoteRequest* self,
GBinderRemoteRequestPriv* self,
GBinderReader* p)
{
/* The caller has already checked the request for NULL */
@@ -103,53 +158,64 @@ gbinder_remote_request_init_reader2(
void
gbinder_remote_request_set_data(
GBinderRemoteRequest* self,
GBinderBuffer* buffer,
void** objects)
GBinderRemoteRequest* req,
guint32 txcode,
GBinderBuffer* buffer)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
GBinderReader reader;
g_free(self->iface2);
g_free(data->objects);
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = objects;
data->objects = gbinder_buffer_objects(buffer);
/* Parse RPC header */
self->header_size = 0;
gbinder_remote_request_init_reader2(self, &reader);
self->iface = self->protocol->read_rpc_header(&reader, &self->iface2);
self->header_size = gbinder_reader_bytes_read(&reader);
self->iface = self->protocol->read_rpc_header(&reader, txcode,
&self->iface2);
if (self->iface) {
self->header_size = gbinder_reader_bytes_read(&reader);
} else {
/* No RPC header */
self->header_size = 0;
}
} else {
gbinder_buffer_free(buffer);
g_free(objects);
}
}
const char*
gbinder_remote_request_interface(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
return G_LIKELY(self) ? self->iface : NULL;
}
GBinderRemoteRequest*
gbinder_remote_request_ref(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return self;
return req;
}
void
gbinder_remote_request_unref(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
@@ -160,9 +226,11 @@ gbinder_remote_request_unref(
void
gbinder_remote_request_init_reader(
GBinderRemoteRequest* self,
GBinderRemoteRequest* req,
GBinderReader* reader)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
gbinder_remote_request_init_reader2(self, reader);
} else {
@@ -172,15 +240,19 @@ gbinder_remote_request_init_reader(
pid_t
gbinder_remote_request_sender_pid(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
return G_LIKELY(self) ? self->pid : (uid_t)(-1);
}
uid_t
gbinder_remote_request_sender_euid(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
return G_LIKELY(self) ? self->euid : (uid_t)(-1);
}
@@ -194,9 +266,11 @@ gbinder_remote_request_read_int32(
gboolean
gbinder_remote_request_read_uint32(
GBinderRemoteRequest* self,
GBinderRemoteRequest* req,
guint32* value)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;
@@ -216,9 +290,11 @@ gbinder_remote_request_read_int64(
gboolean
gbinder_remote_request_read_uint64(
GBinderRemoteRequest* self,
GBinderRemoteRequest* req,
guint64* value)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;
@@ -230,8 +306,10 @@ gbinder_remote_request_read_uint64(
const char*
gbinder_remote_request_read_string8(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;
@@ -243,8 +321,10 @@ gbinder_remote_request_read_string8(
char*
gbinder_remote_request_read_string16(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;
@@ -256,8 +336,10 @@ gbinder_remote_request_read_string16(
GBinderRemoteObject*
gbinder_remote_request_read_object(
GBinderRemoteRequest* self)
GBinderRemoteRequest* req)
{
GBinderRemoteRequestPriv* self = gbinder_remote_request_cast(req);
if (G_LIKELY(self)) {
GBinderReader reader;

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
@@ -37,18 +37,30 @@
#include "gbinder_types_p.h"
struct gbinder_remote_request {
GBinderIpcLooperTx* tx;
};
GBinderRemoteRequest*
gbinder_remote_request_new(
GBinderObjectRegistry* reg,
const GBinderRpcProtocol* protocol,
pid_t pid,
uid_t euid);
uid_t euid)
GBINDER_INTERNAL;
void
gbinder_remote_request_set_data(
GBinderRemoteRequest* request,
GBinderBuffer* buffer,
void** objects);
guint txcode,
GBinderBuffer* buffer)
GBINDER_INTERNAL;
GBinderLocalRequest*
gbinder_remote_request_convert_to_local(
GBinderRemoteRequest* req,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -33,6 +33,15 @@
#include "gbinder_rpc_protocol.h"
#include "gbinder_reader.h"
#include "gbinder_writer.h"
#include "gbinder_config.h"
#include "gbinder_log.h"
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
#define UNSET_WORK_SOURCE (-1)
#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)
@@ -40,19 +49,47 @@
*
* platform/system/libhwbinder/Parcel.cpp
* platform/frameworks/native/libs/binder/Parcel.cpp
*
* which mutate from version to version. Specific device => protocol
* mapping can be optionally configured in /etc/gbinder.conf file.
* The default protocol configuration looks like this:
*
* [Protocol]
* Default = aidl
* /dev/binder = aidl
* /dev/hwbinder = hidl
*
*==========================================================================*/
#define CONF_GROUP GBINDER_CONFIG_GROUP_PROTOCOL
#define CONF_DEFAULT GBINDER_CONFIG_VALUE_DEFAULT
static GHashTable* gbinder_rpc_protocol_map = NULL;
/*
* Default protocol for those binder devices which which haven't been
* explicitely mapped.
*/
#define DEFAULT_PROTOCOL gbinder_rpc_protocol_aidl
static const GBinderRpcProtocol DEFAULT_PROTOCOL;
static const GBinderRpcProtocol* gbinder_rpc_protocol_default =
&DEFAULT_PROTOCOL;
/*==========================================================================*
* /dev/binder
* The original AIDL protocol.
*==========================================================================*/
/* No idea what that is... */
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
static
void
gbinder_rpc_protocol_binder_write_rpc_header(
gbinder_rpc_protocol_aidl_write_ping(
GBinderWriter* writer)
{
/* No payload */
}
static
void
gbinder_rpc_protocol_aidl_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
@@ -67,11 +104,15 @@ gbinder_rpc_protocol_binder_write_rpc_header(
static
const char*
gbinder_rpc_protocol_binder_read_rpc_header(
gbinder_rpc_protocol_aidl_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
{
if (gbinder_reader_read_int32(reader, NULL)) {
if (txcode > GBINDER_TRANSACTION(0,0,0)) {
/* Internal transaction e.g. GBINDER_DUMP_TRANSACTION etc. */
*iface = NULL;
} else if (gbinder_reader_read_int32(reader, NULL)) {
*iface = gbinder_reader_read_string16(reader);
} else {
*iface = NULL;
@@ -79,13 +120,113 @@ gbinder_rpc_protocol_binder_read_rpc_header(
return *iface;
}
static const GBinderRpcProtocol gbinder_rpc_protocol_aidl = {
.name = "aidl",
.ping_tx = GBINDER_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_aidl_write_ping,
.write_rpc_header = gbinder_rpc_protocol_aidl_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl_read_rpc_header
};
/*==========================================================================*
* /dev/hwbinder
* AIDL protocol appeared in Android 10 (API level 29)
*==========================================================================*/
static
void
gbinder_rpc_protocol_hwbinder_write_rpc_header(
gbinder_rpc_protocol_aidl2_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
/*
* writeInt32(IPCThreadState::self()->getStrictModePolicy() |
* STRICT_MODE_PENALTY_GATHER);
* writeInt32(IPCThreadState::kUnsetWorkSource);
* writeString16(interface);
*/
gbinder_writer_append_int32(writer, BINDER_RPC_FLAGS);
gbinder_writer_append_int32(writer, UNSET_WORK_SOURCE);
gbinder_writer_append_string16(writer, iface);
}
static
const char*
gbinder_rpc_protocol_aidl2_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
{
if (txcode > GBINDER_TRANSACTION(0,0,0)) {
/* Internal transaction e.g. GBINDER_DUMP_TRANSACTION etc. */
*iface = NULL;
} else if (gbinder_reader_read_int32(reader, NULL) /* flags */ &&
gbinder_reader_read_int32(reader, NULL) /* work source */) {
*iface = gbinder_reader_read_string16(reader);
} else {
*iface = NULL;
}
return *iface;
}
static const GBinderRpcProtocol gbinder_rpc_protocol_aidl2 = {
.name = "aidl2",
.ping_tx = GBINDER_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_aidl_write_ping, /* no payload */
.write_rpc_header = gbinder_rpc_protocol_aidl2_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_aidl2_read_rpc_header
};
/*==========================================================================*
* 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 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
};
/*==========================================================================*
* The original /dev/hwbinder protocol.
*==========================================================================*/
static
void
gbinder_rpc_protocol_hidl_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
@@ -95,16 +236,109 @@ gbinder_rpc_protocol_hwbinder_write_rpc_header(
gbinder_writer_append_string8(writer, iface);
}
static
void
gbinder_rpc_protocol_hidl_write_ping(
GBinderWriter* writer)
{
gbinder_rpc_protocol_hidl_write_rpc_header(writer,
"android.hidl.base@1.0::IBase");
}
static
const char*
gbinder_rpc_protocol_hwbinder_read_rpc_header(
gbinder_rpc_protocol_hidl_read_rpc_header(
GBinderReader* reader,
guint32 txcode,
char** iface)
{
*iface = NULL;
return gbinder_reader_read_string8(reader);
}
static const GBinderRpcProtocol gbinder_rpc_protocol_hidl = {
.name = "hidl",
.ping_tx = HIDL_PING_TRANSACTION,
.write_ping = gbinder_rpc_protocol_hidl_write_ping,
.write_rpc_header = gbinder_rpc_protocol_hidl_write_rpc_header,
.read_rpc_header = gbinder_rpc_protocol_hidl_read_rpc_header
};
/*==========================================================================*
* Implementation
*==========================================================================*/
/* All known protocols */
static const GBinderRpcProtocol* gbinder_rpc_protocol_list[] = {
&gbinder_rpc_protocol_aidl,
&gbinder_rpc_protocol_aidl2,
&gbinder_rpc_protocol_aidl3,
&gbinder_rpc_protocol_hidl
};
static
const GBinderRpcProtocol*
gbinder_rpc_protocol_find(
const char* name)
{
guint i;
for (i = 0; i < G_N_ELEMENTS(gbinder_rpc_protocol_list); i++) {
if (!g_ascii_strcasecmp(gbinder_rpc_protocol_list[i]->name, name)) {
return gbinder_rpc_protocol_list[i];
}
}
return NULL;
}
static
void
gbinder_rpc_protocol_map_add_default(
GHashTable* map,
const char* dev,
const GBinderRpcProtocol* protocol)
{
if (!g_hash_table_contains(map, dev)) {
g_hash_table_insert(map, g_strdup(dev), (gpointer) protocol);
}
}
static
gconstpointer
gbinder_rpc_protocol_value_map(
const char* name)
{
return gbinder_rpc_protocol_find(name);
}
static
GHashTable*
gbinder_rpc_protocol_load_config()
{
GHashTable* map = gbinder_config_load(CONF_GROUP,
gbinder_rpc_protocol_value_map);
/* Add default configuration if it's not overridden */
gbinder_rpc_protocol_map_add_default(map,
GBINDER_DEFAULT_BINDER, &gbinder_rpc_protocol_aidl);
gbinder_rpc_protocol_map_add_default(map,
GBINDER_DEFAULT_HWBINDER, &gbinder_rpc_protocol_hidl);
return map;
}
/* Runs at exit */
void
gbinder_rpc_protocol_exit()
{
if (gbinder_rpc_protocol_map) {
g_hash_table_destroy(gbinder_rpc_protocol_map);
gbinder_rpc_protocol_map = NULL;
}
/* Reset the default too, mostly for unit testing */
gbinder_rpc_protocol_default = &DEFAULT_PROTOCOL;
}
/*==========================================================================*
* Interface
*==========================================================================*/
@@ -113,18 +347,36 @@ const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device(
const char* dev)
{
static const GBinderRpcProtocol protocol_binder = {
.read_rpc_header = gbinder_rpc_protocol_binder_read_rpc_header,
.write_rpc_header = gbinder_rpc_protocol_binder_write_rpc_header
};
if (dev) {
const GBinderRpcProtocol* protocol;
static const GBinderRpcProtocol protocol_hwbinder = {
.read_rpc_header = gbinder_rpc_protocol_hwbinder_read_rpc_header,
.write_rpc_header = gbinder_rpc_protocol_hwbinder_write_rpc_header
};
if (!gbinder_rpc_protocol_map) {
const GBinderRpcProtocol* p;
return (dev && !strcmp(dev, GBINDER_DEFAULT_HWBINDER)) ?
&protocol_hwbinder : &protocol_binder;
/* One-time initialization */
gbinder_rpc_protocol_map = gbinder_rpc_protocol_load_config();
/* "Default" is a special value stored in a special variable */
p = g_hash_table_lookup(gbinder_rpc_protocol_map, CONF_DEFAULT);
if (p) {
g_hash_table_remove(gbinder_rpc_protocol_map, CONF_DEFAULT);
gbinder_rpc_protocol_default = p;
} else {
gbinder_rpc_protocol_default = &DEFAULT_PROTOCOL;
}
}
protocol = g_hash_table_lookup(gbinder_rpc_protocol_map, dev);
if (protocol) {
GDEBUG("Using %s protocol for %s", protocol->name, dev);
return protocol;
}
GDEBUG("Using default protocol %s for %s",
gbinder_rpc_protocol_default->name, dev);
} else {
GDEBUG("Using default protocol %s",
gbinder_rpc_protocol_default->name);
}
return gbinder_rpc_protocol_default;
}
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -36,18 +36,31 @@
#include "gbinder_types_p.h"
/*
* For whatever reason services communicating via /dev/binder
* and /dev/hwbinder use slightly different RPC headers.
* There are several versions of binder RPC protocol with diffferent
* transaction headers and transaction codes.
*/
struct gbinder_rpc_protocol {
const char* (*read_rpc_header)(GBinderReader* reader, char** iface);
const char* name;
guint32 ping_tx;
void (*write_ping)(GBinderWriter* writer);
void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
const char* (*read_rpc_header)(GBinderReader* reader, guint32 txcode,
char** iface);
};
/* Returns one of the above based on the device name */
const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device(
const char* dev);
const char* dev)
GBINDER_INTERNAL;
/* Runs at exit, declared here strictly for unit tests */
void
gbinder_rpc_protocol_exit(
void)
GBINDER_DESTRUCTOR
GBINDER_INTERNAL;
#endif /* GBINDER_RPC_PROTOCOL_H */

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
@@ -30,20 +30,91 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_servicemanager_p.h"
#include "gbinder_client_p.h"
#include "gbinder_config.h"
#include "gbinder_local_object_p.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gutil_idlepool.h>
#include <gutil_misc.h>
#include <errno.h>
/*==========================================================================*
*
* Different versions of Android come with different flavors of service
* managers. They are usually based on these two more or less independent
* variants:
*
* platform/frameworks/native/cmds/servicemanager/ServiceManager.cpp
* platform/system/hwservicemanager/ServiceManager.cpp
*
* They are talking slightly different protocols which slightly mutate
* from version to version. If that's not complex enough, different
* kinds of service managers can be running simultaneously, serving
* different binder devices. Specific device => servicemanager mapping
* can be optionally configured in /etc/gbinder.conf file. The default
* service manager configuration looks like this:
*
* [ServiceManager]
* Default = aidl
* /dev/binder = aidl
* /dev/hwbinder = hidl
*
*==========================================================================*/
#define CONF_GROUP GBINDER_CONFIG_GROUP_SERVICEMANAGER
#define CONF_DEFAULT GBINDER_CONFIG_VALUE_DEFAULT
typedef struct gbinder_servicemanager_type {
const char* name;
GType (*get_type)(void);
} GBinderServiceManagerType;
static const GBinderServiceManagerType gbinder_servicemanager_types[] = {
{ "aidl", gbinder_servicemanager_aidl_get_type },
{ "aidl2", gbinder_servicemanager_aidl2_get_type },
{ "aidl3", gbinder_servicemanager_aidl3_get_type },
{ "hidl", gbinder_servicemanager_hidl_get_type }
};
#define SERVICEMANAGER_TYPE_AIDL (gbinder_servicemanager_types + 0)
#define SERVICEMANAGER_TYPE_HIDL (gbinder_servicemanager_types + 3)
#define SERVICEMANAGER_TYPE_DEFAULT SERVICEMANAGER_TYPE_AIDL
static GHashTable* gbinder_servicemanager_map = NULL;
static const GBinderServiceManagerType* gbinder_servicemanager_default =
SERVICEMANAGER_TYPE_DEFAULT;
#define PRESENSE_WAIT_MS_MIN (100)
#define PRESENSE_WAIT_MS_MAX (1000)
#define PRESENSE_WAIT_MS_STEP (100)
typedef struct gbinder_servicemanager_watch {
char* name;
char* detail;
GQuark quark;
gboolean watched;
} GBinderServiceManagerWatch;
struct gbinder_servicemanager_priv {
GHashTable* watch_table;
gulong death_id;
gboolean present;
GBinderEventLoopTimeout* presence_check;
guint presence_check_delay_ms;
GBinderEventLoopCallback* autorelease_cb;
GSList* autorelease;
};
G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
G_TYPE_OBJECT)
@@ -51,15 +122,24 @@ G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
#define GBINDER_SERVICEMANAGER(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManager)
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
#define GBINDER_SERVICEMANAGER_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
#define GBINDER_IS_SERVICEMANAGER_TYPE(klass) \
G_TYPE_CHECK_CLASS_TYPE(klass, GBINDER_TYPE_SERVICEMANAGER)
enum gbinder_servicemanager_signal {
SIGNAL_PRESENCE,
SIGNAL_REGISTRATION,
SIGNAL_COUNT
};
static const char SIGNAL_PRESENCE_NAME[] = "servicemanager-presence";
static const char SIGNAL_REGISTRATION_NAME[] = "servicemanager-registration";
#define DETAIL_LEN 32
static guint gbinder_servicemanager_signals[SIGNAL_COUNT] = { 0 };
/*==========================================================================*
* Implementation
*==========================================================================*/
@@ -81,53 +161,29 @@ gbinder_servicemanager_class_ref(
return NULL;
}
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
GType type,
const char* dev)
static
GBinderServiceManagerWatch*
gbinder_servicemanager_watch_new(
const char* name)
{
GBinderServiceManager* self = NULL;
GBinderServiceManagerClass* klass = gbinder_servicemanager_class_ref(type);
GBinderServiceManagerWatch* watch = g_new0(GBinderServiceManagerWatch, 1);
if (klass) {
GBinderIpc* ipc;
watch->name = g_strdup(name);
watch->detail = g_compute_checksum_for_string(G_CHECKSUM_MD5, name, -1);
watch->quark = g_quark_from_string(watch->detail);
return watch;
}
if (!dev) dev = klass->default_device;
ipc = gbinder_ipc_new(dev);
if (ipc) {
GBinderRemoteObject* object = gbinder_ipc_get_remote_object
(ipc, klass->handle);
static
void
gbinder_servicemanager_watch_free(
gpointer data)
{
GBinderServiceManagerWatch* watch = data;
if (object) {
/* Lock */
g_mutex_lock(&klass->mutex);
if (klass->table) {
self = g_hash_table_lookup(klass->table, dev);
}
if (self) {
gbinder_servicemanager_ref(self);
} else {
char* key = g_strdup(dev); /* Owned by the hashtable */
GVERBOSE_("%s", dev);
self = g_object_new(type, NULL);
self->client = gbinder_client_new(object, klass->iface);
self->dev = gbinder_remote_object_dev(object);
if (!klass->table) {
klass->table = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, NULL);
}
g_hash_table_replace(klass->table, key, self);
}
g_mutex_unlock(&klass->mutex);
/* Unlock */
gbinder_remote_object_unref(object);
}
gbinder_ipc_unref(ipc);
}
g_type_class_unref(klass);
}
return self;
g_free(watch->name);
g_free(watch->detail);
g_free(watch);
}
typedef struct gbinder_servicemanager_list_tx_data {
@@ -144,7 +200,8 @@ gbinder_servicemanager_list_tx_exec(
{
GBinderServiceManagerListTxData* data = tx->user_data;
data->result = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->list(data->sm);
data->result = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
list(data->sm, &gbinder_ipc_sync_worker);
}
static
@@ -157,6 +214,7 @@ gbinder_servicemanager_list_tx_done(
if (!data->func(data->sm, data->result, data->user_data)) {
g_strfreev(data->result);
}
data->result = NULL;
}
static
@@ -166,6 +224,7 @@ gbinder_servicemanager_list_tx_free(
{
GBinderServiceManagerListTxData* data = user_data;
g_strfreev(data->result);
gbinder_servicemanager_unref(data->sm);
g_slice_free(GBinderServiceManagerListTxData, data);
}
@@ -186,8 +245,9 @@ gbinder_servicemanager_get_service_tx_exec(
{
GBinderServiceManagerGetServiceTxData* data = tx->user_data;
data->obj = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->get_service
(data->sm, data->name, &data->status);
data->obj = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
get_service(data->sm, data->name, &data->status,
&gbinder_ipc_sync_worker);
}
static
@@ -229,8 +289,8 @@ gbinder_servicemanager_add_service_tx_exec(
{
GBinderServiceManagerAddServiceTxData* data = tx->user_data;
data->status = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->add_service
(data->sm, data->name, data->obj);
data->status = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->
add_service(data->sm, data->name, data->obj, &gbinder_ipc_sync_worker);
}
static
@@ -256,6 +316,302 @@ gbinder_servicemanager_add_service_tx_free(
g_slice_free(GBinderServiceManagerAddServiceTxData, data);
}
static
void
gbinder_servicemanager_reanimated(
GBinderServiceManager* self)
{
GBinderServiceManagerPriv* priv = self->priv;
if (priv->presence_check) {
gbinder_timeout_remove(priv->presence_check);
priv->presence_check = NULL;
}
GINFO("Service manager %s has appeared", self->dev);
/* Re-arm the watches */
if (g_hash_table_size(priv->watch_table) > 0) {
gpointer value;
GHashTableIter it;
GBinderServiceManagerClass* klass =
GBINDER_SERVICEMANAGER_GET_CLASS(self);
g_hash_table_iter_init(&it, priv->watch_table);
while (g_hash_table_iter_next(&it, NULL, &value)) {
GBinderServiceManagerWatch* watch = value;
GASSERT(!watch->watched);
watch->watched = klass->watch(self, watch->name);
if (watch->watched) {
GDEBUG("Watching %s", watch->name);
} else {
GWARN("Failed to watch %s", watch->name);
}
}
}
g_signal_emit(self, gbinder_servicemanager_signals[SIGNAL_PRESENCE], 0);
}
static
gboolean
gbinder_servicemanager_presense_check_timer(
gpointer user_data)
{
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(user_data);
GBinderRemoteObject* remote = self->client->remote;
GBinderServiceManagerPriv* priv = self->priv;
gboolean result;
GASSERT(remote->dead);
gbinder_servicemanager_ref(self);
if (gbinder_remote_object_reanimate(remote)) {
/* Done */
priv->presence_check = NULL;
gbinder_servicemanager_reanimated(self);
result = G_SOURCE_REMOVE;
} else if (priv->presence_check_delay_ms < PRESENSE_WAIT_MS_MAX) {
priv->presence_check_delay_ms += PRESENSE_WAIT_MS_STEP;
priv->presence_check =
gbinder_timeout_add(priv->presence_check_delay_ms,
gbinder_servicemanager_presense_check_timer, self);
result = G_SOURCE_REMOVE;
} else {
result = G_SOURCE_CONTINUE;
}
gbinder_servicemanager_unref(self);
return result;
}
static
void
gbinder_servicemanager_presence_check_start(
GBinderServiceManager* self)
{
GBinderServiceManagerPriv* priv = self->priv;
GASSERT(!priv->presence_check);
priv->presence_check_delay_ms = PRESENSE_WAIT_MS_MIN;
priv->presence_check = gbinder_timeout_add(PRESENSE_WAIT_MS_MIN,
gbinder_servicemanager_presense_check_timer, self);
}
static
void
gbinder_servicemanager_died(
GBinderRemoteObject* remote,
void* user_data)
{
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(user_data);
GBinderServiceManagerPriv* priv = self->priv;
GWARN("Service manager %s has died", self->dev);
gbinder_servicemanager_presence_check_start(self);
/* Will re-arm watches after servicemanager gets restarted */
if (g_hash_table_size(priv->watch_table) > 0) {
gpointer value;
GHashTableIter it;
GBinderServiceManagerClass* klass =
GBINDER_SERVICEMANAGER_GET_CLASS(self);
g_hash_table_iter_init(&it, priv->watch_table);
while (g_hash_table_iter_next(&it, NULL, &value)) {
GBinderServiceManagerWatch* watch = value;
if (watch->watched) {
GDEBUG("Unwatching %s", watch->name);
watch->watched = FALSE;
klass->unwatch(self, watch->name);
}
}
}
g_signal_emit(self, gbinder_servicemanager_signals[SIGNAL_PRESENCE], 0);
}
static
void
gbinder_servicemanager_sleep_ms(
gulong ms)
{
struct timespec wait;
wait.tv_sec = ms/1000; /* seconds */
wait.tv_nsec = (ms % 1000) * 1000000; /* nanoseconds */
while (nanosleep(&wait, &wait) == -1 && errno == EINTR &&
(wait.tv_sec > 0 || wait.tv_nsec > 0));
}
static
void
gbinder_servicemanager_autorelease_cb(
gpointer data)
{
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(data);
GBinderServiceManagerPriv* priv = self->priv;
GSList* list = priv->autorelease;
priv->autorelease_cb = NULL;
priv->autorelease = NULL;
g_slist_free_full(list, g_object_unref);
}
static
void
gbinder_servicemanager_map_add_default(
GHashTable* map,
const char* dev,
const GBinderServiceManagerType* type)
{
if (!g_hash_table_contains(map, dev)) {
g_hash_table_insert(map, g_strdup(dev), (gpointer) type);
}
}
static
gconstpointer
gbinder_servicemanager_value_map(
const char* name)
{
guint i;
for (i = 0; i < G_N_ELEMENTS(gbinder_servicemanager_types); i++) {
const GBinderServiceManagerType* t = gbinder_servicemanager_types + i;
if (!g_strcmp0(name, t->name)) {
return t;
}
}
return NULL;
}
static
GHashTable*
gbinder_servicemanager_load_config()
{
GHashTable* map = gbinder_config_load(CONF_GROUP,
gbinder_servicemanager_value_map);
/* Add default configuration if it's not overridden */
gbinder_servicemanager_map_add_default(map,
GBINDER_DEFAULT_BINDER, SERVICEMANAGER_TYPE_AIDL);
gbinder_servicemanager_map_add_default(map,
GBINDER_DEFAULT_HWBINDER, SERVICEMANAGER_TYPE_HIDL);
return map;
}
/* Runs at exit */
void
gbinder_servicemanager_exit(
void)
{
if (gbinder_servicemanager_map) {
g_hash_table_destroy(gbinder_servicemanager_map);
gbinder_servicemanager_map = NULL;
}
/* Reset the default too, mostly for unit testing */
gbinder_servicemanager_default = SERVICEMANAGER_TYPE_DEFAULT;
}
/*==========================================================================*
* Internal interface
*==========================================================================*/
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
GType type,
const char* dev)
{
GBinderServiceManager* self = NULL;
GBinderServiceManagerClass* klass = gbinder_servicemanager_class_ref(type);
if (klass) {
GBinderIpc* ipc;
if (!dev) dev = klass->default_device;
ipc = gbinder_ipc_new(dev);
if (ipc) {
/* Create a (possibly) dead service manager object */
GBinderRemoteObject* object = gbinder_ipc_get_service_manager(ipc);
if (object) {
gboolean first_ref;
/* Lock */
g_mutex_lock(&klass->mutex);
if (klass->table) {
self = g_hash_table_lookup(klass->table, dev);
}
if (self) {
first_ref = FALSE;
gbinder_servicemanager_ref(self);
} else {
char* key = g_strdup(dev); /* Owned by the hashtable */
first_ref = TRUE;
self = g_object_new(type, NULL);
self->client = gbinder_client_new(object, klass->iface);
self->dev = gbinder_remote_object_dev(object);
if (!klass->table) {
klass->table = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, NULL);
}
g_hash_table_replace(klass->table, key, self);
}
g_mutex_unlock(&klass->mutex);
/* Unlock */
if (first_ref) {
GBinderServiceManagerPriv* priv = self->priv;
priv->death_id =
gbinder_remote_object_add_death_handler(object,
gbinder_servicemanager_died, self);
/* Query the actual state if necessary */
gbinder_remote_object_reanimate(object);
if (object->dead) {
gbinder_servicemanager_presence_check_start(self);
}
GDEBUG("%s has %sservice manager", dev,
object->dead ? "no " : "");
}
gbinder_remote_object_unref(object);
}
gbinder_ipc_unref(ipc);
}
g_type_class_unref(klass);
}
return self;
}
void
gbinder_servicemanager_service_registered(
GBinderServiceManager* self,
const char* name)
{
GBinderServiceManagerClass* klass = GBINDER_SERVICEMANAGER_GET_CLASS(self);
GBinderServiceManagerPriv* priv = self->priv;
GBinderServiceManagerWatch* watch = NULL;
const char* normalized_name;
char* tmp_name = NULL;
switch (klass->check_name(self, name)) {
case GBINDER_SERVICEMANAGER_NAME_OK:
normalized_name = name;
break;
case GBINDER_SERVICEMANAGER_NAME_NORMALIZE:
normalized_name = tmp_name = klass->normalize_name(self, name);
break;
default:
normalized_name = NULL;
break;
}
if (normalized_name) {
watch = g_hash_table_lookup(priv->watch_table, normalized_name);
}
g_free(tmp_name);
g_signal_emit(self, gbinder_servicemanager_signals[SIGNAL_REGISTRATION],
watch ? watch->quark : 0, name);
}
/*==========================================================================*
* Interface
*==========================================================================*/
@@ -264,11 +620,35 @@ GBinderServiceManager*
gbinder_servicemanager_new(
const char* dev)
{
if (!g_strcmp0(dev, GBINDER_DEFAULT_HWBINDER)) {
return gbinder_hwservicemanager_new(dev);
} else {
return gbinder_defaultservicemanager_new(dev);
if (dev) {
const GBinderServiceManagerType* type = NULL;
if (!gbinder_servicemanager_map) {
const GBinderServiceManagerType* t;
/* One-time initialization */
gbinder_servicemanager_map = gbinder_servicemanager_load_config();
/* "Default" is a special value stored in a special variable */
t = g_hash_table_lookup(gbinder_servicemanager_map, CONF_DEFAULT);
if (t) {
g_hash_table_remove(gbinder_servicemanager_map, CONF_DEFAULT);
gbinder_servicemanager_default = t;
} else {
gbinder_servicemanager_default = SERVICEMANAGER_TYPE_DEFAULT;
}
}
type = g_hash_table_lookup(gbinder_servicemanager_map, dev);
if (type) {
GDEBUG("Using %s service manager for %s", type->name, dev);
} else {
type = gbinder_servicemanager_default;
GDEBUG("Using default service manager %s for %s", type->name, dev);
}
return gbinder_servicemanager_new_with_type(type->get_type(), dev);
}
return NULL;
}
GBinderLocalObject*
@@ -277,10 +657,25 @@ gbinder_servicemanager_new_local_object(
const char* iface,
GBinderLocalTransactFunc txproc,
void* user_data)
{
const char* ifaces[2];
ifaces[0] = iface;
ifaces[1] = NULL;
return gbinder_servicemanager_new_local_object2
(self, ifaces, txproc, user_data);
}
GBinderLocalObject*
gbinder_servicemanager_new_local_object2(
GBinderServiceManager* self,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
{
if (G_LIKELY(self)) {
return gbinder_ipc_new_local_object(gbinder_client_ipc(self->client),
iface, txproc, user_data);
return gbinder_local_object_new(gbinder_client_ipc(self->client),
ifaces, txproc, user_data);
}
return NULL;
}
@@ -304,6 +699,65 @@ 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 */
{
return G_LIKELY(self) && !self->client->remote->dead;
}
gboolean
gbinder_servicemanager_wait(
GBinderServiceManager* self,
long max_wait_ms) /* Since 1.0.25 */
{
if (G_LIKELY(self)) {
GBinderRemoteObject* remote = self->client->remote;
if (!remote->dead) {
return TRUE;
} else if (gbinder_remote_object_reanimate(remote)) {
gbinder_servicemanager_reanimated(self);
return TRUE;
} else if (max_wait_ms != 0) {
/* Zero timeout means a singe check and it's already done */
long delay_ms = PRESENSE_WAIT_MS_MIN;
while (max_wait_ms != 0) {
if (max_wait_ms > 0) {
if (max_wait_ms < delay_ms) {
delay_ms = max_wait_ms;
max_wait_ms = 0;
} else {
max_wait_ms -= delay_ms;
}
}
gbinder_servicemanager_sleep_ms(delay_ms);
if (gbinder_remote_object_reanimate(remote)) {
gbinder_servicemanager_reanimated(self);
return TRUE;
}
if (delay_ms < PRESENSE_WAIT_MS_MAX) {
delay_ms += PRESENSE_WAIT_MS_STEP;
if (delay_ms > PRESENSE_WAIT_MS_MAX) {
delay_ms = PRESENSE_WAIT_MS_MAX;
}
}
}
/* Timeout */
GWARN("Timeout waiting for service manager %s", self->dev);
}
}
return FALSE;
}
gulong
gbinder_servicemanager_list(
GBinderServiceManager* self,
@@ -331,7 +785,8 @@ gbinder_servicemanager_list_sync(
GBinderServiceManager* self)
{
if (G_LIKELY(self)) {
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->list(self);
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->
list(self, &gbinder_ipc_sync_main);
}
return NULL;
}
@@ -370,12 +825,17 @@ gbinder_servicemanager_get_service_sync(
GBinderRemoteObject* obj = NULL;
if (G_LIKELY(self) && name) {
obj = GBINDER_SERVICEMANAGER_GET_CLASS(self)->get_service
(self, name, status);
if (!self->pool) {
self->pool = gutil_idle_pool_new();
obj = GBINDER_SERVICEMANAGER_GET_CLASS(self)->
get_service(self, name, status, &gbinder_ipc_sync_main);
if (obj) {
GBinderServiceManagerPriv* priv = self->priv;
priv->autorelease = g_slist_prepend(priv->autorelease, obj);
if (!priv->autorelease_cb) {
priv->autorelease_cb = gbinder_idle_callback_schedule_new
(gbinder_servicemanager_autorelease_cb, self, NULL);
}
}
gutil_idle_pool_add_object(self->pool, obj);
} else if (status) {
*status = (-EINVAL);
}
@@ -416,8 +876,8 @@ gbinder_servicemanager_add_service_sync(
GBinderLocalObject* obj)
{
if (G_LIKELY(self) && name && obj) {
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->add_service
(self, name, obj);
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->
add_service(self, name, obj, &gbinder_ipc_sync_main);
} else {
return (-EINVAL);
}
@@ -433,6 +893,140 @@ gbinder_servicemanager_cancel(
}
}
gulong
gbinder_servicemanager_add_presence_handler(
GBinderServiceManager* self,
GBinderServiceManagerFunc func,
void* user_data) /* Since 1.0.25 */
{
return (G_LIKELY(self) && G_LIKELY(func)) ? g_signal_connect(self,
SIGNAL_PRESENCE_NAME, G_CALLBACK(func), user_data) : 0;
}
gulong
gbinder_servicemanager_add_registration_handler(
GBinderServiceManager* self,
const char* name,
GBinderServiceManagerRegistrationFunc func,
void* data) /* Since 1.0.13 */
{
gulong id = 0;
if (G_LIKELY(self) && G_LIKELY(func)) {
char* tmp_name = NULL;
GBinderServiceManagerClass* klass =
GBINDER_SERVICEMANAGER_GET_CLASS(self);
switch (klass->check_name(self, name)) {
case GBINDER_SERVICEMANAGER_NAME_OK:
break;
case GBINDER_SERVICEMANAGER_NAME_NORMALIZE:
name = tmp_name = klass->normalize_name(self, name);
break;
default:
name = NULL;
break;
}
if (name) {
GBinderServiceManagerPriv* priv = self->priv;
GBinderServiceManagerWatch* watch = NULL;
watch = g_hash_table_lookup(priv->watch_table, name);
if (!watch) {
watch = gbinder_servicemanager_watch_new(name);
g_hash_table_insert(priv->watch_table, watch->name, watch);
}
if (!watch->watched && !self->client->remote->dead) {
watch->watched = klass->watch(self, watch->name);
if (watch->watched) {
GDEBUG("Watching %s", watch->name);
} else {
GWARN("Failed to watch %s", watch->name);
}
}
id = g_signal_connect_closure_by_id(self,
gbinder_servicemanager_signals[SIGNAL_REGISTRATION],
watch->quark, g_cclosure_new(G_CALLBACK(func), data, NULL),
FALSE);
}
g_free(tmp_name);
}
return id;
}
void
gbinder_servicemanager_remove_handler(
GBinderServiceManager* self,
gulong id) /* Since 1.0.13 */
{
gbinder_servicemanager_remove_handlers(self, &id, 1);
}
void
gbinder_servicemanager_remove_handlers(
GBinderServiceManager* self,
gulong* ids,
guint count) /* Since 1.0.25 */
{
if (G_LIKELY(self) && G_LIKELY(ids) && G_LIKELY(count)) {
guint i, disconnected = 0;
for (i = 0; i < count; i++) {
if (ids[i]) {
g_signal_handler_disconnect(self, ids[i]);
disconnected++;
ids[i] = 0;
}
}
if (disconnected) {
GBinderServiceManagerClass* klass =
GBINDER_SERVICEMANAGER_GET_CLASS(self);
GBinderServiceManagerPriv* priv = self->priv;
GHashTableIter it;
gpointer value;
g_hash_table_iter_init(&it, priv->watch_table);
while (disconnected && g_hash_table_iter_next(&it, NULL, &value)) {
GBinderServiceManagerWatch* watch = value;
if (watch->watched && !g_signal_has_handler_pending(self,
gbinder_servicemanager_signals[SIGNAL_REGISTRATION],
watch->quark, TRUE)) {
/* This must be one of those we have just removed */
GDEBUG("Unwatching %s", watch->name);
watch->watched = FALSE;
klass->unwatch(self, watch->name);
disconnected--;
}
}
}
}
}
/*
* These two exist mostly for backward compatibility. Normally,
* gbinder_servicemanager_new() should be used, to allow the type of
* service manager to be configurable per device via /etc/gbinder.conf
*/
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_servicemanager_aidl_get_type(), dev);
}
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_servicemanager_hidl_get_type(), dev);
}
/*==========================================================================*
* Internals
*==========================================================================*/
@@ -442,6 +1036,12 @@ void
gbinder_servicemanager_init(
GBinderServiceManager* self)
{
GBinderServiceManagerPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBINDER_TYPE_SERVICEMANAGER, GBinderServiceManagerPriv);
self->priv = priv;
priv->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, gbinder_servicemanager_watch_free);
}
static
@@ -450,8 +1050,7 @@ gbinder_servicemanager_dispose(
GObject* object)
{
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
GBinderServiceManagerClass* klass =
GBINDER_SERVICEMANAGER_GET_CLASS(self);
GBinderServiceManagerClass* klass = GBINDER_SERVICEMANAGER_GET_CLASS(self);
GVERBOSE_("%s", self->dev);
/* Lock */
@@ -475,7 +1074,7 @@ gbinder_servicemanager_dispose(
* gbinder_servicemanager_finalize() will not be called
* this time around.
*/
if (klass->table && object->ref_count == 0) {
if (klass->table && g_atomic_int_get(&object->ref_count) <= 1) {
g_hash_table_remove(klass->table, self->dev);
if (g_hash_table_size(klass->table) == 0) {
g_hash_table_unref(klass->table);
@@ -493,9 +1092,13 @@ gbinder_servicemanager_finalize(
GObject* object)
{
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
GBinderServiceManagerPriv* priv = self->priv;
gutil_idle_pool_drain(self->pool);
gutil_idle_pool_unref(self->pool);
gbinder_timeout_remove(priv->presence_check);
gbinder_remote_object_remove_handler(self->client->remote, priv->death_id);
gbinder_idle_callback_destroy(priv->autorelease_cb);
g_slist_free_full(priv->autorelease, g_object_unref);
g_hash_table_destroy(priv->watch_table);
gbinder_client_unref(self->client);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
@@ -506,10 +1109,20 @@ gbinder_servicemanager_class_init(
GBinderServiceManagerClass* klass)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
GType type = G_OBJECT_CLASS_TYPE(klass);
g_mutex_init(&klass->mutex);
g_type_class_add_private(klass, sizeof(GBinderServiceManagerPriv));
object_class->dispose = gbinder_servicemanager_dispose;
object_class->finalize = gbinder_servicemanager_finalize;
gbinder_servicemanager_signals[SIGNAL_PRESENCE] =
g_signal_new(SIGNAL_PRESENCE_NAME, type,
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
gbinder_servicemanager_signals[SIGNAL_REGISTRATION] =
g_signal_new(SIGNAL_REGISTRATION_NAME, type,
G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, 0, NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_STRING);
}
/*

View File

@@ -0,0 +1,333 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_servicemanager_aidl.h"
#include "gbinder_servicepoll.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_client_p.h"
#include "gbinder_log.h"
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
typedef struct gbinder_servicemanager_aidl_watch {
GBinderServicePoll* poll;
char* name;
gulong handler_id;
GBinderEventLoopTimeout* notify;
} GBinderServiceManagerAidlWatch;
struct gbinder_servicemanager_aidl_priv {
GBinderServicePoll* poll;
GHashTable* watch_table;
};
G_DEFINE_TYPE(GBinderServiceManagerAidl,
gbinder_servicemanager_aidl,
GBINDER_TYPE_SERVICEMANAGER)
#define PARENT_CLASS gbinder_servicemanager_aidl_parent_class
#define GBINDER_SERVICEMANAGER_AIDL(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
GBinderServiceManagerAidl)
#define SERVICEMANAGER_AIDL_IFACE "android.os.IServiceManager"
static
void
gbinder_servicemanager_aidl_watch_proc(
GBinderServicePoll* poll,
const char* name_added,
void* user_data)
{
GBinderServiceManagerAidlWatch* watch = user_data;
if (!g_strcmp0(name_added, watch->name)) {
GBinderServiceManager* manager =
gbinder_servicepoll_manager(watch->poll);
if (watch->notify) {
gbinder_timeout_remove(watch->notify);
watch->notify = NULL;
}
gbinder_servicemanager_service_registered(manager, name_added);
}
}
static
gboolean
gbinder_servicemanager_aidl_watch_notify(
gpointer user_data)
{
GBinderServiceManagerAidlWatch* watch = user_data;
GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll);
char* name = g_strdup(watch->name);
GASSERT(watch->notify);
watch->notify = NULL;
gbinder_servicemanager_service_registered(manager, name);
g_free(name);
return G_SOURCE_REMOVE;
}
static
void
gbinder_servicemanager_aidl_watch_free(
gpointer user_data)
{
GBinderServiceManagerAidlWatch* watch = user_data;
gbinder_timeout_remove(watch->notify);
gbinder_servicepoll_remove_handler(watch->poll, watch->handler_id);
gbinder_servicepoll_unref(watch->poll);
g_free(watch->name);
g_slice_free(GBinderServiceManagerAidlWatch, watch);
}
static
GBinderServiceManagerAidlWatch*
gbinder_servicemanager_aidl_watch_new(
GBinderServiceManagerAidl* self,
const char* name)
{
GBinderServiceManagerAidlPriv* priv = self->priv;
GBinderServiceManagerAidlWatch* watch =
g_slice_new0(GBinderServiceManagerAidlWatch);
watch->name = g_strdup(name);
watch->poll = gbinder_servicepoll_new(&self->manager, &priv->poll);
watch->handler_id = gbinder_servicepoll_add_handler(priv->poll,
gbinder_servicemanager_aidl_watch_proc, watch);
return watch;
}
static
GBinderLocalRequest*
gbinder_servicemanager_aidl_list_services_req(
GBinderClient* client,
gint32 index)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_int32(req, index);
return req;
}
static
GBinderLocalRequest*
gbinder_servicemanager_aidl_add_service_req(
GBinderClient* client,
const char* name,
GBinderLocalObject* obj)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
return req;
}
static
char**
gbinder_servicemanager_aidl_list(
GBinderServiceManager* manager,
const GBinderIpcSyncApi* api)
{
GPtrArray* list = g_ptr_array_new();
GBinderClient* client = manager->client;
GBinderServiceManagerAidlClass* klass =
GBINDER_SERVICEMANAGER_AIDL_GET_CLASS(manager);
GBinderLocalRequest* req = klass->list_services_req(client, 0);
GBinderRemoteReply* reply;
while ((reply = gbinder_client_transact_sync_reply2(client,
LIST_SERVICES_TRANSACTION, req, NULL, api)) != NULL) {
char* service = gbinder_remote_reply_read_string16(reply);
gbinder_remote_reply_unref(reply);
if (service) {
g_ptr_array_add(list, service);
gbinder_local_request_unref(req);
req = klass->list_services_req(client, list->len);
} else {
break;
}
}
gbinder_local_request_unref(req);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
static
GBinderRemoteObject*
gbinder_servicemanager_aidl_get_service(
GBinderServiceManager* self,
const char* name,
int* status,
const GBinderIpcSyncApi* api)
{
GBinderRemoteObject* obj;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
reply = gbinder_client_transact_sync_reply2(self->client,
CHECK_SERVICE_TRANSACTION, req, status, api);
obj = gbinder_remote_reply_read_object(reply);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return obj;
}
static
int
gbinder_servicemanager_aidl_add_service(
GBinderServiceManager* manager,
const char* name,
GBinderLocalObject* obj,
const GBinderIpcSyncApi* api)
{
int status;
GBinderClient* client = manager->client;
GBinderLocalRequest* req = GBINDER_SERVICEMANAGER_AIDL_GET_CLASS
(manager)->add_service_req(client, name, obj);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply2(client,
ADD_SERVICE_TRANSACTION, req, &status, api);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return status;
}
static
GBINDER_SERVICEMANAGER_NAME_CHECK
gbinder_servicemanager_aidl_check_name(
GBinderServiceManager* self,
const char* name)
{
return GBINDER_SERVICEMANAGER_NAME_OK;
}
static
gboolean
gbinder_servicemanager_aidl_watch(
GBinderServiceManager* manager,
const char* name)
{
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
GBinderServiceManagerAidlPriv* priv = self->priv;
GBinderServiceManagerAidlWatch* watch =
gbinder_servicemanager_aidl_watch_new(self, name);
g_hash_table_replace(priv->watch_table, watch->name, watch);
if (gbinder_servicepoll_is_known_name(watch->poll, name)) {
watch->notify = gbinder_idle_add
(gbinder_servicemanager_aidl_watch_notify, watch);
}
return TRUE;
}
static
void
gbinder_servicemanager_aidl_unwatch(
GBinderServiceManager* manager,
const char* name)
{
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(manager);
GBinderServiceManagerAidlPriv* priv = self->priv;
g_hash_table_remove(priv->watch_table, name);
}
static
void
gbinder_servicemanager_aidl_init(
GBinderServiceManagerAidl* self)
{
GBinderServiceManagerAidlPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBINDER_TYPE_SERVICEMANAGER_AIDL, GBinderServiceManagerAidlPriv);
self->priv = priv;
priv->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, gbinder_servicemanager_aidl_watch_free);
}
static
void
gbinder_servicemanager_aidl_finalize(
GObject* object)
{
GBinderServiceManagerAidl* self = GBINDER_SERVICEMANAGER_AIDL(object);
GBinderServiceManagerAidlPriv* priv = self->priv;
g_hash_table_destroy(priv->watch_table);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
gbinder_servicemanager_aidl_class_init(
GBinderServiceManagerAidlClass* klass)
{
GBinderServiceManagerClass* manager = GBINDER_SERVICEMANAGER_CLASS(klass);
GObjectClass* object = G_OBJECT_CLASS(klass);
g_type_class_add_private(klass, sizeof(GBinderServiceManagerAidlPriv));
klass->list_services_req = gbinder_servicemanager_aidl_list_services_req;
klass->add_service_req = gbinder_servicemanager_aidl_add_service_req;
manager->iface = SERVICEMANAGER_AIDL_IFACE;
manager->default_device = GBINDER_DEFAULT_BINDER;
manager->list = gbinder_servicemanager_aidl_list;
manager->get_service = gbinder_servicemanager_aidl_get_service;
manager->add_service = gbinder_servicemanager_aidl_add_service;
manager->check_name = gbinder_servicemanager_aidl_check_name;
/* normalize_name is not needed */
manager->watch = gbinder_servicemanager_aidl_watch;
manager->unwatch = gbinder_servicemanager_aidl_unwatch;
object->finalize = gbinder_servicemanager_aidl_finalize;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_SERVICEMANAGER_AIDL_H
#define GBINDER_SERVICEMANAGER_AIDL_H
#include "gbinder_servicemanager_p.h"
typedef struct gbinder_servicemanager_aidl_priv GBinderServiceManagerAidlPriv;
typedef struct gbinder_servicemanager_aidl {
GBinderServiceManager manager;
GBinderServiceManagerAidlPriv* priv;
} GBinderServiceManagerAidl;
typedef struct gbinder_servicemanager_aidl_class {
GBinderServiceManagerClass parent;
GBinderLocalRequest* (*list_services_req)
(GBinderClient* client, gint32 index);
GBinderLocalRequest* (*add_service_req)
(GBinderClient* client, const char* name, GBinderLocalObject* obj);
} GBinderServiceManagerAidlClass;
#define GBINDER_TYPE_SERVICEMANAGER_AIDL \
gbinder_servicemanager_aidl_get_type()
#define GBINDER_SERVICEMANAGER_AIDL_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER_AIDL, \
GBinderServiceManagerAidlClass)
#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 */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_servicemanager_aidl.h"
#include <gbinder_client.h>
#include <gbinder_local_request.h>
/* Variant of AIDL servicemanager appeared in Android 9 (API level 28) */
typedef GBinderServiceManagerAidl GBinderServiceManagerAidl2;
typedef GBinderServiceManagerAidlClass GBinderServiceManagerAidl2Class;
G_DEFINE_TYPE(GBinderServiceManagerAidl2,
gbinder_servicemanager_aidl2,
GBINDER_TYPE_SERVICEMANAGER_AIDL)
#define PARENT_CLASS gbinder_servicemanager_aidl2_parent_class
#define DUMP_FLAG_PRIORITY_DEFAULT (0x08)
#define DUMP_FLAG_PRIORITY_ALL (0x0f)
static
GBinderLocalRequest*
gbinder_servicemanager_aidl2_list_services_req(
GBinderClient* client,
gint32 index)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_int32(req, index);
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_ALL);
return req;
}
static
GBinderLocalRequest*
gbinder_servicemanager_aidl2_add_service_req(
GBinderClient* client,
const char* name,
GBinderLocalObject* obj)
{
GBinderLocalRequest* req = gbinder_client_new_request(client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT);
return req;
}
static
void
gbinder_servicemanager_aidl2_init(
GBinderServiceManagerAidl* self)
{
}
static
void
gbinder_servicemanager_aidl2_class_init(
GBinderServiceManagerAidl2Class* cls)
{
cls->list_services_req = gbinder_servicemanager_aidl2_list_services_req;
cls->add_service_req = gbinder_servicemanager_aidl2_add_service_req;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,176 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 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.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
enum gbinder_stability_level {
UNDECLARED = 0,
VENDOR = 0b000011,
SYSTEM = 0b001100,
VINTF = 0b111111
};
static
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 /* stability */);
obj = gbinder_reader_read_object(&reader);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return obj;
}
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);
/*
* Starting from Android 11, to add a service, Android framework requires
* an additional field `stability` when reading a strong binder.
*/
gbinder_local_request_append_int32(req, SYSTEM);
gbinder_local_request_append_int32(req, 0);
gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT);
return req;
}
static
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
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,393 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_servicemanager_p.h"
#include "gbinder_client_p.h"
#include "gbinder_log.h"
#include <gbinder_local_object.h>
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
#include <gbinder_remote_request.h>
#include <gbinder_reader.h>
#include <errno.h>
typedef struct gbinder_servicemanager_hidl_watch {
char* name;
GBinderLocalObject* callback;
} GBinderServiceManagerHidlWatch;
typedef GBinderServiceManagerClass GBinderServiceManagerHidlClass;
typedef struct gbinder_servicemanager_hidl {
GBinderServiceManager manager;
GHashTable* watch_table;
} GBinderServiceManagerHidl;
G_DEFINE_TYPE(GBinderServiceManagerHidl,
gbinder_servicemanager_hidl,
GBINDER_TYPE_SERVICEMANAGER)
#define PARENT_CLASS gbinder_servicemanager_hidl_parent_class
#define GBINDER_TYPE_SERVICEMANAGER_HIDL \
gbinder_servicemanager_hidl_get_type()
#define GBINDER_SERVICEMANAGER_HIDL(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER_HIDL, \
GBinderServiceManagerHidl)
enum gbinder_servicemanager_hidl_calls {
GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
ADD_TRANSACTION,
GET_TRANSPORT_TRANSACTION,
LIST_TRANSACTION,
LIST_BY_INTERFACE_TRANSACTION,
REGISTER_FOR_NOTIFICATIONS_TRANSACTION,
DEBUG_DUMP_TRANSACTION,
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
};
enum gbinder_servicemanager_hidl_notifications {
ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION
};
#define SERVICEMANAGER_HIDL_IFACE "android.hidl.manager@1.0::IServiceManager"
#define SERVICEMANAGER_HIDL_NOTIFICATION_IFACE \
"android.hidl.manager@1.0::IServiceNotification"
static
void
gbinder_servicemanager_hidl_handle_registration(
GBinderServiceManagerHidl* self,
GBinderReader* reader)
{
char* fqname = gbinder_reader_read_hidl_string(reader);
char* name = gbinder_reader_read_hidl_string(reader);
gboolean preexisting;
/* (string fqName, string name, bool preexisting) */
if (fqname && name && gbinder_reader_read_bool(reader, &preexisting) &&
gbinder_reader_at_end(reader)) {
char* full_name = g_strconcat(fqname, "/", name, NULL);
GDEBUG("%s %s", full_name, preexisting ? "true" : "false");
gbinder_servicemanager_service_registered(&self->manager, full_name);
g_free(full_name);
} else {
GWARN("Failed to parse IServiceNotification::onRegistration payload");
}
g_free(fqname);
g_free(name);
}
static
GBinderLocalReply*
gbinder_servicemanager_hidl_notification(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(user_data);
const char* iface = gbinder_remote_request_interface(req);
if (!g_strcmp0(iface, SERVICEMANAGER_HIDL_NOTIFICATION_IFACE)) {
GBinderReader reader;
gbinder_remote_request_init_reader(req, &reader);
switch (code) {
case ON_REGISTRATION_TRANSACTION:
GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u onRegistration",
code);
gbinder_servicemanager_hidl_handle_registration(self, &reader);
*status = GBINDER_STATUS_OK;
break;
default:
GDEBUG(SERVICEMANAGER_HIDL_NOTIFICATION_IFACE " %u", code);
*status = GBINDER_STATUS_FAILED;
break;
}
} else {
GDEBUG("%s %u", iface, code);
*status = GBINDER_STATUS_FAILED;
}
return NULL;
}
static
char**
gbinder_servicemanager_hidl_list(
GBinderServiceManager* self,
const GBinderIpcSyncApi* api)
{
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply2
(self->client, LIST_TRANSACTION, req, NULL, api);
gbinder_local_request_unref(req);
if (reply) {
GBinderReader reader;
char** result = NULL;
int status = -1;
gbinder_remote_reply_init_reader(reply, &reader);
/* Read status */
GVERIFY(gbinder_reader_read_int32(&reader, &status));
GASSERT(status == GBINDER_STATUS_OK);
/* Followed by hidl_vec<string> */
result = gbinder_reader_read_hidl_string_vec(&reader);
gbinder_remote_reply_unref(reply);
return result;
}
return NULL;
}
static
GBinderRemoteObject*
gbinder_servicemanager_hidl_get_service(
GBinderServiceManager* self,
const char* fqinstance,
int* status,
const GBinderIpcSyncApi* api)
{
/* e.g. "android.hardware.radio@1.1::IRadio/slot1" */
const char* sep = strchr(fqinstance, '/');
GBinderRemoteObject* obj = NULL;
if (sep) {
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
char* fqname = g_strndup(fqinstance, sep - fqinstance);
const char* name = sep + 1;
gbinder_local_request_append_hidl_string(req, fqname);
gbinder_local_request_append_hidl_string(req, name);
reply = gbinder_client_transact_sync_reply2(self->client,
GET_TRANSACTION, req, status, api);
if (reply) {
GBinderReader reader;
int status = -1;
gbinder_remote_reply_init_reader(reply, &reader);
/* Read status */
GVERIFY(gbinder_reader_read_int32(&reader, &status));
GASSERT(status == GBINDER_STATUS_OK);
/* Read the object */
obj = gbinder_reader_read_object(&reader);
gbinder_remote_reply_unref(reply);
}
gbinder_local_request_unref(req);
g_free(fqname);
} else {
GERR("Invalid instance \"%s\"", fqinstance);
if (status) *status = (-EINVAL);
}
return obj;
}
static
int
gbinder_servicemanager_hidl_add_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj,
const GBinderIpcSyncApi* api)
{
int status;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
/* add(string name, interface service) generates (bool success); */
gbinder_local_request_append_hidl_string(req, name);
gbinder_local_request_append_local_object(req, obj);
reply = gbinder_client_transact_sync_reply2(self->client,
ADD_TRANSACTION, req, &status, api);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return status;
}
static
void
gbinder_servicemanager_hidl_watch_free(
gpointer data)
{
GBinderServiceManagerHidlWatch* watch = data;
g_free(watch->name);
gbinder_local_object_drop(watch->callback);
g_free(watch);
}
static
GBINDER_SERVICEMANAGER_NAME_CHECK
gbinder_servicemanager_hidl_check_name(
GBinderServiceManager* self,
const char* name)
{
if (name) {
const gsize len = strlen(name);
static const char allowed_chars[] = "./0123456789:@"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
if (len && strspn(name, allowed_chars) == len) {
return strchr(name, '/') ?
GBINDER_SERVICEMANAGER_NAME_NORMALIZE :
GBINDER_SERVICEMANAGER_NAME_OK;
}
}
return GBINDER_SERVICEMANAGER_NAME_INVALID;
}
static
char*
gbinder_servicemanager_hidl_normalize_name(
GBinderServiceManager* self,
const char* name)
{
/* Slash must be there, see gbinder_servicemanager_hidl_check_name() */
return g_strndup(name, strchr(name, '/') - name);
}
static
gboolean
gbinder_servicemanager_hidl_watch(
GBinderServiceManager* manager,
const char* name)
{
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(manager);
GBinderLocalRequest* req = gbinder_client_new_request(manager->client);
GBinderRemoteReply* reply;
GBinderServiceManagerHidlWatch* watch =
g_new0(GBinderServiceManagerHidlWatch, 1);
gboolean success = FALSE;
int status;
watch->name = g_strdup(name);
watch->callback = gbinder_servicemanager_new_local_object(manager,
SERVICEMANAGER_HIDL_NOTIFICATION_IFACE,
gbinder_servicemanager_hidl_notification, self);
g_hash_table_replace(self->watch_table, watch->name, watch);
/* registerForNotifications(string fqName, string name,
* IServiceNotification callback) generates (bool success); */
gbinder_local_request_append_hidl_string(req, name);
gbinder_local_request_append_hidl_string(req, "");
gbinder_local_request_append_local_object(req, watch->callback);
reply = gbinder_client_transact_sync_reply(manager->client,
REGISTER_FOR_NOTIFICATIONS_TRANSACTION, req, &status);
if (status == GBINDER_STATUS_OK && reply) {
GBinderReader reader;
gbinder_remote_reply_init_reader(reply, &reader);
if (gbinder_reader_read_int32(&reader, &status) &&
status == GBINDER_STATUS_OK) {
gbinder_reader_read_bool(&reader, &success);
}
}
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
if (!success) {
/* unwatch() won't be called if we return FALSE */
g_hash_table_remove(self->watch_table, watch->name);
}
return success;
}
static
void
gbinder_servicemanager_hidl_unwatch(
GBinderServiceManager* manager,
const char* name)
{
g_hash_table_remove(GBINDER_SERVICEMANAGER_HIDL(manager)->
watch_table, name);
}
static
void
gbinder_servicemanager_hidl_init(
GBinderServiceManagerHidl* self)
{
self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, gbinder_servicemanager_hidl_watch_free);
}
static
void
gbinder_servicemanager_hidl_finalize(
GObject* object)
{
GBinderServiceManagerHidl* self = GBINDER_SERVICEMANAGER_HIDL(object);
g_hash_table_destroy(self->watch_table);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
gbinder_servicemanager_hidl_class_init(
GBinderServiceManagerHidlClass* klass)
{
klass->iface = SERVICEMANAGER_HIDL_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->list = gbinder_servicemanager_hidl_list;
klass->get_service = gbinder_servicemanager_hidl_get_service;
klass->add_service = gbinder_servicemanager_hidl_add_service;
klass->check_name = gbinder_servicemanager_hidl_check_name;
klass->normalize_name = gbinder_servicemanager_hidl_normalize_name;
klass->watch = gbinder_servicemanager_hidl_watch;
klass->unwatch = gbinder_servicemanager_hidl_unwatch;
G_OBJECT_CLASS(klass)->finalize = gbinder_servicemanager_hidl_finalize;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

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
@@ -39,38 +39,79 @@
#include <glib-object.h>
typedef struct gbinder_servicemanager_priv GBinderServiceManagerPriv;
typedef struct gbinder_servicemanager {
GObject parent;
GBinderServiceManagerPriv* priv;
const char* dev;
GBinderClient* client;
GUtilIdlePool* pool;
} GBinderServiceManager;
typedef enum gbinder_servicemanager_name_check {
GBINDER_SERVICEMANAGER_NAME_OK,
GBINDER_SERVICEMANAGER_NAME_NORMALIZE,
GBINDER_SERVICEMANAGER_NAME_INVALID,
} GBINDER_SERVICEMANAGER_NAME_CHECK;
typedef struct gbinder_servicemanager_class {
GObjectClass parent;
GMutex mutex;
GHashTable* table;
guint32 handle;
const char* iface;
const char* default_device;
/* Methods (synchronous) */
char** (*list)(GBinderServiceManager* self);
GBinderRemoteObject* (*get_service)
(GBinderServiceManager* self, const char* name, int* status);
int (*add_service)
(GBinderServiceManager* self, const char* name,
GBinderLocalObject* obj);
char** (*list)(GBinderServiceManager* self, const GBinderIpcSyncApi* api);
GBinderRemoteObject* (*get_service)(GBinderServiceManager* self,
const char* name, int* status, const GBinderIpcSyncApi* api);
int (*add_service)(GBinderServiceManager* self, const char* name,
GBinderLocalObject* obj, const GBinderIpcSyncApi* api);
/* Checking/normalizing watch names */
GBINDER_SERVICEMANAGER_NAME_CHECK (*check_name)
(GBinderServiceManager* self, const char* name);
char* (*normalize_name)(GBinderServiceManager* self, const char* name);
/* If watch() returns FALSE, unwatch() is not called */
gboolean (*watch)(GBinderServiceManager* self, const char* name);
void (*unwatch)(GBinderServiceManager* self, const char* name);
} GBinderServiceManagerClass;
GType gbinder_servicemanager_get_type(void);
GType gbinder_servicemanager_get_type(void) GBINDER_INTERNAL;
#define GBINDER_TYPE_SERVICEMANAGER (gbinder_servicemanager_get_type())
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
#define gbinder_servicemanager_ipc(sm) gbinder_client_ipc(sm->client)
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
GType type,
const char* dev);
const char* dev)
GBINDER_INTERNAL;
void
gbinder_servicemanager_service_registered(
GBinderServiceManager* self,
const char* name)
GBINDER_INTERNAL;
/* Declared for unit tests */
void
gbinder_servicemanager_exit(
void)
GBINDER_INTERNAL
GBINDER_DESTRUCTOR;
/* Derived types */
GType gbinder_servicemanager_aidl_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_aidl2_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_aidl3_get_type(void) GBINDER_INTERNAL;
GType gbinder_servicemanager_hidl_get_type(void) GBINDER_INTERNAL;
#endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */

205
src/gbinder_servicename.c Normal file
View File

@@ -0,0 +1,205 @@
/*
* Copyright (C) 2019-2021 Jolla Ltd.
* Copyright (C) 2019-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_types_p.h"
#include "gbinder_eventloop_p.h"
#include "gbinder_servicename.h"
#include "gbinder_servicemanager.h"
#include "gbinder_local_object.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
/* Since 1.0.26 */
#define GBINDER_SERVICENAME_RETRY_INTERVAL_MS (500)
typedef struct gbinder_servicename_priv {
GBinderServiceName pub;
gint refcount;
char* name;
GBinderLocalObject* object;
GBinderServiceManager* sm;
GBinderEventLoopTimeout* retry_timer;
gulong presence_id;
gulong add_call_id;
} GBinderServiceNamePriv;
static
void
gbinder_servicename_add_service(
GBinderServiceNamePriv* priv);
GBINDER_INLINE_FUNC GBinderServiceNamePriv*
gbinder_servicename_cast(GBinderServiceName* pub)
{ return G_CAST(pub, GBinderServiceNamePriv, pub); }
/*==========================================================================*
* Implementation
*==========================================================================*/
static
gboolean
gbinder_servicename_add_service_retry(
gpointer user_data)
{
GBinderServiceNamePriv* priv = user_data;
priv->retry_timer = NULL;
gbinder_servicename_add_service(priv);
return G_SOURCE_REMOVE;
}
static
void
gbinder_servicename_add_service_done(
GBinderServiceManager* sm,
int status,
void* user_data)
{
GBinderServiceNamePriv* priv = user_data;
GASSERT(priv->add_call_id);
priv->add_call_id = 0;
if (status) {
GWARN("Error %d adding name \"%s\"", status, priv->name);
gbinder_timeout_remove(priv->retry_timer);
priv->retry_timer =
gbinder_timeout_add(GBINDER_SERVICENAME_RETRY_INTERVAL_MS,
gbinder_servicename_add_service_retry, priv);
} else {
GDEBUG("Service \"%s\" has been registered", priv->name);
}
}
static
void
gbinder_servicename_add_service(
GBinderServiceNamePriv* priv)
{
GDEBUG("Adding service \"%s\"", priv->name);
gbinder_servicemanager_cancel(priv->sm, priv->add_call_id);
priv->add_call_id = gbinder_servicemanager_add_service(priv->sm,
priv->name, priv->object, gbinder_servicename_add_service_done, priv);
}
static
void
gbinder_servicename_presence_handler(
GBinderServiceManager* sm,
void* user_data)
{
GBinderServiceNamePriv* priv = user_data;
if (gbinder_servicemanager_is_present(sm)) {
gbinder_servicename_add_service(priv);
} else {
if (priv->add_call_id) {
gbinder_servicemanager_cancel(priv->sm, priv->add_call_id);
priv->add_call_id = 0;
}
if (priv->retry_timer) {
gbinder_timeout_remove(priv->retry_timer);
priv->retry_timer = NULL;
}
}
}
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderServiceName*
gbinder_servicename_new(
GBinderServiceManager* sm,
GBinderLocalObject* object,
const char* name)
{
if (G_LIKELY(sm) && G_LIKELY(object) && G_LIKELY(name)) {
GBinderServiceNamePriv* priv = g_slice_new0(GBinderServiceNamePriv);
GBinderServiceName* self = &priv->pub;
g_atomic_int_set(&priv->refcount, 1);
priv->object = gbinder_local_object_ref(object);
priv->sm = gbinder_servicemanager_ref(sm);
self->name = priv->name = g_strdup(name);
priv->presence_id = gbinder_servicemanager_add_presence_handler(sm,
gbinder_servicename_presence_handler, priv);
if (gbinder_servicemanager_is_present(sm)) {
gbinder_servicename_add_service(priv);
}
return self;
} else {
return NULL;
}
}
GBinderServiceName*
gbinder_servicename_ref(
GBinderServiceName* self)
{
if (G_LIKELY(self)) {
GBinderServiceNamePriv* priv = gbinder_servicename_cast(self);
GASSERT(priv->refcount > 0);
g_atomic_int_inc(&priv->refcount);
}
return self;
}
void
gbinder_servicename_unref(
GBinderServiceName* self)
{
if (G_LIKELY(self)) {
GBinderServiceNamePriv* priv = gbinder_servicename_cast(self);
GASSERT(priv->refcount > 0);
if (g_atomic_int_dec_and_test(&priv->refcount)) {
gbinder_servicemanager_cancel(priv->sm, priv->add_call_id);
gbinder_servicemanager_remove_handler(priv->sm, priv->presence_id);
gbinder_servicemanager_unref(priv->sm);
gbinder_local_object_unref(priv->object);
gbinder_timeout_remove(priv->retry_timer);
g_free(priv->name);
gutil_slice_free(priv);
}
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

269
src/gbinder_servicepoll.c Normal file
View File

@@ -0,0 +1,269 @@
/*
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gbinder_servicepoll.h"
#include "gbinder_servicemanager.h"
#include "gbinder_eventloop_p.h"
#include <gutil_strv.h>
#include <glib-object.h>
/* This is configurable mostly so that unit testing doesn't take too long */
guint gbinder_servicepoll_interval_ms = 2000;
typedef GObjectClass GBinderServicePollClass;
struct gbinder_servicepoll {
GObject object;
GBinderServiceManager* manager;
char** list;
gulong list_id;
GBinderEventLoopTimeout* timer;
};
G_DEFINE_TYPE(GBinderServicePoll, gbinder_servicepoll, G_TYPE_OBJECT)
#define GBINDER_TYPE_SERVICEPOLL (gbinder_servicepoll_get_type())
#define GBINDER_SERVICEPOLL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_SERVICEPOLL, GBinderServicePoll))
enum gbinder_servicepoll_signal {
SIGNAL_NAME_ADDED,
SIGNAL_COUNT
};
static const char SIGNAL_NAME_ADDED_NAME[] = "servicepoll-name-added";
static guint gbinder_servicepoll_signals[SIGNAL_COUNT] = { 0 };
/*==========================================================================*
* Implementation
*==========================================================================*/
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
* list, otherwise the caller will deallocate it. */
gboolean
gbinder_servicepoll_list(
GBinderServiceManager* sm,
char** services,
void* user_data)
{
GBinderServicePoll* self = GBINDER_SERVICEPOLL(user_data);
gbinder_servicepoll_ref(self);
self->list_id = 0;
if (services) {
const GStrV* ptr_new;
ptr_new = services = gutil_strv_sort(services, TRUE);
if (self->list) {
const GStrV* ptr_old = self->list;
while (*ptr_new && *ptr_old) {
const int i = gutil_strv_find(ptr_old, *ptr_new);
if (i < 0) {
/* New name */
g_signal_emit(self, gbinder_servicepoll_signals
[SIGNAL_NAME_ADDED], 0, *ptr_new);
} else {
int k;
/* If some names have disappeared, then i may be > 0 */
for (k = 0; k < i; k ++) ptr_old++;
ptr_old++;
}
ptr_new++;
}
}
while (*ptr_new) {
g_signal_emit(self, gbinder_servicepoll_signals
[SIGNAL_NAME_ADDED], 0, *ptr_new);
ptr_new++;
}
}
g_strfreev(self->list);
self->list = services;
gbinder_servicepoll_unref(self);
return TRUE;
}
static
gboolean
gbinder_servicepoll_timer(
gpointer user_data)
{
GBinderServicePoll* self = GBINDER_SERVICEPOLL(user_data);
if (!self->list_id) {
self->list_id = gbinder_servicemanager_list(self->manager,
gbinder_servicepoll_list, self);
}
return G_SOURCE_CONTINUE;
}
static
GBinderServicePoll*
gbinder_servicepoll_create(
GBinderServiceManager* manager)
{
GBinderServicePoll* self = g_object_new(GBINDER_TYPE_SERVICEPOLL, NULL);
self->manager = gbinder_servicemanager_ref(manager);
self->list_id = gbinder_servicemanager_list(manager,
gbinder_servicepoll_list, self);
return self;
}
/*==========================================================================*
* API
*==========================================================================*/
GBinderServicePoll*
gbinder_servicepoll_new(
GBinderServiceManager* manager,
GBinderServicePoll** weakptr)
{
if (weakptr) {
if (*weakptr) {
gbinder_servicepoll_ref(*weakptr);
} else {
*weakptr = gbinder_servicepoll_create(manager);
g_object_add_weak_pointer(G_OBJECT(*weakptr), (gpointer*)weakptr);
}
return *weakptr;
} else {
return gbinder_servicepoll_create(manager);
}
}
GBinderServicePoll*
gbinder_servicepoll_ref(
GBinderServicePoll* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_SERVICEPOLL(self));
return self;
} else {
return NULL;
}
}
void
gbinder_servicepoll_unref(
GBinderServicePoll* self)
{
if (G_LIKELY(self)) {
g_object_unref(GBINDER_SERVICEPOLL(self));
}
}
GBinderServiceManager*
gbinder_servicepoll_manager(
GBinderServicePoll* self)
{
return G_LIKELY(self) ? self->manager : NULL;
}
gboolean
gbinder_servicepoll_is_known_name(
GBinderServicePoll* self,
const char* name)
{
return G_LIKELY(self) && gutil_strv_contains(self->list, name);
}
gulong
gbinder_servicepoll_add_handler(
GBinderServicePoll* self,
GBinderServicePollFunc fn,
void* user_data)
{
return (G_LIKELY(self) && G_LIKELY(fn)) ? g_signal_connect(self,
SIGNAL_NAME_ADDED_NAME, G_CALLBACK(fn), user_data) : 0;
}
void
gbinder_servicepoll_remove_handler(
GBinderServicePoll* self,
gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
/*==========================================================================*
* Internals
*==========================================================================*/
static
void
gbinder_servicepoll_init(
GBinderServicePoll* self)
{
self->timer = gbinder_timeout_add(gbinder_servicepoll_interval_ms,
gbinder_servicepoll_timer, self);
}
static
void
gbinder_servicepoll_finalize(
GObject* object)
{
GBinderServicePoll* self = GBINDER_SERVICEPOLL(object);
gbinder_timeout_remove(self->timer);
gbinder_servicemanager_cancel(self->manager, self->list_id);
gbinder_servicemanager_unref(self->manager);
g_strfreev(self->list);
}
static
void
gbinder_servicepoll_class_init(
GBinderServicePollClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = gbinder_servicepoll_finalize;
gbinder_servicepoll_signals[SIGNAL_NAME_ADDED] =
g_signal_new(SIGNAL_NAME_ADDED_NAME, G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
1, G_TYPE_STRING);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

95
src/gbinder_servicepoll.h Normal file
View File

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

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 Jolla Ltd.
* Contact: Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -38,29 +38,34 @@
int
gbinder_system_open(
const char* path,
int flags);
int flags)
GBINDER_INTERNAL;
int
gbinder_system_close(
int fd);
int fd)
GBINDER_INTERNAL;
int
gbinder_system_ioctl(
int fd,
int request,
void* data);
void* data)
GBINDER_INTERNAL;
void*
gbinder_system_mmap(
size_t length,
int prot,
int flags,
int fd);
int fd)
GBINDER_INTERNAL;
int
gbinder_system_munmap(
void* addr,
size_t length);
size_t length)
GBINDER_INTERNAL;
#endif /* GBINDER_SYSTEM_H */

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
@@ -35,38 +35,24 @@
#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_ipc GBinderIpc;
typedef struct gbinder_object_converter GBinderObjectConverter;
typedef struct gbinder_object_registry GBinderObjectRegistry;
typedef struct gbinder_output_data GBinderOutputData;
typedef struct gbinder_proxy_object GBinderProxyObject;
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;
typedef struct hidl_vec {
union {
guint64 value;
const void* ptr;
} data;
guint32 count;
guint32 owns_buffer;
} HidlVec;
#define HIDL_VEC_BUFFER_OFFSET (0)
typedef struct hidl_string {
union {
guint64 value;
const char* str;
} data;
guint32 len;
guint32 owns_buffer;
} HidlString;
#define HIDL_STRING_BUFFER_OFFSET (0)
typedef struct gbinder_servicepoll GBinderServicePoll;
typedef struct gbinder_ipc_looper_tx GBinderIpcLooperTx;
typedef struct gbinder_ipc_sync_api GBinderIpcSyncApi;
#define GBINDER_INLINE_FUNC static inline
#define GBINDER_INTERNAL G_GNUC_INTERNAL
#define GBINDER_DESTRUCTOR __attribute__((destructor))
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
#define GBINDER_PING_TRANSACTION GBINDER_TRANSACTION('P','N','G')
@@ -88,6 +74,9 @@ typedef struct hidl_string {
#define HIDL_DEBUG_TRANSACTION HIDL_FOURCC('D','B','G')
#define HIDL_HASH_CHAIN_TRANSACTION HIDL_FOURCC('H','S','H')
/* As a special case, ServiceManager's handle is zero */
#define GBINDER_SERVICEMANAGER_HANDLE (0)
#endif /* GBINDER_TYPES_PRIVATE_H */
/*

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-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
@@ -48,82 +48,133 @@ typedef struct gbinder_writer_data {
void
gbinder_writer_init(
GBinderWriter* writer,
GBinderWriterData* data);
GBinderWriterData* data)
GBINDER_INTERNAL;
void
gbinder_writer_data_set_contents(
GBinderWriterData* data,
GBinderBuffer* buffer,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_contents(
GBinderWriterData* data,
GBinderBuffer* buffer,
gsize data_offset,
GBinderObjectConverter* convert)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_bool(
GBinderWriterData* data,
gboolean value);
gboolean value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_int32(
GBinderWriterData* data,
guint32 value);
guint32 value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_int64(
GBinderWriterData* data,
guint64 value);
guint64 value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_float(
GBinderWriterData* data,
gfloat value);
gfloat value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_double(
GBinderWriterData* data,
gdouble value);
gdouble value)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_string8(
GBinderWriterData* data,
const char* str);
const char* str)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_string8_len(
GBinderWriterData* data,
const char* str,
gsize len);
gsize len)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_string16(
GBinderWriterData* data,
const char* utf8);
const char* utf8)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_string16_len(
GBinderWriterData* data,
const char* utf8,
gssize num_bytes);
gssize num_bytes)
GBINDER_INTERNAL;
guint
gbinder_writer_data_append_buffer_object(
GBinderWriterData* data,
const void* ptr,
gsize size,
const GBinderParent* parent);
const GBinderParent* parent)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_parcelable(
GBinderWriterData* data,
const void* ptr,
gsize size)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_hidl_vec(
GBinderWriterData* data,
const void* base,
guint count,
guint elemsize)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_hidl_string(
GBinderWriterData* data,
const char* str);
const char* str)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_hidl_string_vec(
GBinderWriterData* data,
const char* strv[],
gssize count);
gssize count)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_local_object(
GBinderWriterData* data,
GBinderLocalObject* obj);
GBinderLocalObject* obj)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_remote_object(
GBinderWriterData* data,
GBinderRemoteObject* obj);
GBinderRemoteObject* obj)
GBINDER_INTERNAL;
void
gbinder_writer_data_append_fd(
GBinderWriterData* data,
int fd)
GBINDER_INTERNAL;
#endif /* GBINDER_WRITER_PRIVATE_H */

View File

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

140
test/ashmem-test/Makefile Normal file
View File

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

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

154
test/binder-bridge/Makefile Normal file
View File

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

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

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

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

View File

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

View File

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

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);
}

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