Compare commits

..

104 Commits

Author SHA1 Message Date
Slava Monich
c6d8e8d1e6 Version 1.4.11 2022-08-31 19:12:54 +03:00
Slava Monich
ee7fdd06d4 Merge pull request #20 from monich/user_data
Add radio_request_user_data()
2022-08-31 19:08:22 +03:00
Slava Monich
8fa78cc777 [gbinder-radio] Added radio_request_user_data(). JB#58006 2022-08-31 14:29:45 +03:00
Slava Monich
f4276f8602 Version 1.4.10 2022-04-15 22:01:08 +03:00
Slava Monich
ff1195ffc6 Merge pull request #19 from monich/complete
Tweak completion callback criteria
2022-04-15 21:55:43 +03:00
Slava Monich
11673897fa [gbinder-radio] Tweaked completion callback criteria. JB#58006
Don't invoke completion callback for the requests that were
never submitted.
2022-04-15 21:22:06 +03:00
Slava Monich
520fe4257a Version 1.4.9 2022-02-17 01:49:55 +02:00
Slava Monich
179e8d6160 Merge pull request #18 from monich/ims
Add IMS types
2022-02-17 01:32:49 +02:00
Slava Monich
6d52c79f6c [gbinder-radio] Added IMS types. JB#57425 2022-02-17 00:53:56 +02:00
Slava Monich
48026e4fe6 Version 1.4.8 2022-01-19 03:34:14 +02:00
Slava Monich
451711a1ce Merge pull request #17 from monich/block-retry
Fix retries of blocking requests
2022-01-19 03:29:44 +02:00
Slava Monich
32523f2b1a [unit] Added test for retry of a blocking request. JB#57102 2022-01-19 03:24:54 +02:00
Slava Monich
e0e475c4e3 [gbinder-radio] Fixed retries of blocking requests. JB#57102
A blocking request shouldn't block itself.
2022-01-19 01:25:00 +02:00
Slava Monich
02789fa6a4 [gbinder-radio] More logging in radio_request_default_retry()
To make it clear why request was (or wasn't) retried
2022-01-19 01:22:12 +02:00
Slava Monich
6a4f434592 Version 1.4.7 2022-01-10 01:04:17 +02:00
Slava Monich
a96fdf6c42 [gbinder-radio] Fixed owner queue logic. JB#56824 2022-01-10 01:02:01 +02:00
Slava Monich
77a9b126ef [gbinder-radio] Added internal DEBUG_ASSERT macro
It's an assert fatal in debug build and non-fatal in release.
Marks truely unavoidable conditions.
2022-01-09 19:30:39 +02:00
Slava Monich
5085ccc3c6 [gbinder-radio] Houskeeping
radio_base_ref/unref are unnecessary. It's an internal API, it
doesn't add much to compile time type safety, and the object
pointer is always checked for NULL by the caller anyway,
there's no need to check it twice.
2022-01-09 19:28:02 +02:00
Slava Monich
4eb1ced700 Version 1.4.6 2022-01-08 21:23:41 +02:00
Slava Monich
68ff7696d7 [license] Freshened up copyright 2022-01-08 21:23:30 +02:00
Slava Monich
b6021807dd [gbinder-radio] Fixed compilation issues
Older build environments don't know uint and ulong:

src/radio_base.c: In function 'radio_base_submit_request':
src/radio_base.c:527:9: error: unknown type name 'uint'
         const uint timeout = radio_base_timeout_ms(self, req);
         ^

src/radio_request.c: In function 'radio_request_set_timeout':
src/radio_request.c:276:13: error: unknown type name 'uint'
             const uint timeout = radio_base_timeout_ms(base, req);
             ^

unit_instance.c: In function 'test_connected':
unit_instance.c:425:5: error: unknown type name 'ulong'
     ulong id[4];
     ^
2022-01-08 21:20:39 +02:00
Slava Monich
ea6071fb11 Merge pull request #16 from monich/radio-config
Added RadioConfig API
2022-01-08 20:52:34 +02:00
Slava Monich
b50d08ddd9 [gbinder-radio] Added RadioConfig API. JB#56824
Simplifies talking to IRadioConfig binder service.
2022-01-08 20:46:00 +02:00
Slava Monich
2f4b216758 [gbinder-radio] Fixed compilation warning
Some older systems produce this:

test_gbinder_client.c:236:13: warning: implicit declaration of
function 'qsort' [-Wimplicit-function-declaration]

    qsort(self->ranges, count, sizeof(TestGBinderClientIfaceRange),
    ^
2022-01-03 04:14:23 +02:00
Slava Monich
0af836aa7a [gbinder-radio] Moved reusable code to RadioBase class. JB#56824 2021-12-29 21:26:06 +02:00
Slava Monich
d2227efa9e Version 1.4.5 2021-12-16 01:25:42 +02:00
Slava Monich
092bc3aa5f Merge pull request #15 from monich/radio_req_resp2
Add radio_req_resp2()
2021-12-16 01:23:12 +02:00
Slava Monich
f52b5e98d6 [gbinder-radio] Added radio_req_resp2(). JB#56484
Reliable request-to-response mapping requires interface version
as a parameter.
2021-12-16 01:12:38 +02:00
Slava Monich
d81a883289 Version 1.4.4 2021-12-14 18:04:45 +02:00
Slava Monich
a1de914f94 [gbinder-radio] Added IRadio@1.2 IndicationFilter bits. JB#55524 2021-12-14 17:59:56 +02:00
Slava Monich
b1e7cb78d2 Version 1.4.3 2021-12-02 19:12:21 +02:00
Slava Monich
309383a3dd Merge pull request #14 from monich/client
Add RadioClient and related APIs
2021-12-02 18:53:34 +02:00
Slava Monich
24a5e281d7 [gbinder-radio] Add RadioClient and related APIs. JB#55524
Replacement of some gint32 fields with enums may cause "warning:
passing argument xxx from incompatible pointer type" or something
similar at compile time but it's safe from the ABI prospective
because those enums have the same size as gint32 (and that's
checked at compiled time). It may, however, cause compilation
errors in the projects compiled with -Werror
2021-12-02 17:33:00 +02:00
Slava Monich
6a9a0b7d5e [rpm] Install license file. JB#55991 2021-11-24 20:31:17 +02:00
Slava Monich
4b95a7efef [unit] Small fix 2021-09-12 19:16:48 +03:00
Slava Monich
1d14925196 Version 1.4.2 2021-09-12 18:08:18 +03:00
Slava Monich
77d600150a Merge pull request #13 from monich/unit
Unit tests + some housekeeping
2021-09-12 17:42:26 +03:00
Slava Monich
7684a717de [gbinder-radio] Added unit tests. JB#55524 2021-09-12 17:28:22 +03:00
Slava Monich
6be4596f0d [gbinder-radio] Housekeeping 2021-09-11 16:03:17 +03:00
Slava Monich
76f7fa6ee1 [gbinder-radio] Don't assume that GBinderServiceManager is a GObject
It's an implementation detail and not a part of libgbinder interface.
2021-09-11 16:01:44 +03:00
Slava Monich
c3135de5c7 Version 1.4.1 2021-05-20 16:34:13 +03:00
Slava Monich
4595539656 Merge pull request #12 from d-grigorev/jb54258
Define RADIO_CELL_INFO_TYPE_1_4
2021-05-20 16:29:53 +03:00
Denis Grigorev
62a0764577 [gbinder-radio] Define RADIO_CELL_INFO_TYPE_1_4. JB#54258
Cell info type is encoded by hidl_discriminator, and is actually part of
struct CellInfo.Info. For simplicity it is defined here as part of struct
CellInfo, so the code for android@1.2 can be reused for android@1.4.
The values are taken from the generated types.h:

    struct CellInfo final {
      struct Info final {
        enum class hidl_discriminator : uint8_t {
          gsm = 0,  // ::android::hardware:📻:V1_2::CellInfoGsm
          cdma = 1,  // ::android::hardware:📻:V1_2::CellInfoCdma
          wcdma = 2,  // ::android::hardware:📻:V1_2::CellInfoWcdma
          tdscdma = 3,  // ::android::hardware:📻:V1_2::CellInfoTdscdma
          lte = 4,  // ::android::hardware:📻:V1_4::CellInfoLte
          nr = 5,  // ::android::hardware:📻:V1_4::CellInfoNr
        };
2021-05-20 11:03:44 +03:00
Slava Monich
ff65e170e1 Version 1.4.0 2021-05-18 18:59:08 +03:00
Slava Monich
0ce5f268c9 Acknowledge contributions 2021-05-18 18:52:06 +03:00
Slava Monich
ab379e4fe3 Merge pull request #11 from d-grigorev/jb54258
Add support for android.hardware.radio@1.4
2021-05-18 18:47:24 +03:00
Denis Grigorev
e4ab7078a1 [gbinder-radio] Fix RadioCellInfo_1_4 structure. JB#54258 2021-05-18 18:02:41 +03:00
Denis Grigorev
9b1c2df489 [gbinder-radio] Support radio@1.4 interface. JB#54258 2021-05-18 18:02:32 +03:00
Slava Monich
62212c5165 Version 1.2.6 2021-04-25 14:42:33 +03:00
Slava Monich
ea502d417a [gbinder-radio] Added RadioSimApdu type. JB#54048
It exists since radio@1.0 but for whatever reason it's been missing.
2021-04-25 14:39:41 +03:00
Slava Monich
1ce4ff615b [gbinder-radio] Avoid hardcoding list of ifaces twice 2021-04-22 14:41:39 +03:00
Slava Monich
72b3fc58ec Version 1.2.5 2021-03-25 20:16:27 +02:00
Slava Monich
4140def1fc Merge pull request #10 from monich/radio1.4
Add radio@1.4 types
2021-03-25 20:15:29 +02:00
Slava Monich
901396b385 [gbinder-radio] Added radio@1.4 types. JB#48905 2021-03-25 20:07:19 +02:00
Slava Monich
052a0e11fb [gbinder-radio] Added radio@1.3 types. JB#48905 2021-03-25 20:07:00 +02:00
Slava Monich
024f319164 Version 1.2.4 2021-03-20 02:43:01 +02:00
Slava Monich
91f7b80459 [gbinder-radio] Added more radio@1.2 types. JB#53501
RadioCellIdentity_1_2
RadioVoiceRegStateResult_1_2
RadioDataRegStateResult_1_2

Also added RADIO_1_x_RESP_LAST and RADIO_1_x_IND_LAST constants in addition
to already existing RADIO_1_x_REQ_LAST
2021-03-20 02:41:25 +02:00
Slava Monich
13076eb3ec Version 1.2.3 2021-03-19 05:22:35 +02:00
Slava Monich
27695ee5ff [gbinder-radio] Reformatted radio@1.2 types. JB#53501
To resemble types.hal definitions. This change is binary but not
compile-time compatible.
2021-03-19 05:18:29 +02:00
Slava Monich
7b5656d2a8 Version 1.2.2 2021-03-05 14:01:30 +02:00
Slava Monich
788d472839 [gbinder-radio] Added radio_instance_get_with_version(). JB#50597
That's consistent with other API calls.

radio_instance_get_with_interface() has been removed from the header
and shouldn't be used.
2021-03-05 13:58:59 +02:00
Slava Monich
7f4446b3fd Version 1.2.1 2021-03-05 12:35:10 +02:00
Slava Monich
e08ef1bdae Merge pull request #9 from monich/backcompat
Backward compatibility with radio@1.0
2021-03-05 12:30:13 +02:00
Slava Monich
8039bfe66e [gbinder-radio] Backward compatibility with radio@1.0. JB#50597
Once you say you support radio@1.2 responses, getIccCardStatus@1.0
responds with getIccCardStatusResponse@1.2. That breaks clients
which only handle radio@1.0 responses.

Intention to support higher interface levels must be explicitly
expressed.
2021-03-05 12:23:10 +02:00
Slava Monich
7e23a74fbf Version 1.2.0
Version bump marks radio@1.2 support
2021-03-04 13:39:04 +02:00
Slava Monich
a9463baaaf Freshened up license 2021-03-04 13:38:42 +02:00
Slava Monich
ddee97fc93 Acknowledge Matti's contribution 2021-03-04 13:34:24 +02:00
Slava Monich
f562149d18 Merge pull request #8 from monich/radio-1.2
Support for android.hardware.radio@1.2 interfaces
2021-03-04 13:26:42 +02:00
Matti Lehtimäki
21d659a5c5 [gbinder-radio] Attach to the highest supported interface. JB#50597 2021-03-04 02:28:52 +02:00
Matti Lehtimäki
71f5632e2d [gbinder-radio] Added android.hardware.radio@1.2 types. JB#50597
Add missing android.hardware.radio@1.1 entry to radio_req_resp.
2021-03-03 18:15:45 +02:00
Slava Monich
30e7563d94 Version 1.0.11 2020-10-01 21:05:56 +03:00
Slava Monich
26a321bc36 [gbinder-radio] Added req => resp mapping for radio@1.1 calls 2020-10-01 21:03:42 +03:00
Slava Monich
f141bd1615 Merge pull request #7 from nemomobile-ux/permissions
Install the library with exe permissions.
2020-10-01 20:58:26 +03:00
Rinigus
d3a63909c7 [gbinder-radio] Install the library with exe permissions. JB#51013
Signed-off-by: Rinigus <rinigus.git@gmail.com>
2020-09-30 23:02:43 +03:00
Slava Monich
aaa1c0c9a0 Version 1.0.10 2020-06-03 15:35:18 +03:00
Slava Monich
e0ffc4d60c Merge pull request #6 from monich/lib64
Respect arch specific lib dir
2020-06-03 15:22:39 +03:00
Slava Monich
94d469380e [gbinder-radio] Respect arch specific lib dir. JB#49681 2020-06-03 04:04:01 +03:00
Slava Monich
7e4b839fc6 [gbinder-radio] Hide internal symbols 2020-06-03 04:04:01 +03:00
Slava Monich
0708177e94 [gbinder-radio] Constants for android.hardware.radio@1.1 interfaces 2020-06-03 04:03:54 +03:00
Slava Monich
9047ef9a56 [gbinder-radio] Ignore GLib deprecation warnings 2020-06-02 20:14:05 +03:00
Slava Monich
bb61f00d57 Version 1.0.9 2020-03-24 12:37:01 +02:00
Slava Monich
601ef084ee Added AUTHORS file 2020-03-24 12:33:40 +02:00
Slava Monich
3cd41646b4 Merge pull request #5 from Danct12/1.0.8-deb
[debian] Packaging for Debian-based distros. JB#42254
2020-03-24 12:29:17 +02:00
Danct12
d1fb490f9b Initial packaging for Debian
Signed-off-by: Danct12 <danct12@disroot.org>
2020-03-24 09:16:30 +07:00
Slava Monich
7e0c222f1d Version 1.0.8 2019-08-14 18:03:57 +03:00
Slava Monich
f5b2cc062c [gbinder-radio] Added RADIO_DEVICE_STATE enum. JB#46836 2019-08-14 18:00:57 +03:00
Slava Monich
9e246ebb55 Version 1.0.7 2019-07-02 14:23:45 +03:00
Slava Monich
5f5afc3d76 Fixed syntax error in a last-minute change 2019-07-02 14:23:32 +03:00
Slava Monich
eab404c46b Merge pull request #4 from monich/enabled
Add enabled attribute to RadioInstance
2019-07-02 14:11:40 +03:00
Slava Monich
395a50ba3d [gbinder-radio] Added enabled attribute to RadioInstance. JB#46324
And these new functions:

  radio_instance_new_with_modem_and_slot()
  radio_instance_set_enabled()
  radio_instance_add_enabled_handler()
2019-06-28 19:00:26 +03:00
Slava Monich
79379ea3d1 Version 1.0.6 2019-04-30 12:04:25 +03:00
Slava Monich
197e84e71a [gbinder-radio] Added RadioDataProfile enums. JB#45342
RADIO_DATA_PROFILE_ID and RADIO_APN_TYPES
2019-04-30 12:02:32 +03:00
Slava Monich
30ea57a3cb Version 1.0.5 2019-03-19 12:45:16 +02:00
Slava Monich
49fcc2a599 Merge pull request #2 from krnlyng/jb44067
Add HardwareConfig types
2019-03-19 12:43:01 +02:00
Frajo Haider
6d9f87f7ea [gbinder-radio] add HardwareConfig types. JB#44067 2019-03-19 12:39:42 +02:00
Slava Monich
efc30cd06d Version 1.0.4 2019-03-06 00:41:13 +02:00
Slava Monich
6959979384 [gbinder-radio] Fixed death handling. JB#44551
Listeners were being registered for the wrong signal.
2019-03-06 00:38:32 +02:00
Slava Monich
1ebf32bc73 Version 1.0.3 2019-03-05 02:59:50 +02:00
Slava Monich
a119a68374 [gbinder-radio] Added RADIO_APN_AUTH_TYPE enum. JB#44551 2019-03-05 02:56:47 +02:00
Slava Monich
1e7506e7ac Version 1.0.2 2019-02-22 00:14:31 +02:00
Slava Monich
bd20f5aabe [gbinder-radio] Optimize radio_instance_response()
... by using gbinder_reader_read_hidl_struct() instead of
gbinder_reader_read_buffer(). The former doesn't allocate
anything - it returns direct pointer to the memory block
associated with the transaction.
2019-02-22 00:14:00 +02:00
Slava Monich
42fc35fbc7 [gbinder-radio] Moved RadioResponseInfo to radio_types.h. JB#44551 2019-02-22 00:06:45 +02:00
Slava Monich
031228b3a8 Version 1.0.1 2019-01-30 00:06:19 +02:00
Slava Monich
bcb1963582 [gbinder-radio] Added more IRadio types. JB#44067
Specifically, RADIO_ACCESS_FAMILY and RadioActivityStatsInfo.
2019-01-29 23:59:15 +02:00
63 changed files with 14756 additions and 235 deletions

12
.gitignore vendored
View File

@@ -1,15 +1,15 @@
*~
debian/files
debian/libgbinder-radio-dev.debhelper.log
debian/libgbinder-radio-dev.substvars
debian/libgbinder-radio-dev
debian/libgbinder-radio.debhelper.log
debian/libgbinder-radio.postinst.debhelper
debian/libgbinder-radio.postrm.debhelper
debian/libgbinder-radio.substvars
debian/libgbinder-radio
debian/*.debhelper.log
debian/*.debhelper
debian/*.substvars
debian/*.install
debian/tmp
documentation.list
unit/coverage/*.gcov
unit/coverage/report
installroot
build
RPMS

6
AUTHORS Normal file
View File

@@ -0,0 +1,6 @@
Danct12 <danct12@disroot.org>
Denis Grigorev <d.grigorev@omprussia.ru>
Frajo Haider <f_haider@gmx.at>
Matti Lehtimäki <matti.lehtimaki@jolla.com>
Rinigus <rinigus.git@gmail.com>
Slava Monich <slava@monich.com>

33
LICENSE Normal file
View File

@@ -0,0 +1,33 @@
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 the 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.
The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
any official policies, either expressed or implied.

View File

@@ -1,7 +1,8 @@
# -*- Mode: makefile-gmake -*-
.PHONY: clean all debug release coverage
.PHONY: clean all debug release coverage test
.PHONY: debug_lib release_lib coverage_lib
.PHONY: print_debug_lib print_release_lib print_coverage_lib
.PHONY: pkgconfig install install-dev
@@ -22,8 +23,8 @@ all: debug release pkgconfig
#
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_RELEASE = 0
VERSION_MINOR = 4
VERSION_RELEASE = 11
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
@@ -46,8 +47,13 @@ LIB = $(LIB_NAME).a
#
SRC = \
radio_base.c \
radio_client.c \
radio_config.c \
radio_instance.c \
radio_registry.c \
radio_request.c \
radio_request_group.c \
radio_util.c
#
@@ -78,10 +84,7 @@ 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
@@ -141,12 +144,26 @@ coverage_lib: $(COVERAGE_LIB)
pkgconfig: $(PKGCONFIG)
print_debug_lib:
@echo $(DEBUG_LIB)
print_release_lib:
@echo $(RELEASE_LIB)
print_coverage_lib:
@echo $(COVERAGE_LIB)
clean:
make -C unit clean
rm -f *~ $(SRC_DIR)/*~ $(INCLUDE_DIR)/*~
rm -fr $(BUILD_DIR) RPMS installroot
rm -fr debian/tmp debian/libgbinder debian/libgbinder-dev
rm -fr debian/tmp debian/libgbinder-radio debian/libgbinder-radio-dev
rm -f documentation.list debian/files debian/*.substvars
rm -f debian/*.debhelper.log debian/*.debhelper debian/*~
rm -f debian/*.install
test:
make -C unit test
$(BUILD_DIR):
mkdir -p $@
@@ -192,25 +209,34 @@ $(COVERAGE_LIB): $(COVERAGE_OBJS)
$(AR) rc $@ $?
ranlib $@
#
# 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 $< > $@
sed -e 's|@version@|$(PCVERSION)|g' -e 's|@libdir@|$(ABS_LIBDIR)|g' $< > $@
debian/%.install: debian/%.install.in
sed 's|@LIBDIR@|$(LIBDIR)|g' $< > $@
#
# Install
#
INSTALL_PERM = 644
INSTALL = install
INSTALL_DIRS = $(INSTALL) -d
INSTALL_FILES = $(INSTALL) -m $(INSTALL_PERM)
INSTALL_FILES = $(INSTALL) -m 644
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)

2
README Normal file
View File

@@ -0,0 +1,2 @@
A library for communicating with Android IRadio binder services,
built on top of libgbinder.

138
debian/changelog vendored Normal file
View File

@@ -0,0 +1,138 @@
libgbinder-radio (1.4.11) unstable; urgency=medium
* Added radio_request_user_data()
-- Slava Monich <slava.monich@jolla.com> Wed, 31 Aug 2022 19:10:49 +0300
libgbinder-radio (1.4.10) unstable; urgency=medium
* Tweaked completion callback criteria
-- Slava Monich <slava.monich@jolla.com> Fri, 15 Apr 2022 21:58:17 +0300
libgbinder-radio (1.4.9) unstable; urgency=medium
* Added IMS types
-- Slava Monich <slava.monich@jolla.com> Thu, 17 Feb 2022 01:47:27 +0200
libgbinder-radio (1.4.8) unstable; urgency=medium
* Fixed retries of blocking requests
-- Slava Monich <slava.monich@jolla.com> Wed, 19 Jan 2022 03:32:30 +0200
libgbinder-radio (1.4.7) unstable; urgency=medium
* Fixed owner queue logic
-- Slava Monich <slava.monich@jolla.com> Mon, 10 Jan 2022 01:03:28 +0200
libgbinder-radio (1.4.6) unstable; urgency=medium
* Added RadioConfig API
-- Slava Monich <slava.monich@jolla.com> Sat, 08 Jan 2022 20:58:06 +0200
libgbinder-radio (1.4.5) unstable; urgency=medium
* Added radio_req_resp2()
-- Slava Monich <slava.monich@jolla.com> Thu, 16 Dec 2021 01:18:54 +0200
libgbinder-radio (1.4.4) unstable; urgency=medium
* Added IRadio@1.2 IndicationFilter bits
-- Slava Monich <slava.monich@jolla.com> Tue, 14 Dec 2021 18:01:43 +0200
libgbinder-radio (1.4.3) unstable; urgency=medium
* Added RadioClient and related APIs
-- Slava Monich <slava.monich@jolla.com> Thu, 02 Dec 2021 19:08:47 +0200
libgbinder-radio (1.4.2) unstable; urgency=medium
* Don't assume that GBinderServiceManager is a GObject
* Added unit tests
-- Slava Monich <slava.monich@jolla.com> Sun, 12 Sep 2021 18:05:19 +0300
libgbinder-radio (1.4.1) unstable; urgency=medium
* Added RADIO_CELL_INFO_TYPE_1_4 enum
-- Slava Monich <slava.monich@jolla.com> Thu, 20 May 2021 16:32:16 +0300
libgbinder-radio (1.4.0) unstable; urgency=medium
* Support for radio@1.4 interfaces
* Fixed RadioCellInfo_1_4 definition
-- Slava Monich <slava.monich@jolla.com> Tue, 18 May 2021 18:54:52 +0300
libgbinder-radio (1.2.6) unstable; urgency=medium
* Added RadioSimApdu type
-- Slava Monich <slava.monich@jolla.com> Sun, 25 Apr 2021 14:41:32 +0300
libgbinder-radio (1.2.5) unstable; urgency=medium
* Added radio@1.3 types
* Added radio@1.4 types
-- Slava Monich <slava.monich@jolla.com> Thu, 25 Mar 2021 20:13:08 +0200
libgbinder-radio (1.2.4) unstable; urgency=medium
* Added more radio@1.2 types
-- Slava Monich <slava.monich@jolla.com> Sat, 20 Mar 2021 02:41:07 +0200
libgbinder-radio (1.2.3) unstable; urgency=medium
* Reformatted radio@1.2 types
-- Slava Monich <slava.monich@jolla.com> Fri, 19 Mar 2021 05:21:52 +0200
libgbinder-radio (1.2.2) unstable; urgency=medium
* Added radio_instance_get_with_version()
-- Slava Monich <slava.monich@jolla.com> Fri, 05 Mar 2021 14:00:20 +0200
libgbinder-radio (1.2.1) unstable; urgency=medium
* Fixed backward compatibility with radio@1.0
-- Slava Monich <slava.monich@jolla.com> Fri, 05 Mar 2021 12:33:50 +0200
libgbinder-radio (1.2.0) unstable; urgency=medium
* Support for radio@1.2 interfaces
-- Slava Monich <slava.monich@jolla.com> Thu, 04 Mar 2021 13:36:51 +0200
libgbinder-radio (1.0.11) unstable; urgency=medium
* Make library executable on RPM based systems
* Added req => resp mapping for radio@1.1 calls
-- Slava Monich <slava.monich@jolla.com> Thu, 01 Oct 2020 21:04:59 +0300
libgbinder-radio (1.0.10) unstable; urgency=medium
* Hide internal symbols
* Respect arch specific lib dir
* Ignore GLib deprecation warnings
* Added constants for android.hardware.radio@1.1 interfaces
-- Slava Monich <slava.monich@jolla.com> Wed, 03 Jun 2020 15:24:17 +0300
libgbinder-radio (1.0.9) unstable; urgency=medium
* Added packaging for Debian-based distros.
-- Danct12 <danct12@disroot.org> Tue, 24 Mar 2020 02:55:50 +0700

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
9

17
debian/control vendored Normal file
View File

@@ -0,0 +1,17 @@
Source: libgbinder-radio
Priority: optional
Maintainer: Danct12 <danct12@disroot.org>
Build-Depends: debhelper (>=9), libgbinder-dev (>= 1.1.14), libglibutil-dev (>= 1.0.49)
Standards-Version: 3.9.6
Package: libgbinder-radio-dev
Section: libdevel
Architecture: any
Depends: libgbinder-radio (= ${binary:Version}), ${misc:Depends}
Description: Development files for libgbinder-radio
Package: libgbinder-radio
Section: libs
Architecture: any
Depends: libgbinder (>= 1.1.14), libglibutil (>= 1.0.49), ${shlibs:Depends}, ${misc:Depends}
Description: Binder client library for Android radio interfaces

33
debian/copyright vendored Normal file
View File

@@ -0,0 +1,33 @@
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 the 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.
The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
any official policies, either expressed or implied.

View File

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

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

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

14
debian/rules vendored Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/make -f
# Uncomment to enable verbose build
#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-radio.install debian/libgbinder-radio-dev.install
override_dh_auto_install:
dh_auto_install -- LIBDIR=$(LIBDIR) install-dev
%:
dh $@

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (native)

143
include/radio_client.h Normal file
View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_CLIENT_H
#define RADIO_CLIENT_H
/* This API exists since 1.4.3 */
#include <radio_types.h>
G_BEGIN_DECLS
typedef
void
(*RadioClientIndicationFunc)(
RadioClient* client,
RADIO_IND code,
const GBinderReader* reader,
gpointer user_data);
typedef
void
(*RadioClientFunc)(
RadioClient* client,
gpointer user_data);
RadioClient*
radio_client_new(
RadioInstance* instance)
G_GNUC_WARN_UNUSED_RESULT;
RadioClient*
radio_client_ref(
RadioClient* client);
void
radio_client_unref(
RadioClient* client);
RADIO_INTERFACE
radio_client_interface(
RadioClient* client);
const char*
radio_client_slot(
RadioClient* client);
gboolean
radio_client_dead(
RadioClient* client);
gboolean
radio_client_connected(
RadioClient* client);
void
radio_client_set_default_timeout(
RadioClient* client,
int milliseconds);
gulong
radio_client_add_indication_handler(
RadioClient* client,
RADIO_IND code,
RadioClientIndicationFunc func,
gpointer user_data);
gulong
radio_client_add_owner_changed_handler(
RadioClient* client,
RadioClientFunc func,
gpointer user_data);
gulong
radio_client_add_death_handler(
RadioClient* client,
RadioClientFunc func,
gpointer user_data);
gulong
radio_client_add_connected_handler(
RadioClient* client,
RadioClientFunc func,
gpointer user_data);
void
radio_client_remove_handler(
RadioClient* client,
gulong id);
void
radio_client_remove_handlers(
RadioClient* client,
gulong* ids,
int count);
#define radio_client_remove_all_handlers(client,ids) \
radio_client_remove_handlers(client, ids, G_N_ELEMENTS(ids))
G_END_DECLS
#endif /* RADIO_CLIENT_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

197
include/radio_config.h Normal file
View File

@@ -0,0 +1,197 @@
/*
* Copyright (C) 2022 Jolla Ltd.
* Copyright (C) 2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_CONFIG_H
#define RADIO_CONFIG_H
/* This API exists since 1.4.6 */
#include <radio_config_types.h>
G_BEGIN_DECLS
typedef
void
(*RadioConfigFunc)(
RadioConfig* config,
gpointer user_data);
typedef
void
(*RadioConfigRequestObserverFunc)(
RadioConfig* config,
RADIO_CONFIG_REQ code,
GBinderLocalRequest* args,
gpointer user_data);
typedef
void
(*RadioConfigResponseObserverFunc)(
RadioConfig* config,
RADIO_CONFIG_RESP code,
const RadioResponseInfo* info,
const GBinderReader* args,
gpointer user_data);
typedef
void
(*RadioConfigIndicationObserverFunc)(
RadioConfig* config,
RADIO_CONFIG_IND code,
const GBinderReader* args,
gpointer user_data);
RadioConfig*
radio_config_new(void)
G_GNUC_WARN_UNUSED_RESULT;
RadioConfig*
radio_config_new_with_version(
RADIO_CONFIG_INTERFACE max_version)
G_GNUC_WARN_UNUSED_RESULT;
RadioConfig*
radio_config_ref(
RadioConfig* config);
void
radio_config_unref(
RadioConfig* config);
gboolean
radio_config_dead(
RadioConfig* config);
RADIO_CONFIG_INTERFACE
radio_config_interface(
RadioConfig* config);
gsize
radio_config_rpc_header_size(
RadioConfig* config,
RADIO_CONFIG_REQ req);
const char*
radio_config_req_name(
RadioConfig* config,
RADIO_CONFIG_REQ req);
const char*
radio_config_resp_name(
RadioConfig* config,
RADIO_CONFIG_RESP resp);
const char*
radio_config_ind_name(
RadioConfig* config,
RADIO_CONFIG_IND ind);
gulong
radio_config_add_death_handler(
RadioConfig* config,
RadioConfigFunc func,
gpointer user_data);
gulong
radio_config_add_request_observer(
RadioConfig* config,
RADIO_CONFIG_REQ code,
RadioConfigRequestObserverFunc func,
gpointer user_data);
gulong
radio_config_add_request_observer_with_priority(
RadioConfig* config,
RADIO_OBSERVER_PRIORITY priority,
RADIO_CONFIG_REQ code,
RadioConfigRequestObserverFunc func,
gpointer user_data);
gulong
radio_config_add_response_observer(
RadioConfig* config,
RADIO_CONFIG_RESP code,
RadioConfigResponseObserverFunc func,
gpointer user_data);
gulong
radio_config_add_response_observer_with_priority(
RadioConfig* config,
RADIO_OBSERVER_PRIORITY priority,
RADIO_CONFIG_RESP code,
RadioConfigResponseObserverFunc func,
gpointer user_data);
gulong
radio_config_add_indication_observer(
RadioConfig* config,
RADIO_CONFIG_IND code,
RadioConfigIndicationObserverFunc func,
gpointer user_data);
gulong
radio_config_add_indication_observer_with_priority(
RadioConfig* config,
RADIO_OBSERVER_PRIORITY priority,
RADIO_CONFIG_IND code,
RadioConfigIndicationObserverFunc func,
gpointer user_data);
void
radio_config_remove_handler(
RadioConfig* config,
gulong id);
void
radio_config_remove_handlers(
RadioConfig* config,
gulong* ids,
int count);
#define radio_config_remove_all_handlers(config,ids) \
radio_config_remove_handlers(config, ids, G_N_ELEMENTS(ids))
G_END_DECLS
#endif /* RADIO_CONFIG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2022 Jolla Ltd.
* Copyright (C) 2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_CONFIG_TYPES_H
#define RADIO_CONFIG_TYPES_H
/* This API exists since 1.4.6 */
#include <radio_types.h>
G_BEGIN_DECLS
typedef enum radio_config_interface {
RADIO_CONFIG_INTERFACE_NONE = -1,
RADIO_CONFIG_INTERFACE_1_0,
RADIO_CONFIG_INTERFACE_1_1,
RADIO_CONFIG_INTERFACE_COUNT
} RADIO_CONFIG_INTERFACE;
#define RADIO_CONFIG_INTERFACE_MAX (RADIO_CONFIG_INTERFACE_COUNT - 1)
#define RADIO_CONFIG_INSTANCE "default"
#define RADIO_CONFIG_IFACE_PREFIX "android.hardware.radio.config@"
#define RADIO_CONFIG_IFACE "IRadioConfig"
#define RADIO_CONFIG_RESPONSE_IFACE "IRadioConfigResponse"
#define RADIO_CONFIG_INDICATION_IFACE "IRadioConfigIndication"
#define RADIO_CONFIG_IFACE_1_0(x) RADIO_CONFIG_IFACE_PREFIX "1.0::" x
#define RADIO_CONFIG_IFACE_1_1(x) RADIO_CONFIG_IFACE_PREFIX "1.1::" x
#define RADIO_CONFIG_1_0 RADIO_CONFIG_IFACE_1_0(RADIO_CONFIG_IFACE)
#define RADIO_CONFIG_1_1 RADIO_CONFIG_IFACE_1_1(RADIO_CONFIG_IFACE)
#define RADIO_CONFIG_1_0_FQNAME RADIO_CONFIG_1_0 "/" RADIO_CONFIG_INSTANCE
#define RADIO_CONFIG_1_1_FQNAME RADIO_CONFIG_1_1 "/" RADIO_CONFIG_INSTANCE
#define RADIO_CONFIG_RESPONSE_1_0 \
RADIO_CONFIG_IFACE_1_0(RADIO_CONFIG_RESPONSE_IFACE)
#define RADIO_CONFIG_RESPONSE_1_1 \
RADIO_CONFIG_IFACE_1_1(RADIO_CONFIG_RESPONSE_IFACE)
#define RADIO_CONFIG_INDICATION_1_0 \
RADIO_CONFIG_IFACE_1_0(RADIO_CONFIG_INDICATION_IFACE)
#define RADIO_CONFIG_INDICATION_1_1 \
RADIO_CONFIG_IFACE_1_1(RADIO_CONFIG_INDICATION_IFACE)
/* Types defined in types.hal */
/* SlotState */
typedef enum radio_slot_state {
RADIO_SLOT_STATE_INACTIVE,
RADIO_SLOT_STATE_ACTIVE
} RADIO_SLOT_STATE;
G_STATIC_ASSERT(sizeof(RADIO_SLOT_STATE) == 4);
/* SimSlotStatus */
typedef struct radio_sim_slot_status {
RADIO_CARD_STATE cardState RADIO_ALIGNED(4);
RADIO_SLOT_STATE slotState RADIO_ALIGNED(4);
GBinderHidlString atr RADIO_ALIGNED(8);
guint32 logicalSlotId RADIO_ALIGNED(4);
GBinderHidlString iccid RADIO_ALIGNED(8);
} RADIO_ALIGNED(8) RadioSimSlotStatus;
G_STATIC_ASSERT(sizeof(RadioSimSlotStatus) == 48);
/* ModemInfo */
typedef struct radio_modem_info {
guint8 modemId RADIO_ALIGNED(1);
} RADIO_ALIGNED(1) RadioModemInfo;
G_STATIC_ASSERT(sizeof(RadioModemInfo) == 1);
/* PhoneCapability */
typedef struct radio_phone_capability {
guint8 maxActiveData RADIO_ALIGNED(1);
guint8 maxActiveInternetData RADIO_ALIGNED(1);
guint8 isInternetLingeringSupported RADIO_ALIGNED(1);
GBinderHidlVec logicalModemList RADIO_ALIGNED(8); /* vec<ModemInfo> */
} RADIO_ALIGNED(8) RadioPhoneCapability;
G_STATIC_ASSERT(sizeof(RadioPhoneCapability) == 24);
/* ModemsConfig */
typedef struct radio_modems_config {
guint8 numOfLiveModems RADIO_ALIGNED(1);
} RADIO_ALIGNED(1) RadioModemsConfig;
G_STATIC_ASSERT(sizeof(RadioModemsConfig) == 1);
/* Transaction codes */
/* c(req,resp,Name,CALL_NAME) */
#define RADIO_CONFIG_CALL_1_0(c) \
c(2,1,getSimSlotsStatus,GET_SIM_SLOTS_STATUS) \
c(3,2,setSimSlotsMapping,SET_SIM_SLOTS_MAPPING)
#define RADIO_CONFIG_CALL_1_1(c) \
c(4,3,getPhoneCapability,GET_PHONE_CAPABILITY) \
c(5,4,setPreferredDataModem,SET_PREFERRED_DATA_MODEM) \
c(6,5,setModemsConfig,SET_MODEMS_CONFIG) \
c(7,6,getModemsConfig,GET_MODEMS_CONFIG)
/* i(code,Name,IND_NAME) */
#define RADIO_CONFIG_IND_1_0(i) \
i(1,simSlotsStatusChanged,SIM_SLOTS_STATUS_CHANGED)
typedef enum radio_config_req {
RADIO_CONFIG_REQ_ANY = 0,
RADIO_CONFIG_REQ_NONE = 0,
#define RADIO_CONFIG_REQ_(req,resp,Name,NAME) RADIO_CONFIG_REQ_##NAME = req,
/* android.hardware.radio.config@1.0::IRadioConfig */
RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS = 1, /* setResponseFunctions */
RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_REQ_)
RADIO_CONFIG_1_0_REQ_LAST = RADIO_CONFIG_REQ_SET_SIM_SLOTS_MAPPING,
/* android.hardware.radio.config@1.1::IRadioConfig */
RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_REQ_)
RADIO_CONFIG_1_1_REQ_LAST = RADIO_CONFIG_REQ_GET_MODEMS_CONFIG
#undef RADIO_CONFIG_REQ_
} RADIO_CONFIG_REQ;
G_STATIC_ASSERT(sizeof(RADIO_CONFIG_REQ) == 4);
typedef enum radio_config_resp {
RADIO_CONFIG_RESP_ANY = 0,
RADIO_CONFIG_RESP_NONE = 0,
#define RADIO_CONFIG_RESP_(req,resp,Name,NAME) RADIO_CONFIG_RESP_##NAME = resp,
/* android.hardware.radio.config@1.0::IRadioConfigResponse */
RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_RESP_)
RADIO_CONFIG_1_0_RESP_LAST = RADIO_CONFIG_RESP_SET_SIM_SLOTS_MAPPING,
/* android.hardware.radio.config@1.1::IRadioConfigResponse */
RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_RESP_)
RADIO_CONFIG_1_1_RESP_LAST = RADIO_CONFIG_RESP_GET_MODEMS_CONFIG
#undef RADIO_CONFIG_RESP_
} RADIO_CONFIG_RESP;
G_STATIC_ASSERT(sizeof(RADIO_CONFIG_RESP) == 4);
typedef enum radio_config_ind {
RADIO_CONFIG_IND_ANY = 0,
RADIO_CONFIG_IND_NONE = 0,
#define RADIO_CONFIG_IND_(code,Name,NAME) RADIO_CONFIG_IND_##NAME = code,
/* android.hardware.radio.config@1.0::IRadioConfigIndication */
RADIO_CONFIG_IND_1_0(RADIO_CONFIG_IND_)
RADIO_CONFIG_1_0_IND_LAST = RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED
#undef RADIO_CONFIG_IND_
} RADIO_CONFIG_IND;
G_STATIC_ASSERT(sizeof(RADIO_CONFIG_IND) == 4);
G_END_DECLS
#endif /* RADIO_CONFIG_TYPES_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -52,13 +52,21 @@ struct radio_instance {
const char* dev;
const char* slot;
const char* key;
/* Since 1.0.7 */
const char* modem; /* D-Bus path */
int slot_index; /* 0 for SIM1, 1 for SIM2 and so on */
gboolean enabled;
/* Since 1.2.0 */
RADIO_INTERFACE version;
/* Since 1.4.3 */
gboolean connected; /* rilConnected received */
};
typedef struct radio_response_info {
RADIO_RESP_TYPE type;
guint32 serial;
guint32 error;
} RadioResponseInfo;
/* These were introduced in 1.4.3 and then renamed in 1.4.6 */
#define RADIO_INSTANCE_PRIORITY_LOWEST RADIO_OBSERVER_PRIORITY_LOWEST
#define RADIO_INSTANCE_PRIORITY_DEFAULT RADIO_OBSERVER_PRIORITY_DEFAULT
#define RADIO_INSTANCE_PRIORITY_HIGHEST RADIO_OBSERVER_PRIORITY_HIGHEST
#define RADIO_INSTANCE_PRIORITY RADIO_OBSERVER_PRIORITY
typedef
void
@@ -66,6 +74,14 @@ void
RadioInstance* radio,
gpointer user_data);
typedef
void
(*RadioRequestObserverFunc)(
RadioInstance* radio,
RADIO_REQ code,
GBinderLocalRequest* args,
gpointer user_data); /* Since 1.4.3 */
typedef
gboolean
(*RadioResponseHandlerFunc)(
@@ -119,11 +135,38 @@ radio_instance_new(
const char* dev,
const char* name);
RadioInstance*
radio_instance_new_with_modem_and_slot(
const char* dev,
const char* name,
const char* modem,
int slot_index); /* Since 1.0.7 */
RadioInstance*
radio_instance_new_with_version(
const char* dev,
const char* name,
RADIO_INTERFACE version); /* Since 1.2.1 */
RadioInstance*
radio_instance_new_with_modem_slot_and_version(
const char* dev,
const char* name,
const char* modem,
int slot_index,
RADIO_INTERFACE version); /* Since 1.2.1 */
RadioInstance*
radio_instance_get(
const char* dev,
const char* name);
RadioInstance*
radio_instance_get_with_version(
const char* dev,
const char* name,
RADIO_INTERFACE version); /* Since 1.2.2 */
RadioInstance* const*
radio_instance_get_all(
void);
@@ -136,6 +179,11 @@ void
radio_instance_unref(
RadioInstance* radio);
gsize
radio_instance_rpc_header_size(
RadioInstance* radio,
RADIO_REQ req); /* Since 1.4.3 */
const char*
radio_instance_req_name(
RadioInstance* radio,
@@ -166,13 +214,41 @@ radio_instance_send_request_sync(
RADIO_REQ code,
GBinderLocalRequest* args);
gulong
radio_instance_add_indication_handler(
void
radio_instance_set_enabled(
RadioInstance* radio,
RADIO_IND code,
RadioIndicationHandlerFunc func,
gboolean enabled); /* Since 1.0.7 */
gulong
radio_instance_add_request_observer(
RadioInstance* radio,
RADIO_REQ code,
RadioRequestObserverFunc func,
gpointer user_data); /* Since 1.4.3 */
gulong
radio_instance_add_request_observer_with_priority(
RadioInstance* radio,
RADIO_OBSERVER_PRIORITY priority,
RADIO_REQ code,
RadioRequestObserverFunc func,
gpointer user_data); /* Since 1.4.3 */
gulong
radio_instance_add_response_observer(
RadioInstance* radio,
RADIO_RESP code,
RadioResponseObserverFunc func,
gpointer user_data);
gulong
radio_instance_add_response_observer_with_priority(
RadioInstance* radio,
RADIO_OBSERVER_PRIORITY priority,
RADIO_RESP code,
RadioResponseObserverFunc func,
gpointer user_data); /* Since 1.4.3 */
gulong
radio_instance_add_indication_observer(
RadioInstance* radio,
@@ -180,6 +256,14 @@ radio_instance_add_indication_observer(
RadioIndicationObserverFunc func,
gpointer user_data);
gulong
radio_instance_add_indication_observer_with_priority(
RadioInstance* radio,
RADIO_OBSERVER_PRIORITY priority,
RADIO_IND code,
RadioIndicationObserverFunc func,
gpointer user_data); /* Since 1.4.3 */
gulong
radio_instance_add_response_handler(
RadioInstance* radio,
@@ -188,10 +272,10 @@ radio_instance_add_response_handler(
gpointer user_data);
gulong
radio_instance_add_response_observer(
radio_instance_add_indication_handler(
RadioInstance* radio,
RADIO_RESP code,
RadioResponseObserverFunc func,
RADIO_IND code,
RadioIndicationHandlerFunc func,
gpointer user_data);
gulong
@@ -206,6 +290,18 @@ radio_instance_add_death_handler(
RadioInstanceFunc func,
gpointer user_data);
gulong
radio_instance_add_enabled_handler(
RadioInstance* radio,
RadioInstanceFunc func,
gpointer user_data); /* Since 1.0.7 */
gulong
radio_instance_add_connected_handler(
RadioInstance* radio,
RadioInstanceFunc func,
gpointer user_data); /* Since 1.4.3 */
void
radio_instance_remove_handler(
RadioInstance* radio,

224
include/radio_request.h Normal file
View File

@@ -0,0 +1,224 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_REQUEST_H
#define RADIO_REQUEST_H
/* This API exists since 1.4.3 */
#include <radio_config_types.h>
/*
* Basic workflow
*
* 1. radio_request_new() or radio_request_new2() creates the request.
* That assigns a serial and initializes GBinderWriter for appending
* more arguments. GBinderWriter pointer can be NULL if serial is the
* only argument.
* 2. The caller (optionally) uses GBinderWriter to add more arguments
* to the request.
* 3. radio_request_submit() submits the request
* 4. radio_request_unref() can be called at this point to release the
* reference produced by radio_request_new() unless the caller needs
* to keep it. In any case, radio_request_unref() has to be called
* sooner or later for each request created by radio_request_new().
* The library keeps its own internal reference while the request is
* being processed.
* 5. RadioRequestCompleteFunc receives the response from the radio service.
*/
G_BEGIN_DECLS
typedef enum radio_tx_status {
RADIO_TX_STATUS_OK, /* Successful completion, no error */
RADIO_TX_STATUS_FAILED, /* Request transaction failed */
RADIO_TX_STATUS_TIMEOUT /* No response transaction received */
} RADIO_TX_STATUS;
/*
* RadioRequestCompleteFunc
* RadioConfigRequestCompleteFunc
*
* Invoked upon completion of each request. If an error occurs,
* resp is set to zero (RADIO_RESP_NONE, RADIO_CONFIG_RESP_NONE)
* and args is NULL.
*
* The status argument is the status of the request transaction.
* If it's anything other than RADIO_TX_STATUS_OK, the request
* transaction failed (or response didn't arrive in time) and
* the other arguments can be ignored.
*
* If status is RADIO_TX_STATUS_OK then the resp, error and args
* arguments contain the information received in the response.
*/
typedef
void
(*RadioRequestCompleteFunc)(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_RESP resp,
RADIO_ERROR error,
const GBinderReader* args,
gpointer user_data);
typedef
void
(*RadioConfigRequestCompleteFunc)(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_CONFIG_RESP resp,
RADIO_ERROR error,
const GBinderReader* args,
gpointer user_data); /* Since 1.4.6 */
/*
* RadioRequestRetryFunc
*
* If retries are enabled with radio_request_set_retry_func(), then this
* callback is invoiked to check whether the request should be retried,
* based on the status received from the radio service and the contents
* of the reply. If such callback returns TRUE, the request is retried
* at some point in the future with a new serial, otherwise it gets
* completed right away.
*
* user_data is the pointer passed to radio_request_new() when the request
* was created.
*/
typedef
gboolean
(*RadioRequestRetryFunc)(
RadioRequest* req,
RADIO_TX_STATUS status,
guint32 resp, /* Was RADIO_RESP before 1.4.6 */
RADIO_ERROR error,
const GBinderReader* args,
void* user_data);
RadioRequest*
radio_request_new(
RadioClient* client,
RADIO_REQ code,
GBinderWriter* args, /* NULL if serial is the only arg */
RadioRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
G_GNUC_WARN_UNUSED_RESULT;
RadioRequest*
radio_request_new2(
RadioRequestGroup* group,
RADIO_REQ code,
GBinderWriter* args, /* NULL if serial is the only arg */
RadioRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
G_GNUC_WARN_UNUSED_RESULT;
RadioRequest*
radio_config_request_new(
RadioConfig* config,
RADIO_CONFIG_REQ code,
GBinderWriter* args, /* NULL if serial is the only arg */
RadioConfigRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data) /* Since 1.4.6 */
G_GNUC_WARN_UNUSED_RESULT;
RadioRequest*
radio_request_ref(
RadioRequest* req);
void
radio_request_unref(
RadioRequest* req);
void
radio_request_set_blocking(
RadioRequest* req,
gboolean blocking);
void
radio_request_set_timeout(
RadioRequest* req,
guint milliseconds); /* Zero to use the default timeout */
void
radio_request_set_retry(
RadioRequest* req,
guint delay_ms, /* Delay before each retry, in milliseconds */
int max_count); /* Negative count to keep retrying indefinitely */
void
radio_request_set_retry_func(
RadioRequest* req,
RadioRequestRetryFunc retry);
gboolean
radio_request_submit(
RadioRequest* req);
gboolean
radio_request_retry(
RadioRequest* req);
void
radio_request_cancel(
RadioRequest* req);
void
radio_request_drop( /* cancel and unref */
RadioRequest* req);
void
radio_request_set_retry_func(
RadioRequest* req,
RadioRequestRetryFunc retry);
void*
radio_request_user_data(
RadioRequest* req); /* Since 1.4.11 */
G_END_DECLS
#endif /* RADIO_REQUEST_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_REQUEST_GROUP_H
#define RADIO_REQUEST_GROUP_H
/* This API exists since 1.4.3 */
#include <radio_types.h>
/*
* In addition to being just a group of requests and making it easier
* to perform bulk operations (i.e. cancel all), RadioRequestGroup can
* be given the "blocker" status by its RadioClient and then only requests
* belonging to this group will be submitted until the block is released.
*/
G_BEGIN_DECLS
struct radio_request_group {
RadioClient* client;
};
RadioRequestGroup*
radio_request_group_new(
RadioClient* client)
G_GNUC_WARN_UNUSED_RESULT;
RadioRequestGroup*
radio_request_group_ref(
RadioRequestGroup* group);
void
radio_request_group_unref(
RadioRequestGroup* group);
void
radio_request_group_cancel(
RadioRequestGroup* group);
RADIO_BLOCK
radio_request_group_block_status(
RadioRequestGroup* group);
RADIO_BLOCK
radio_request_group_block(
RadioRequestGroup* group);
void
radio_request_group_unblock(
RadioRequestGroup* group);
G_END_DECLS
#endif /* RADIO_REQUEST_GROUP_H */
/*
* 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-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -55,7 +55,13 @@ radio_ind_name(
RADIO_RESP
radio_req_resp(
RADIO_REQ req);
RADIO_REQ req)
G_GNUC_DEPRECATED_FOR(radio_req_resp2);
RADIO_RESP
radio_req_resp2(
RADIO_REQ req,
RADIO_INTERFACE iface); /* Since 1.4.5 */
G_END_DECLS

View File

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

View File

@@ -1,14 +1,26 @@
Name: libgbinder-radio
Version: 0.0.1
Version: 1.4.11
Release: 0
Summary: Binder client library for Android radio interfaces
Group: Development/Libraries
License: BSD
URL: https://github.com/mer-hybris/libgbinder-radio
Source: %{name}-%{version}.tar.bz2
%define libgbinder_version 1.1.14
%define libglibutil_version 1.0.49
BuildRequires: pkgconfig
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libglibutil)
BuildRequires: pkgconfig(libgbinder)
BuildRequires: pkgconfig(libglibutil) >= %{libglibutil_version}
BuildRequires: pkgconfig(libgbinder) >= %{libgbinder_version}
# license macro requires rpm >= 4.11
BuildRequires: pkgconfig(rpm)
%define license_support %(pkg-config --exists 'rpm >= 4.11'; echo $?)
Requires: libglibutil >= %{libglibutil_version}
Requires: libgbinder >= %{libgbinder_version}
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
@@ -18,7 +30,6 @@ Binder client library for Android radio interfaces
%package devel
Summary: Development library for %{name}
Requires: %{name} = %{version}
Requires: pkgconfig
%description devel
This package contains the development library for %{name}.
@@ -27,11 +38,14 @@ 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
%install
rm -rf %{buildroot}
make install-dev DESTDIR=%{buildroot}
make LIBDIR=%{_libdir} DESTDIR=%{buildroot} install-dev
%check
make -C unit test
%post -p /sbin/ldconfig
@@ -40,6 +54,9 @@ make install-dev DESTDIR=%{buildroot}
%files
%defattr(-,root,root,-)
%{_libdir}/%{name}.so.*
%if %{license_support} == 0
%license LICENSE
%endif
%files devel
%defattr(-,root,root,-)

1014
src/radio_base.c Normal file

File diff suppressed because it is too large Load Diff

198
src/radio_base.h Normal file
View File

@@ -0,0 +1,198 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_BASE_H
#define RADIO_BASE_H
#include "radio_types_p.h"
#include <glib-object.h>
/* RadioBaseFunc must be compatible with RadioClientFunc */
typedef
void
(*RadioBaseFunc)(
RadioBase* base,
gpointer user_data);
typedef
void
(*RadioBaseRequestSentFunc)(
RadioBase* base,
RadioRequest* req,
int status);
typedef struct radio_base_priv RadioBasePriv;
struct radio_base {
GObject object;
RadioBasePriv* priv;
};
typedef struct radio_base_class {
GObjectClass parent;
gboolean (*is_dead)(RadioBase* base);
gboolean (*can_submit_requests)(RadioBase* base);
GBinderLocalRequest* (*new_request)(RadioBase* base, guint32 code);
gulong (*send_request)(RadioBase* base, RadioRequest* req,
RadioBaseRequestSentFunc sent);
void (*cancel_request)(RadioBase* base, gulong id);
} RadioBaseClass;
GType radio_base_get_type(void) RADIO_INTERNAL;
#define RADIO_TYPE_BASE radio_base_get_type()
#define RADIO_BASE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
RADIO_TYPE_BASE, RadioBase)
#define RADIO_BASE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
RADIO_TYPE_BASE, RadioBaseClass)
#define RADIO_BASE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
THIS_TYPE, RadioBaseClass)
void
radio_base_initialize(
RadioBase* base)
RADIO_INTERNAL;
void
radio_base_register_request(
RadioBase* base,
RadioRequest* req)
RADIO_INTERNAL;
void
radio_base_unregister_request(
RadioBase* base,
RadioRequest* req)
RADIO_INTERNAL;
gboolean
radio_base_submit_request(
RadioBase* base,
RadioRequest* req)
RADIO_INTERNAL;
gboolean
radio_base_retry_request(
RadioBase* base,
RadioRequest* req)
RADIO_INTERNAL;
void
radio_base_request_dropped(
RadioRequest* req)
RADIO_INTERNAL;
guint
radio_base_timeout_ms(
RadioBase* base,
RadioRequest* req)
RADIO_INTERNAL;
void
radio_base_reset_timeout(
RadioBase* base)
RADIO_INTERNAL;
RADIO_BLOCK
radio_base_block_status(
RadioBase* base,
RadioRequestGroup* group)
RADIO_INTERNAL;
RADIO_BLOCK
radio_base_block(
RadioBase* base,
RadioRequestGroup* group)
RADIO_INTERNAL;
void
radio_base_unblock(
RadioBase* base,
RadioRequestGroup* group)
RADIO_INTERNAL;
gboolean
radio_base_handle_resp(
RadioBase* base,
guint32 code,
const RadioResponseInfo* info,
const GBinderReader* reader)
RADIO_INTERNAL;
void
radio_base_handle_ack(
RadioBase* base,
guint32 serial)
RADIO_INTERNAL;
void
radio_base_handle_death(
RadioBase* base)
RADIO_INTERNAL;
void
radio_base_submit_requests(
RadioBase* base)
RADIO_INTERNAL;
void
radio_base_cancel_request(
RadioBase* base,
RadioRequest* req)
RADIO_INTERNAL;
void
radio_base_set_default_timeout(
RadioBase* self,
int ms)
RADIO_INTERNAL;
gulong
radio_base_add_owner_changed_handler(
RadioBase* base,
RadioBaseFunc func,
gpointer user_data)
RADIO_INTERNAL;
#endif /* RADIO_BASE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

473
src/radio_client.c Normal file
View File

@@ -0,0 +1,473 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "radio_base.h"
#include "radio_client.h"
#include "radio_instance_p.h"
#include "radio_request_p.h"
#include "radio_util.h"
#include "radio_log.h"
#include <gutil_macros.h>
#include <gutil_misc.h>
/* This API exists since 1.4.3 */
enum radio_events {
RADIO_EVENT_IND,
RADIO_EVENT_RESP,
RADIO_EVENT_ACK,
RADIO_EVENT_DEATH,
RADIO_EVENT_CONNECTED,
RADIO_EVENT_COUNT
};
struct radio_client {
RadioBase base;
RadioInstance* instance;
gulong event_ids[RADIO_EVENT_COUNT];
};
typedef RadioBaseClass RadioClientClass;
GType radio_client_get_type() RADIO_INTERNAL;
G_DEFINE_TYPE(RadioClient, radio_client, RADIO_TYPE_BASE)
#define PARENT_CLASS radio_client_parent_class
#define THIS_TYPE radio_client_get_type()
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, THIS_TYPE, RadioClient)
typedef struct radio_client_call {
RadioRequest* req;
RadioBaseRequestSentFunc callback;
} RadioClientCall;
enum radio_client_signal {
SIGNAL_INDICATION,
SIGNAL_DEATH,
SIGNAL_CONNECTED,
SIGNAL_COUNT
};
#define SIGNAL_INDICATION_NAME "radio-client-indication"
#define SIGNAL_DEATH_NAME "radio-client-death"
#define SIGNAL_CONNECTED_NAME "radio-client-connected"
static guint radio_client_signals[SIGNAL_COUNT] = { 0 };
/*==========================================================================*
* Implementation
*==========================================================================*/
static
void
radio_client_call_free(
RadioClientCall* call)
{
radio_request_unref(call->req);
gutil_slice_free(call);
}
static
void
radio_client_call_destroy(
void* user_data1,
void* user_data2)
{
radio_client_call_free(user_data2);
}
static
void
radio_client_call_complete(
RadioInstance* instance,
gulong id,
int status,
void* user_data1,
void* user_data2)
{
RadioClientCall* call = user_data2;
call->callback(RADIO_BASE(user_data1), call->req, status);
}
static
void
radio_client_handle_death(
RadioInstance* instance,
gpointer user_data)
{
RadioBase* base = RADIO_BASE(user_data);
g_object_ref(base);
radio_base_handle_death(base);
g_signal_emit(base, radio_client_signals[SIGNAL_DEATH], 0);
g_object_unref(base);
}
static
void
radio_client_handle_connected(
RadioInstance* instance,
gpointer user_data)
{
g_signal_emit(THIS(user_data), radio_client_signals[SIGNAL_CONNECTED], 0);
radio_base_submit_requests(RADIO_BASE(user_data));
}
static
void
radio_client_handle_ack(
RadioInstance* instance,
guint32 serial,
gpointer user_data)
{
radio_base_handle_ack(RADIO_BASE(user_data), serial);
}
static
void
radio_client_handle_ind(
RadioInstance* instance,
RADIO_IND code,
RADIO_IND_TYPE type,
const GBinderReader* reader,
gpointer user_data)
{
g_signal_emit(THIS(user_data), radio_client_signals[SIGNAL_INDICATION],
radio_instance_ind_quark(instance, code), code, reader);
}
static
void
radio_client_handle_resp(
RadioInstance* instance,
RADIO_RESP code,
const RadioResponseInfo* info,
const GBinderReader* reader,
gpointer user_data)
{
if (!radio_base_handle_resp(RADIO_BASE(user_data), code, info, reader)) {
const char* name = radio_resp_name(code);
/* Most likely this is a response to a cancelled request */
GDEBUG("Ignoring IRadio response [%08x] %u %s", info->serial, code,
name ? name : "");
}
}
static
gulong
radio_client_add_handler(
RadioClient* self,
enum radio_client_signal sig,
RadioClientFunc fn,
gpointer user_data)
{
return (G_LIKELY(self) && G_LIKELY(fn)) ?
g_signal_connect_closure_by_id(self, radio_client_signals[sig], 0,
g_cclosure_new(G_CALLBACK(fn), user_data, NULL), FALSE) : 0;
}
/*==========================================================================*
* API
*==========================================================================*/
RadioClient*
radio_client_new(
RadioInstance* instance)
{
RadioClient* self = NULL;
if (G_LIKELY(instance)) {
self = g_object_new(THIS_TYPE, NULL);
radio_base_initialize(&self->base);
self->instance = radio_instance_ref(instance);
self->event_ids[RADIO_EVENT_IND] =
radio_instance_add_indication_observer(instance, RADIO_IND_ANY,
radio_client_handle_ind, self);
self->event_ids[RADIO_EVENT_RESP] =
radio_instance_add_response_observer(instance, RADIO_RESP_ANY,
radio_client_handle_resp, self);
self->event_ids[RADIO_EVENT_ACK] =
radio_instance_add_ack_handler(instance,
radio_client_handle_ack, self);
self->event_ids[RADIO_EVENT_DEATH] =
radio_instance_add_death_handler(instance,
radio_client_handle_death, self);
self->event_ids[RADIO_EVENT_CONNECTED] =
radio_instance_add_connected_handler(instance,
radio_client_handle_connected, self);
}
return self;
}
RadioClient*
radio_client_ref(
RadioClient* self)
{
if (G_LIKELY(self)) {
g_object_ref(self);
}
return self;
}
void
radio_client_unref(
RadioClient* self)
{
if (G_LIKELY(self)) {
g_object_unref(self);
}
}
const char*
radio_client_slot(
RadioClient* self)
{
return G_LIKELY(self) ? self->instance->slot : NULL;
}
gboolean
radio_client_dead(
RadioClient* self)
{
return !self || self->instance->dead;
}
gboolean
radio_client_connected(
RadioClient* self)
{
return self && self->instance->connected;
}
RADIO_INTERFACE
radio_client_interface(
RadioClient* self)
{
return G_LIKELY(self) ? self->instance->version : RADIO_INTERFACE_NONE;
}
void
radio_client_set_default_timeout(
RadioClient* self,
int milliseconds)
{
if (G_LIKELY(self)) {
radio_base_set_default_timeout(&self->base, milliseconds);
}
}
gulong
radio_client_add_indication_handler(
RadioClient* self,
RADIO_IND code,
RadioClientIndicationFunc fn,
gpointer user_data)
{
return (G_LIKELY(self) && G_LIKELY(fn)) ?
g_signal_connect_closure_by_id(self,
radio_client_signals[SIGNAL_INDICATION],
radio_instance_ind_quark(self->instance, code),
g_cclosure_new(G_CALLBACK(fn), user_data, NULL), FALSE) : 0;
}
gulong
radio_client_add_owner_changed_handler(
RadioClient* self,
RadioClientFunc fn,
gpointer user_data)
{
return self ? radio_base_add_owner_changed_handler(&self->base,
(RadioBaseFunc) fn, user_data) : 0;
}
gulong
radio_client_add_death_handler(
RadioClient* self,
RadioClientFunc fn,
gpointer user_data)
{
return radio_client_add_handler(self, SIGNAL_DEATH, fn, user_data);
}
gulong
radio_client_add_connected_handler(
RadioClient* self,
RadioClientFunc fn,
gpointer user_data)
{
return radio_client_add_handler(self, SIGNAL_CONNECTED, fn, user_data);
}
void
radio_client_remove_handler(
RadioClient* self,
gulong id)
{
if (G_LIKELY(id) && G_LIKELY(self)) {
g_signal_handler_disconnect(self, id);
}
}
void
radio_client_remove_handlers(
RadioClient* self,
gulong* ids,
int count)
{
gutil_disconnect_handlers(self, ids, count);
}
/*==========================================================================*
* Methods
*==========================================================================*/
static
gboolean
radio_client_is_dead(
RadioBase* base)
{
return THIS(base)->instance->dead;
}
static
gboolean
radio_client_can_submit_requests(
RadioBase* base)
{
return THIS(base)->instance->connected;
}
static
GBinderLocalRequest*
radio_client_new_request(
RadioBase* base,
guint32 code)
{
return radio_instance_new_request(THIS(base)->instance, code);
}
static
gulong
radio_client_send_request(
RadioBase* base,
RadioRequest* req,
RadioBaseRequestSentFunc callback)
{
RadioClientCall* call = g_slice_new(RadioClientCall);
gulong tx_id;
call->callback = callback;
call->req = radio_request_ref(req);
tx_id = radio_instance_send_request(THIS(base)->instance,
req->code, req->args, radio_client_call_complete,
radio_client_call_destroy, base, call);
if (tx_id) {
return tx_id;
} else {
radio_client_call_free(call);
return 0;
}
}
static
void
radio_client_cancel_request(
RadioBase* base,
gulong id)
{
radio_instance_cancel_request(THIS(base)->instance, id);
}
/*==========================================================================*
* Internals
*==========================================================================*/
static
void
radio_client_init(
RadioClient* self)
{
}
static
void
radio_client_finalize(
GObject* object)
{
RadioClient* self = THIS(object);
radio_instance_remove_all_handlers(self->instance, self->event_ids);
radio_instance_unref(self->instance);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
radio_client_class_init(
RadioClientClass* klass)
{
RadioBaseClass* base_class = RADIO_BASE_CLASS(klass);
GObjectClass* object_class = G_OBJECT_CLASS(klass);
GType type = G_OBJECT_CLASS_TYPE(klass);
base_class->is_dead = radio_client_is_dead;
base_class->can_submit_requests = radio_client_can_submit_requests;
base_class->new_request = radio_client_new_request;
base_class->send_request = radio_client_send_request;
base_class->cancel_request = radio_client_cancel_request;
object_class->finalize = radio_client_finalize;
radio_client_signals[SIGNAL_INDICATION] =
g_signal_new(SIGNAL_INDICATION_NAME, type,
G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, 0, NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
radio_client_signals[SIGNAL_DEATH] =
g_signal_new(SIGNAL_DEATH_NAME, type, G_SIGNAL_RUN_FIRST, 0,
NULL, NULL, NULL, G_TYPE_NONE, 0);
radio_client_signals[SIGNAL_CONNECTED] =
g_signal_new(SIGNAL_CONNECTED_NAME, type, G_SIGNAL_RUN_FIRST, 0,
NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

1000
src/radio_config.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

89
src/radio_instance_p.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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_INSTANCE_PRIVATE_H
#define RADIO_INSTANCE_PRIVATE_H
#include "radio_types_p.h"
#include "radio_instance.h"
typedef
void
(*RadioInstanceTxCompleteFunc)(
RadioInstance* instance,
gulong id,
int status,
void* user_data1,
void* user_data2);
typedef
void
(*RadioInstanceTxDestroyFunc)(
void* user_data1,
void* user_data2);
gulong
radio_instance_send_request(
RadioInstance* instance,
RADIO_REQ code,
GBinderLocalRequest* args,
RadioInstanceTxCompleteFunc complete,
RadioInstanceTxDestroyFunc destroy,
void* user_data1,
void* user_data2)
RADIO_INTERNAL;
void
radio_instance_cancel_request(
RadioInstance* instance,
gulong id)
RADIO_INTERNAL;
GQuark
radio_instance_ind_quark(
RadioInstance* instance,
RADIO_IND ind)
RADIO_INTERNAL;
#endif /* RADIO_INSTANCE_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -44,6 +44,7 @@ struct radio_registry {
GObject parent;
};
GType radio_registry_get_type(void) RADIO_INTERNAL;
G_DEFINE_TYPE(RadioRegistry, radio_registry, G_TYPE_OBJECT)
#define RADIO_TYPE_REGISTRY (radio_registry_get_type())
#define RADIO_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
@@ -110,7 +111,7 @@ radio_registry_new(
(gpointer*)(&radio_registry_instance));
}
return radio_registry_instance;
}
RadioRegistry*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -37,15 +37,18 @@
#ifndef RADIO_REGISTRY_PRIVATE_H
#define RADIO_REGISTRY_PRIVATE_H
#include "radio_types_p.h"
#include "radio_registry.h"
void
radio_registry_instance_added(
RadioInstance* instance);
RadioInstance* instance)
RADIO_INTERNAL;
void
radio_registry_instance_removed(
const char* key);
const char* key)
RADIO_INTERNAL;
#endif /* RADIO_REGISTRY_PRIVATE_H */

382
src/radio_request.c Normal file
View File

@@ -0,0 +1,382 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "radio_base.h"
#include "radio_request_p.h"
#include "radio_request_group_p.h"
#include "radio_log.h"
#include <gbinder_local_request.h>
#include <gbinder_writer.h>
#include <gutil_macros.h>
typedef enum radio_request_flags {
RADIO_REQUEST_NO_FLAGS = 0,
RADIO_REQUEST_FLAG_DROPPED = 0x01,
RADIO_REQUEST_FLAG_SUBMITTED = 0x02
} RADIO_REQUEST_FLAGS;
typedef struct radio_request_object {
RadioRequest pub;
GDestroyNotify destroy;
gsize serial_offset;
RADIO_REQUEST_FLAGS flags;
gint refcount;
} RadioRequestObject;
static inline RadioRequestObject* radio_request_cast(RadioRequest* req)
{ return req ? G_CAST(req, RadioRequestObject, pub) : NULL; }
/*==========================================================================*
* Implementation
*==========================================================================*/
static
void
radio_request_object_cancel(
RadioRequestObject* self)
{
RadioRequest* req = &self->pub;
radio_base_cancel_request(req->object, req);
if (!(self->flags & RADIO_REQUEST_FLAG_DROPPED)) {
self->flags |= RADIO_REQUEST_FLAG_DROPPED;
radio_request_group_remove(req->group, req);
radio_base_request_dropped(req);
}
radio_base_unregister_request(req->object, req);
}
static
void
radio_request_free(
RadioRequestObject* self)
{
RadioRequest* req = &self->pub;
GVERBOSE_("%u (%08x) %p", req->code, req->serial, req);
radio_request_object_cancel(self);
/* Don't invoke completion routine if the request was never submitted */
if (req->complete && (self->flags & RADIO_REQUEST_FLAG_SUBMITTED)) {
RadioRequestCompleteFunc complete = req->complete;
/* Request is being freed too early, before completion */
req->complete = NULL;
complete(req, RADIO_TX_STATUS_FAILED, RADIO_RESP_NONE,
RADIO_ERROR_NONE, NULL, req->user_data);
}
if (self->destroy) {
GDestroyNotify destroy = self->destroy;
self->destroy = NULL;
destroy(req->user_data);
}
gbinder_local_request_unref(req->args);
gutil_slice_free(self);
}
static
void
radio_request_object_unref(
RadioRequestObject* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
radio_request_free(self);
}
}
}
static
gboolean
radio_request_default_retry(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_RESP resp,
RADIO_ERROR error,
const GBinderReader* reader,
void* user_data)
{
if (status != RADIO_TX_STATUS_OK) {
GVERBOSE_("req %p %u (%08x) status %d", req, req->code, req->serial,
status);
return TRUE;
} else if (error != RADIO_ERROR_NONE) {
GVERBOSE_("req %p %u (%08x) error %d", req, req->code, req->serial,
error);
return TRUE;
} else {
return FALSE;
}
}
static
RadioRequest*
radio_request_object_new(
RadioBase* base,
RadioRequestGroup* group,
RADIO_REQ code,
GBinderWriter* writer,
RadioRequestGenericCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
{
RadioRequestObject* self = g_slice_new0(RadioRequestObject);
RadioRequest* req = &self->pub;
GBinderWriter tmp;
self->destroy = destroy;
g_atomic_int_set(&self->refcount, 1);
req->state = RADIO_REQUEST_STATE_NEW;
req->code = code;
req->complete = complete;
req->user_data = user_data;
req->retry = radio_request_default_retry;
/* Assign serial and add to the group */
radio_base_register_request(base, req);
radio_request_group_add(group, req);
GVERBOSE_("%u (%08x) %p group %p", req->code, req->serial, req, group);
/* Build the argument list */
if (!writer) writer = &tmp;
req->args = RADIO_BASE_GET_CLASS(base)->new_request(base, code);
gbinder_local_request_init_writer(req->args, writer);
self->serial_offset = gbinder_writer_bytes_written(writer);
gbinder_writer_append_int32(writer, req->serial);
return req;
}
/*==========================================================================*
* Internal API
*==========================================================================*/
void
radio_request_unref_func(
gpointer req)
{
radio_request_object_unref(radio_request_cast(req));
}
void
radio_request_update_serial(
RadioRequest* req,
guint32 serial)
{
GBinderWriter writer;
gbinder_local_request_init_writer(req->args, &writer);
gbinder_writer_overwrite_int32(&writer,
radio_request_cast(req)->serial_offset, serial);
}
/*==========================================================================*
* API
*==========================================================================*/
RadioRequest*
radio_request_new(
RadioClient* client,
RADIO_REQ code,
GBinderWriter* writer, /* NULL if serial is the only arg */
RadioRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
{
return client ? radio_request_object_new(RADIO_BASE(client), NULL,
code, writer, (RadioRequestGenericCompleteFunc) complete,
destroy, user_data) : NULL;
}
RadioRequest*
radio_request_new2(
RadioRequestGroup* group,
RADIO_REQ code,
GBinderWriter* writer, /* NULL if serial is the only arg */
RadioRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
{
return group ? radio_request_object_new(RADIO_BASE(group->client), group,
code, writer, (RadioRequestGenericCompleteFunc) complete,
destroy, user_data) : NULL;
}
RadioRequest*
radio_config_request_new(
RadioConfig* config,
RADIO_CONFIG_REQ code,
GBinderWriter* writer, /* NULL if serial is the only arg */
RadioConfigRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data) /* Since 1.4.6 */
{
return config ? radio_request_object_new(RADIO_BASE(config), NULL,
code, writer, (RadioRequestGenericCompleteFunc) complete,
destroy, user_data) : NULL;
}
RadioRequest*
radio_request_ref(
RadioRequest* req)
{
RadioRequestObject* self = radio_request_cast(req);
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return req;
}
void
radio_request_unref(
RadioRequest* req)
{
radio_request_object_unref(radio_request_cast(req));
}
void
radio_request_set_blocking(
RadioRequest* req,
gboolean blocking)
{
if (G_LIKELY(req)) {
req->blocking = blocking;
}
}
void
radio_request_set_timeout(
RadioRequest* req,
guint ms)
{
if (G_LIKELY(req) && req->timeout_ms != ms) {
RadioBase* base = req->object;
req->timeout_ms = ms;
if (base && req->state >= RADIO_REQUEST_STATE_QUEUED) {
const guint timeout = radio_base_timeout_ms(base, req);
req->deadline = g_get_monotonic_time() + MICROSEC(timeout);
radio_base_reset_timeout(base);
}
}
}
void
radio_request_set_retry(
RadioRequest* req,
guint delay_ms, /* Delay before each retry, in milliseconds */
int max_count) /* Negative count to keep retrying indefinitely */
{
if (G_LIKELY(req)) {
req->retry_delay_ms = delay_ms;
req->max_retries = max_count;
}
}
void
radio_request_set_retry_func(
RadioRequest* req,
RadioRequestRetryFunc retry)
{
if (G_LIKELY(req)) {
req->retry = retry ? retry : radio_request_default_retry;
}
}
gboolean
radio_request_submit(
RadioRequest* req)
{
if (req && req->object && radio_base_submit_request(req->object, req)) {
radio_request_cast(req)->flags |= RADIO_REQUEST_FLAG_SUBMITTED;
return TRUE;
}
return FALSE;
}
gboolean
radio_request_retry(
RadioRequest* req)
{
return req && req->object && radio_base_retry_request(req->object, req);
}
void
radio_request_cancel(
RadioRequest* req)
{
RadioRequestObject* self = radio_request_cast(req);
if (G_LIKELY(self)) {
req->complete = NULL;
radio_request_object_cancel(self);
}
}
void
radio_request_drop(
RadioRequest* req)
{
RadioRequestObject* self = radio_request_cast(req);
if (G_LIKELY(self)) {
req->complete = NULL;
radio_request_object_cancel(self);
radio_request_object_unref(self);
}
}
void*
radio_request_user_data(
RadioRequest* req) /* Since 1.4.11 */
{
return G_LIKELY(req) ? req->user_data : NULL;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

224
src/radio_request_group.c Normal file
View File

@@ -0,0 +1,224 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "radio_base.h"
#include "radio_client.h"
#include "radio_request_group_p.h"
#include "radio_request_p.h"
#include "radio_log.h"
#include <gutil_macros.h>
typedef struct radio_request_group_object {
RadioRequestGroup pub;
GHashTable* requests;
gint refcount;
} RadioRequestGroupObject;
static inline RadioRequestGroupObject*
radio_request_group_cast(RadioRequestGroup* group)
{ return group ? G_CAST(group, RadioRequestGroupObject, pub) : NULL; }
/*==========================================================================*
* Implementation
*==========================================================================*/
void
radio_request_group_unlink_func(
gpointer req)
{
((RadioRequest*)req)->group = NULL;
}
static
void
radio_request_group_free(
RadioRequestGroupObject* self)
{
RadioRequestGroup* group = &self->pub;
radio_base_unblock(RADIO_BASE(group->client), group);
g_hash_table_destroy(self->requests);
radio_client_unref(group->client);
gutil_slice_free(self);
}
/*==========================================================================*
* Internal API
*==========================================================================*/
void
radio_request_group_add(
RadioRequestGroup* group,
RadioRequest* req)
{
RadioRequestGroupObject* self = radio_request_group_cast(group);
/* Request is never NULL but the group may be */
if (self) {
g_hash_table_insert(self->requests, req, req);
req->group = group;
}
}
void
radio_request_group_remove(
RadioRequestGroup* group,
RadioRequest* req)
{
RadioRequestGroupObject* self = radio_request_group_cast(group);
/* Request is never NULL but the group may be */
if (self) {
g_hash_table_remove(self->requests, req);
}
}
/*==========================================================================*
* API
*==========================================================================*/
RadioRequestGroup*
radio_request_group_new(
RadioClient* client)
{
if (G_LIKELY(client)) {
RadioRequestGroupObject* self = g_slice_new0(RadioRequestGroupObject);
RadioRequestGroup* group = &self->pub;
group->client = radio_client_ref(client);
self->requests = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, radio_request_group_unlink_func);
g_atomic_int_set(&self->refcount, 1);
return group;
}
return NULL;
}
RadioRequestGroup*
radio_request_group_ref(
RadioRequestGroup* group)
{
RadioRequestGroupObject* self = radio_request_group_cast(group);
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return group;
}
void
radio_request_group_unref(
RadioRequestGroup* group)
{
RadioRequestGroupObject* self = radio_request_group_cast(group);
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
radio_request_group_free(self);
}
}
}
void
radio_request_group_cancel(
RadioRequestGroup* group)
{
RadioRequestGroupObject* self = radio_request_group_cast(group);
if (G_LIKELY(self)) {
GHashTableIter it;
gpointer value;
GSList* list = NULL;
GSList* l;
/*
* Move requests to the list and temporarily reference them
* before invoking any callbacks.
*/
g_hash_table_iter_init(&it, self->requests);
while (g_hash_table_iter_next(&it, NULL, &value)) {
list = g_slist_prepend(list, radio_request_ref(value));
g_hash_table_iter_remove(&it);
}
/*
* Actually cancel the requests. This invokes completion callbacks.
* The group is already empty at this point.
*/
for (l = list; l; l = l->next) {
radio_request_cancel(l->data);
}
/* Release the temporary references */
g_slist_free_full(list, radio_request_unref_func);
}
}
RADIO_BLOCK
radio_request_group_block_status(
RadioRequestGroup* group)
{
return group ? radio_base_block_status(RADIO_BASE(group->client), group) :
RADIO_BLOCK_NONE;
}
RADIO_BLOCK
radio_request_group_block(
RadioRequestGroup* group)
{
return group ? radio_base_block(RADIO_BASE(group->client), group) :
RADIO_BLOCK_NONE;
}
void
radio_request_group_unblock(
RadioRequestGroup* group)
{
if (group) {
radio_base_unblock(RADIO_BASE(group->client), group);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_REQUEST_GROUP_PRIVATE_H
#define RADIO_REQUEST_GROUP_PRIVATE_H
#include "radio_types_p.h"
#include <radio_request_group.h>
void
radio_request_group_add(
RadioRequestGroup* group,
RadioRequest* req)
RADIO_INTERNAL;
void
radio_request_group_remove(
RadioRequestGroup* group,
RadioRequest* req)
RADIO_INTERNAL;
#endif /* RADIO_REQUEST_GROUP_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

162
src/radio_request_p.h Normal file
View File

@@ -0,0 +1,162 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_REQUEST_PRIVATE_H
#define RADIO_REQUEST_PRIVATE_H
#include "radio_types_p.h"
#include "radio_request.h"
/*
* Request lifecycle
* =================
*
* +=====+
* | NEW | ----------------------[cancel]------------+
* +=====+ |
* | |
* [submit] |
* | |
* | |
* +----> +---------------+ |
* | | | |
* | | (blocked) |
* | (unblocked) | |
* | | v v
* | | +========+ +===========+
* (retry) | | QUEUED | ----[cancel]----> | CANCELLED |
* | | +========+ +===========+
* | | | ^
* | | (unblocked) |
* | | | |
* | | +----------+ |
* | | | |
* | v v |
* | +-------------+ |
* | | submit | +========+ |
* | | request | ---(error)---> | FAILED | |
* | | transaction | +========+ |
* | +-------------+ ^ |
* | | | |
* | (ok) +---(error)---------+ |
* | | / |
* | v / |
* | +=========+ +=========+ |
* +--- | PENDING | ---(timeout)---> | TIMEOUT | |
* +=========+ +=========+ |
* | \ |
* | +----------------[cancel]------------+
* (response)
* |
* v
* +======+
* | DONE |
* +======+
*
* Timeout starts ticking when request enters the PENDING state.
* The library maintains an internal reference to the request in
* QUEUED and PENDING states.
*/
typedef enum radio_request_state {
RADIO_REQUEST_STATE_INVALID,
RADIO_REQUEST_STATE_NEW,
RADIO_REQUEST_STATE_QUEUED,
RADIO_REQUEST_STATE_PENDING,
/*
* Reorder states carefully or better don't reorder at all.
* States >= RADIO_REQUEST_STATE_FAILED are assumed to be
* terminal states in the state machine.
*/
RADIO_REQUEST_STATE_FAILED,
RADIO_REQUEST_STATE_CANCELLED,
RADIO_REQUEST_STATE_TIMEOUT,
RADIO_REQUEST_STATE_DONE
} RADIO_REQUEST_STATE;
typedef
void
(*RadioRequestGenericCompleteFunc)(
RadioRequest* req,
RADIO_TX_STATUS status,
guint32 resp,
RADIO_ERROR error,
const GBinderReader* args,
gpointer user_data);
struct radio_request {
RADIO_REQUEST_STATE state;
guint32 code;
GBinderLocalRequest* args;
RadioRequestGenericCompleteFunc complete;
RadioRequestRetryFunc retry;
void* user_data;
guint32 serial; /* Immutable, generated at creation time */
guint32 serial2; /* Mutable, used by the last transaction */
int max_retries; /* Negative = retry indefinitely */
int retry_count; /* Number of times we have already retried */
guint retry_delay_ms; /* Delay before each retry, in milliseconds */
guint timeout_ms; /* Timeout, in milliseconds (0 = default) */
gint64 deadline; /* Monotonic time, in microseconds */
gint64 scheduled; /* Monotonic time, in microseconds */
gulong tx_id; /* Id of the request transaction */
gboolean blocking; /* TRUE if this request blocks all others */
gboolean acked;
RadioBase* object; /* Not a reference */
RadioRequestGroup* group; /* Not a reference */
RadioRequest* queue_next;
};
void
radio_request_unref_func(
gpointer req)
RADIO_INTERNAL;
void
radio_request_update_serial(
RadioRequest* req,
guint32 serial)
RADIO_INTERNAL;
#endif /* RADIO_REQUEST_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

75
src/radio_types_p.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_TYPES_PRIVATE_H
#define RADIO_TYPES_PRIVATE_H
#include <radio_types.h>
typedef struct radio_base RadioBase;
#define RADIO_INTERNAL G_GNUC_INTERNAL
/* Miliseconds to microseconds */
#define MICROSEC(ms) (((gint64)(ms)) * 1000)
/* Preprocessor magic related to observers */
G_STATIC_ASSERT(RADIO_OBSERVER_PRIORITY_LOWEST == 0);
G_STATIC_ASSERT(RADIO_OBSERVER_PRIORITY_HIGHEST == 7);
#define FOREACH_OBSERVER_PRIORITY(p) p(0) p(1) p(2) p(3) p(4) p(5) p(6) p(7)
#define RADIO_OBSERVER_PRIORITY_INDEX(p) ((p) - RADIO_OBSERVER_PRIORITY_LOWEST)
#define RADIO_OBSERVER_PRIORITY_COUNT \
(RADIO_OBSERVER_PRIORITY_INDEX(RADIO_OBSERVER_PRIORITY_HIGHEST) + 1)
/*
* A special assert fatal in debug build and non-fatal in release.
* Marks truely unavoidable conditions.
*/
#ifdef DEBUG
# define DEBUG_ASSERT(expr) g_assert(expr)
#else
# define DEBUG_ASSERT(expr)
#endif
#endif /* RADIO_TYPES_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -34,11 +34,24 @@
* any official policies, either expressed or implied.
*/
#include "radio_util.h"
#include "radio_util_p.h"
#include "radio_log.h"
GLOG_MODULE_DEFINE("gbinder-radio");
guint
radio_observer_priority_index(
RADIO_OBSERVER_PRIORITY priority)
{
if (priority < RADIO_OBSERVER_PRIORITY_LOWEST) {
return 0;
} else if (priority > RADIO_OBSERVER_PRIORITY_HIGHEST) {
return RADIO_OBSERVER_PRIORITY_COUNT - 1;
} else {
return priority - RADIO_OBSERVER_PRIORITY_LOWEST;
}
}
const char*
radio_req_name(
RADIO_REQ req)
@@ -49,7 +62,17 @@ radio_req_name(
#define RADIO_REQ_(req,resp,Name,NAME) \
case RADIO_REQ_##NAME: return #Name;
RADIO_CALL_1_0(RADIO_REQ_)
RADIO_CALL_1_1(RADIO_REQ_)
RADIO_CALL_1_2(RADIO_REQ_)
RADIO_CALL_1_3(RADIO_REQ_)
RADIO_CALL_1_4(RADIO_REQ_)
#undef RADIO_REQ_
case RADIO_REQ_START_NETWORK_SCAN_1_2: return "startNetworkScan_1_2";
case RADIO_REQ_SET_INDICATION_FILTER_1_2: return "setIndicationFilter_1_2";
case RADIO_REQ_SETUP_DATA_CALL_1_2: return "setupDataCall_1_2";
case RADIO_REQ_DEACTIVATE_DATA_CALL_1_2: return "deactivateDataCall_1_2";
case RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4: return "setInitialAttachApn_1_4";
case RADIO_REQ_SET_DATA_PROFILE_1_4: return "setDataProfile_1_4";
case RADIO_REQ_ANY:
break;
}
@@ -65,7 +88,31 @@ radio_resp_name(
#define RADIO_RESP_(req,resp,Name,NAME) \
case RADIO_RESP_##NAME: return #Name "Response";
RADIO_CALL_1_0(RADIO_RESP_)
RADIO_CALL_1_1(RADIO_RESP_)
RADIO_CALL_1_2(RADIO_RESP_)
RADIO_CALL_1_3(RADIO_RESP_)
RADIO_CALL_1_4(RADIO_RESP_)
#undef RADIO_RESP_
case RADIO_RESP_GET_CELL_INFO_LIST_1_2:
return "getCellInfoListResponse_1_2";
case RADIO_RESP_GET_ICC_CARD_STATUS_1_2:
return "getIccCardStatusResponse_1_2";
case RADIO_RESP_GET_CURRENT_CALLS_1_2:
return "getCurrentCallsResponse_1_2";
case RADIO_RESP_GET_SIGNAL_STRENGTH_1_2:
return "getSignalStrengthResponse_1_2";
case RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2:
return "getVoiceRegistrationStateResponse_1_2";
case RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_2:
return "getDataRegistrationStateResponse_1_2";
case RADIO_RESP_GET_CELL_INFO_LIST_RESPONSE_1_4:
return "getCellInfoListResponse_1_4";
case RADIO_RESP_GET_DATA_REGISTRATION_STATE_RESPONSE_1_4:
return "getDataRegistrationStateResponse_1_4";
case RADIO_RESP_GET_ICC_CARD_STATUS_RESPONSE_1_4:
return "getIccCardStatusResponse_1_4";
case RADIO_RESP_GET_DATA_CALL_LIST_RESPONSE_1_4:
return "getDataCallListResponse_1_4";
case RADIO_RESP_ANY:
break;
}
@@ -80,6 +127,9 @@ radio_ind_name(
#define RADIO_IND_(code,Name,NAME) \
case RADIO_IND_##NAME: return #Name;
RADIO_EVENT_1_0(RADIO_IND_)
RADIO_EVENT_1_1(RADIO_IND_)
RADIO_EVENT_1_2(RADIO_IND_)
RADIO_EVENT_1_4(RADIO_IND_)
#undef RADIO_IND_
case RADIO_IND_ANY:
break;
@@ -87,6 +137,17 @@ radio_ind_name(
return NULL;
}
/**
* This function no longer makes as much sense as it did in IRadio 1.0 times.
* Later it turned out that that same call may produce different responses
* under different circumstances. For example, getIccCardStatus call may
* cause getIccCardStatusResponse or getIccCardStatusResponse_1_2 to be
* sent back, depending on which interfaces are supported by the caller.
* There's no longer one-to-one match between requests and responses,
* that would be too easy and straightforward for Google designers :)
*
* Use this function carefully or better don't use it at all.
*/
RADIO_RESP
radio_req_resp(
RADIO_REQ req)
@@ -95,10 +156,235 @@ radio_req_resp(
#define RADIO_REQ_(req,resp,Name,NAME) \
case RADIO_REQ_##NAME: return RADIO_RESP_##NAME;
RADIO_CALL_1_0(RADIO_REQ_)
RADIO_CALL_1_1(RADIO_REQ_)
RADIO_CALL_1_2(RADIO_REQ_)
RADIO_CALL_1_3(RADIO_REQ_)
RADIO_CALL_1_4(RADIO_REQ_)
#undef RADIO_REQ_
default:
return RADIO_RESP_NONE;
case RADIO_REQ_SETUP_DATA_CALL_1_2:
return RADIO_RESP_SETUP_DATA_CALL;
case RADIO_REQ_DEACTIVATE_DATA_CALL_1_2:
return RADIO_RESP_DEACTIVATE_DATA_CALL;
case RADIO_REQ_START_NETWORK_SCAN_1_2:
return RADIO_RESP_START_NETWORK_SCAN;
case RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4:
return RADIO_RESP_SET_INITIAL_ATTACH_APN;
case RADIO_REQ_SET_DATA_PROFILE_1_4:
return RADIO_RESP_SET_DATA_PROFILE;
case RADIO_REQ_SET_INDICATION_FILTER_1_2:
return RADIO_RESP_SET_INDICATION_FILTER;
/*
* All these still need to be listed here to ensure a compilation
* warnings when something gets added to RADIO_REQ enum.
*/
case RADIO_REQ_SET_RESPONSE_FUNCTIONS:
case RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT:
case RADIO_REQ_ANY:
break;
}
return RADIO_RESP_NONE;
}
/**
* And this is a version of radio_req_resp which takes IRadio interface
* version into account. This one is OK to use.
*/
RADIO_RESP
radio_req_resp2(
RADIO_REQ req,
RADIO_INTERFACE iface) /* Since 1.4.5 */
{
switch (req) {
/*
* Requests expecting a response from a previous version of the
* interface.
*/
case RADIO_REQ_SETUP_DATA_CALL_1_2:
return RADIO_RESP_SETUP_DATA_CALL;
case RADIO_REQ_DEACTIVATE_DATA_CALL_1_2:
return RADIO_RESP_DEACTIVATE_DATA_CALL;
case RADIO_REQ_START_NETWORK_SCAN_1_2:
return RADIO_RESP_START_NETWORK_SCAN;
case RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4:
return RADIO_RESP_SET_INITIAL_ATTACH_APN;
case RADIO_REQ_SET_DATA_PROFILE_1_4:
return RADIO_RESP_SET_DATA_PROFILE;
case RADIO_REQ_SET_INDICATION_FILTER_1_2:
/* case RADIO_REQ_SET_INDICATION_FILTER_1_5: */
return RADIO_RESP_SET_INDICATION_FILTER;
/*
* Requests which may receive a response from a higher version of
* the interface.
*/
/*
* getIccCardStatus
* getIccCardStatusResponse
* getIccCardStatusResponse_1_2
* getIccCardStatusResponse_1_4
* getIccCardStatusResponse_1_5
* ...
*/
case RADIO_REQ_GET_ICC_CARD_STATUS:
switch (iface) {
case RADIO_INTERFACE_1_0:
case RADIO_INTERFACE_1_1:
return RADIO_RESP_GET_ICC_CARD_STATUS;
case RADIO_INTERFACE_1_2:
case RADIO_INTERFACE_1_3:
return RADIO_RESP_GET_ICC_CARD_STATUS_1_2;
case RADIO_INTERFACE_1_4:
return RADIO_RESP_GET_ICC_CARD_STATUS_1_4;
/*
case RADIO_INTERFACE_1_5:
return RADIO_RESP_GET_ICC_CARD_STATUS_1_5;
*/
case RADIO_INTERFACE_NONE:
case RADIO_INTERFACE_COUNT:
break;
}
return RADIO_RESP_NONE;
/*
* getCellInfoList
* getCellInfoListResponse
* getCellInfoListResponse_1_2
* getCellInfoListResponse_1_4
* getCellInfoListResponse_1_5 <= the last one
* getCellInfoList_1_6
*/
case RADIO_REQ_GET_CELL_INFO_LIST:
switch (iface) {
case RADIO_INTERFACE_1_0:
case RADIO_INTERFACE_1_1:
return RADIO_RESP_GET_CELL_INFO_LIST;
case RADIO_INTERFACE_1_2:
case RADIO_INTERFACE_1_3:
return RADIO_RESP_GET_CELL_INFO_LIST_1_2;
case RADIO_INTERFACE_1_4:
return RADIO_RESP_GET_CELL_INFO_LIST_1_4;
/*
default:
return RADIO_RESP_GET_CELL_INFO_LIST_1_5;
*/
case RADIO_INTERFACE_NONE:
case RADIO_INTERFACE_COUNT:
break;
}
return RADIO_RESP_NONE;
/*
* getCurrentCalls
* getCurrentCallsResponse
* getCurrentCallsResponse_1_2 <= the last one
* getCurrentCalls_1_6
*/
case RADIO_REQ_GET_CURRENT_CALLS:
switch (iface) {
case RADIO_INTERFACE_1_0:
case RADIO_INTERFACE_1_1:
return RADIO_RESP_GET_CURRENT_CALLS;
default:
return RADIO_RESP_GET_CURRENT_CALLS_1_2;
case RADIO_INTERFACE_NONE:
break;
}
return RADIO_RESP_NONE;
/*
* getSignalStrength
* getSignalStrengthResponse
* getSignalStrengthResponse_1_2 <= the last one
* getSignalStrength_1_4
*/
case RADIO_REQ_GET_SIGNAL_STRENGTH:
switch (iface) {
case RADIO_INTERFACE_1_0:
case RADIO_INTERFACE_1_1:
return RADIO_RESP_GET_SIGNAL_STRENGTH;
default:
return RADIO_RESP_GET_SIGNAL_STRENGTH_1_2;
case RADIO_INTERFACE_NONE:
break;
}
return RADIO_RESP_NONE;
/*
* getVoiceRegistrationState
* getVoiceRegistrationStateResponse
* getVoiceRegistrationStateResponse_1_2 <= the last one
* getVoiceRegistrationState_1_5
*/
case RADIO_REQ_GET_VOICE_REGISTRATION_STATE:
switch (iface) {
case RADIO_INTERFACE_1_0:
case RADIO_INTERFACE_1_1:
return RADIO_RESP_GET_VOICE_REGISTRATION_STATE;
default:
return RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2;
case RADIO_INTERFACE_NONE:
break;
}
return RADIO_RESP_NONE;
/*
* getDataRegistrationState
* getDataRegistrationStateResponse
* getDataRegistrationStateResponse_1_2
* getDataRegistrationStateResponse_1_4 <= the last one
* getDataRegistrationState_1_5
*/
case RADIO_REQ_GET_DATA_REGISTRATION_STATE:
switch (iface) {
case RADIO_INTERFACE_1_0:
case RADIO_INTERFACE_1_1:
return RADIO_RESP_GET_DATA_REGISTRATION_STATE;
case RADIO_INTERFACE_1_2:
case RADIO_INTERFACE_1_3:
return RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_2;
default:
return RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_4;
case RADIO_INTERFACE_NONE:
break;
}
return RADIO_RESP_NONE;
/*
* getDataCallList
* getDataCallListResponse
* getDataCallListResponse_1_4
* getDataCallListResponse_1_5 <= the last one
* getDataCallList_1_6
*/
case RADIO_REQ_GET_DATA_CALL_LIST:
switch (iface) {
case RADIO_INTERFACE_1_0:
case RADIO_INTERFACE_1_1:
case RADIO_INTERFACE_1_2:
case RADIO_INTERFACE_1_3:
return RADIO_RESP_GET_DATA_CALL_LIST;
case RADIO_INTERFACE_1_4:
return RADIO_RESP_GET_DATA_CALL_LIST_1_4;
/*
default:
return RADIO_RESP_GET_DATA_CALL_LIST_1_5;
*/
case RADIO_INTERFACE_NONE:
case RADIO_INTERFACE_COUNT:
break;
}
return RADIO_RESP_NONE;
default:
break;
}
/* Fallback */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
return radio_req_resp(req);
G_GNUC_END_IGNORE_DEPRECATIONS
}
/*

56
src/radio_util_p.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#ifndef RADIO_UTIL_PRIVATE_H
#define RADIO_UTIL_PRIVATE_H
#include "radio_types_p.h"
#include "radio_util.h"
guint
radio_observer_priority_index(
RADIO_OBSERVER_PRIORITY priority)
RADIO_INTERNAL;
#endif /* RADIO_UTIL_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

15
unit/Makefile Normal file
View File

@@ -0,0 +1,15 @@
# -*- Mode: makefile-gmake -*-
.PHONY: clean all
all:
%:
@$(MAKE) -C unit_client $*
@$(MAKE) -C unit_config $*
@$(MAKE) -C unit_instance $*
@$(MAKE) -C unit_registry $*
@$(MAKE) -C unit_util $*
clean: unitclean
rm -f coverage/*.gcov
rm -fr coverage/report

216
unit/common/Makefile Normal file
View File

@@ -0,0 +1,216 @@
# -*- Mode: makefile-gmake -*-
.PHONY: clean cleaner unitclean all debug release coverage valgrind
.PHONY: debug_lib release_lib coverage_lib
.PHONY: test test_banner
#
# Real test makefile defines EXE (and possibly SRC) and includes this one.
#
ifndef EXE
${error EXE not defined}
endif
SRC ?= $(EXE).c
COMMON_SRC ?= \
test_gbinder_client.c \
test_gbinder_local_object.c \
test_gbinder_local_request.c \
test_gbinder_local_reply.c \
test_gbinder_reader_writer.c \
test_gbinder_remote_object.c \
test_gbinder_remote_request.c \
test_gbinder_remote_reply.c \
test_gbinder_servicemanager.c \
test_main.c
#
# Required packages
#
LINK_PKGS += libglibutil glib-2.0 gobject-2.0
PKGS += $(LINK_PKGS) libgbinder
#
# Default target
#
all: debug release
#
# Directories
#
SRC_DIR = .
LIB_DIR = ../..
COMMON_DIR = ../common
BUILD_DIR = build
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
COMMON_BUILD_DIR = $(COMMON_DIR)/build
COMMON_DEBUG_BUILD_DIR = $(COMMON_BUILD_DIR)/debug
COMMON_RELEASE_BUILD_DIR = $(COMMON_BUILD_DIR)/release
COMMON_COVERAGE_BUILD_DIR = $(COMMON_BUILD_DIR)/coverage
#
# Tools and flags
#
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS += -Wall -Wno-deprecated-declarations
INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) \
-MMD -MP $(shell pkg-config --cflags $(PKGS))
FULL_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS)
LIBS = $(shell pkg-config --libs $(LINK_PKGS)) -lpthread
QUIET_MAKE = make --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =
COVERAGE_FLAGS = -g
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
COVERAGE_LDFLAGS = $(FULL_LDFLAGS) $(COVERAGE_FLAGS) --coverage
DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
DEBUG_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_lib)
RELEASE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_lib)
COVERAGE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_coverage_lib)
DEBUG_LIB = $(LIB_DIR)/$(DEBUG_LIB_FILE)
RELEASE_LIB = $(LIB_DIR)/$(RELEASE_LIB_FILE)
COVERAGE_LIB = $(LIB_DIR)/$(COVERAGE_LIB_FILE)
DEBUG_LIBS = $(DEBUG_LIB) $(LIBS)
RELEASE_LIBS = $(RELEASE_LIB) $(LIBS)
COVERAGE_LIBS = $(COVERAGE_LIB) $(LIBS)
#
# Files
#
TEST_DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
TEST_RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
TEST_COVERAGE_OBJS = $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
COMMON_DEBUG_OBJS = $(COMMON_SRC:%.c=$(COMMON_DEBUG_BUILD_DIR)/%.o)
COMMON_RELEASE_OBJS = $(COMMON_SRC:%.c=$(COMMON_RELEASE_BUILD_DIR)/%.o)
COMMON_COVERAGE_OBJS = $(COMMON_SRC:%.c=$(COMMON_COVERAGE_BUILD_DIR)/%.o)
DEBUG_OBJS = $(COMMON_DEBUG_OBJS) $(TEST_DEBUG_OBJS)
RELEASE_OBJS = $(COMMON_RELEASE_OBJS) $(TEST_RELEASE_OBJS)
COVERAGE_OBJS = $(COMMON_COVERAGE_OBJS) $(TEST_COVERAGE_OBJS)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(DEBUG_LIB): | debug_lib
$(RELEASE_LIB): | release_lib
$(COVERAGE_LIB): | coverage_lib
$(TEST_DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(TEST_RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
$(TEST_COVERAGE_OBJS): | $(COVERAGE_BUILD_DIR)
$(COMMON_DEBUG_OBJS): | $(COMMON_DEBUG_BUILD_DIR)
$(COMMON_RELEASE_OBJS): | $(COMMON_RELEASE_BUILD_DIR)
$(COMMON_COVERAGE_OBJS): | $(COMMON_COVERAGE_BUILD_DIR)
#
# Rules
#
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
COVERAGE_EXE = $(COVERAGE_BUILD_DIR)/$(EXE)
debug: debug_lib $(DEBUG_EXE)
release: release_lib $(RELEASE_EXE)
coverage: coverage_lib $(COVERAGE_EXE)
unitclean:
rm -f *~
rm -fr $(BUILD_DIR) $(COMMON_BUILD_DIR)
clean: unitclean
cleaner: unitclean
@make -C $(LIB_DIR) clean
test_banner:
@echo "===========" $(EXE) "=========== "
test: test_banner debug
@$(DEBUG_EXE)
valgrind: test_banner debug
@G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no $(DEBUG_EXE)
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(COVERAGE_BUILD_DIR):
mkdir -p $@
$(COMMON_DEBUG_BUILD_DIR):
mkdir -p $@
$(COMMON_RELEASE_BUILD_DIR):
mkdir -p $@
$(COMMON_COVERAGE_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 $@
$(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(COMMON_DEBUG_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(COMMON_RELEASE_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(COMMON_COVERAGE_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_EXE): $(DEBUG_LIB) $(DEBUG_OBJS)
$(LD) $(DEBUG_LDFLAGS) $(DEBUG_OBJS) $(DEBUG_LIBS) -o $@
$(RELEASE_EXE): $(RELEASE_LIB) $(RELEASE_OBJS)
$(LD) $(RELEASE_LDFLAGS) $(RELEASE_OBJS) $(RELEASE_LIBS) -o $@
$(COVERAGE_EXE): $(COVERAG_LIB) $(COVERAGE_OBJS)
$(LD) $(COVERAGE_LDFLAGS) $(COVERAGE_OBJS) $(COVERAGE_LIBS) -o $@
debug_lib:
$(MAKE) -C $(LIB_DIR) $@
release_lib:
$(MAKE) -C $(LIB_DIR) $@
coverage_lib:
$(MAKE) -C $(LIB_DIR) $@

109
unit/common/test_common.h Normal file
View File

@@ -0,0 +1,109 @@
/*
* 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:
*
* 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 TEST_COMMON_H
#define TEST_COMMON_H
#include <radio_types.h>
#define TEST_FLAG_DEBUG (0x01)
typedef struct test_opt {
int flags;
} TestOpt;
/* Should be invoked after g_test_init */
void
test_init(
TestOpt* opt,
int argc,
char* argv[]);
/* Run loop with a timeout */
void
test_run(
const TestOpt* opt,
GMainLoop* loop);
/* Quits the event loop on the next iteration */
void
test_quit_later(
GMainLoop* loop);
/* Quits the event loop after n iterations */
void
test_quit_later_n(
GMainLoop* loop,
guint n);
#define TEST_TIMEOUT_SEC (20)
#define TEST_TIMEOUT_MS (1000*TEST_TIMEOUT_SEC)
/* Helper macros */
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
# define TEST_INT16_BYTES(v) \
(guint8)(v), (guint8)((v) >> 8)
# define TEST_INT32_BYTES(v) \
(guint8)(v), (guint8)((v) >> 8), \
(guint8)((v) >> 16), (guint8)((v) >> 24)
# define TEST_INT64_BYTES(v) \
(guint8)(v), (guint8)((v) >> 8), \
(guint8)((v) >> 16), (guint8)((v) >> 24), \
(guint8)(((guint64)(v)) >> 32), (guint8)(((guint64)(v)) >> 40), \
(guint8)(((guint64)(v)) >> 48), (guint8)(((guint64)(v)) >> 56)
#elif G_BYTE_ORDER == G_BIG_ENDIAN
# define TEST_INT16_BYTES(v) \
(guint8)((v) >> 8), (guint8)(v)
# define TEST_INT32_BYTES(v) \
(guint8)((v) >> 24), (guint8)((v) >> 16), \
(guint8)((v) >> 8), (guint8)(v)
# define TEST_INT64_BYTES(v) \
(guint8)(((guint64)(v)) >> 56), (guint8)(((guint64)(v)) >> 48), \
(guint8)(((guint64)(v)) >> 40), (guint8)(((guint64)(v)) >> 32), \
(guint8)((v) >> 24), (guint8)((v) >> 16), \
(guint8)((v) >> 8), (guint8)(v)
#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
#error unknown ENDIAN type
#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
#define TEST_ARRAY_AND_COUNT(a) a, G_N_ELEMENTS(a)
#define TEST_ARRAY_AND_SIZE(a) a, sizeof(a)
#endif /* TEST_COMMON_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

165
unit/common/test_gbinder.h Normal file
View File

@@ -0,0 +1,165 @@
/*
* 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.
*/
#ifndef TEST_GBINDER_H
#define TEST_GBINDER_H
#include <gbinder.h>
typedef struct test_gbinder_data TestGBinderData;
/* test_gbinder_reader_writer.c */
TestGBinderData*
test_gbinder_data_new(
const char* iface);
TestGBinderData*
test_gbinder_data_ref(
TestGBinderData* data);
void
test_gbinder_data_unref(
TestGBinderData* data);
void
test_gbinder_data_add_int32(
TestGBinderData* data,
guint32 value);
void
test_gbinder_data_add_hidl_struct(
TestGBinderData* data,
const void* buf,
gsize size);
void
test_gbinder_data_init_reader(
TestGBinderData* data,
GBinderReader* reader);
void
test_gbinder_data_init_writer(
TestGBinderData* data,
GBinderWriter* writer);
/* test_gbinder_local_request.c */
GBinderLocalRequest*
test_gbinder_local_request_new(
const char* iface);
const char*
test_gbinder_local_request_interface(
GBinderLocalRequest* local);
TestGBinderData*
test_gbinder_local_request_data(
GBinderLocalRequest* local);
/* test_gbinder_local_reply.c */
GBinderLocalReply*
test_gbinder_local_reply_new(
void);
TestGBinderData*
test_gbinder_local_reply_data(
GBinderLocalReply* reply);
/* test_gbinder_remote_request.c */
GBinderRemoteRequest*
test_gbinder_remote_request_new(
GBinderLocalRequest* req);
/* test_gbinder_remote_reply.c */
GBinderRemoteReply*
test_gbinder_remote_reply_new(
GBinderLocalReply* reply);
/* test_gbinder_local_object.c */
GBinderLocalObject*
test_gbinder_local_object_new(
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data);
GBinderLocalReply*
test_gbinder_local_object_handle_tx(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status);
/* test_gbinder_remote_object.c */
GBinderRemoteObject*
test_gbinder_remote_object_new(
GBinderLocalObject* local);
void
test_gbinder_remote_object_kill(
GBinderRemoteObject* remote);
gboolean
test_gbinder_remote_object_dead(
GBinderRemoteObject* remote);
GBinderLocalObject*
test_gbinder_remote_object_to_local(
GBinderRemoteObject* remote);
/* test_gbinder_client.c */
extern int test_gbinder_client_tx_fail_count;
/* test_gbinder_servicemanager.c */
GBinderRemoteObject*
test_gbinder_servicemanager_new_service(
GBinderServiceManager* manager,
const char* name,
GBinderLocalObject* local);
#endif /* TEST_GBINDER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,402 @@
/*
* 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 the 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
#include <gutil_log.h>
#include <stdlib.h>
typedef struct test_gbinder_client_tx {
GBinderClient* client;
guint32 code;
guint32 flags;
GBinderLocalRequest* req;
GBinderClientReplyFunc reply;
GDestroyNotify destroy;
void* user_data;
} TestGBinderClientTx;
typedef struct test_gbinder_client_iface_range {
char* iface;
GBytes* header;
guint32 last_code;
} TestGBinderClientIfaceRange;
struct gbinder_client {
guint32 refcount;
GBinderRemoteObject* remote;
TestGBinderClientIfaceRange* ranges;
guint nr;
};
int test_gbinder_client_tx_fail_count = 0;
static
void
test_gbinder_client_free(
GBinderClient* self)
{
guint i;
for (i = 0; i < self->nr; i++) {
TestGBinderClientIfaceRange* r = self->ranges + i;
g_bytes_unref(r->header);
g_free(r->iface);
}
g_free(self->ranges);
gbinder_remote_object_unref(self->remote);
g_free(self);
}
static
void
test_gbinder_client_init_range(
TestGBinderClientIfaceRange* r,
const GBinderClientIfaceInfo* info)
{
r->header = g_bytes_new(info->iface, strlen(info->iface));
r->iface = g_strdup(info->iface);
r->last_code = info->last_code;
}
static
int
test_gbinder_client_sort_ranges(
const void* p1,
const void* p2)
{
const TestGBinderClientIfaceRange* r1 = p1;
const TestGBinderClientIfaceRange* r2 = p2;
return (r1->last_code < r2->last_code) ? (-1) :
(r1->last_code > r2->last_code) ? 1 : 0;
}
static
const TestGBinderClientIfaceRange*
test_gbinder_client_find_range(
GBinderClient* self,
guint32 code)
{
guint i;
for (i = 0; i < self->nr; i++) {
const TestGBinderClientIfaceRange* r = self->ranges + i;
if (r->last_code >= code) {
return r;
}
}
return NULL;
}
static
GBinderRemoteReply*
test_gbinder_client_transact(
GBinderClient* self,
guint32 code,
guint32 flags,
GBinderLocalRequest* req,
int* status)
{
GBinderLocalObject* obj = test_gbinder_remote_object_to_local(self->remote);
GBinderRemoteRequest* remote_req = test_gbinder_remote_request_new(req);
GBinderLocalReply* reply = test_gbinder_local_object_handle_tx(obj,
remote_req, code, flags, status);
GBinderRemoteReply* remote_reply = test_gbinder_remote_reply_new(reply);
gbinder_remote_request_unref(remote_req);
gbinder_local_reply_unref(reply);
return remote_reply;
}
static
GBinderRemoteReply*
test_gbinder_client_transact_sync(
GBinderClient* self,
guint32 code,
guint32 flags,
GBinderLocalRequest* req,
int* status)
{
GBinderRemoteReply* reply = NULL;
if (self) {
GBinderRemoteObject* obj = self->remote;
if (!test_gbinder_remote_object_dead(obj)) {
GBinderLocalRequest* tmp = NULL;
if (!req) {
const TestGBinderClientIfaceRange* r =
test_gbinder_client_find_range(self, code);
if (r) {
req = tmp = test_gbinder_local_request_new(r->iface);
}
}
if (req) {
reply = test_gbinder_client_transact(self, code, flags, req,
status);
}
gbinder_local_request_unref(tmp);
} else {
GDEBUG("Refusing to perform transaction with a dead object");
}
}
return reply;
}
static
gboolean
test_gbinder_client_tx_handle(
gpointer data)
{
int status = -1;
TestGBinderClientTx* tx = data;
GBinderRemoteReply* reply = test_gbinder_client_transact
(tx->client, tx->code, tx->flags, tx->req, &status);
if (tx->reply) {
tx->reply(tx->client, reply, status, tx->user_data);
}
gbinder_remote_reply_unref(reply);
return G_SOURCE_REMOVE;
}
static
void
test_gbinder_client_tx_destroy(
gpointer data)
{
TestGBinderClientTx* tx = data;
if (tx->destroy) {
tx->destroy(tx->user_data);
}
gbinder_local_request_unref(tx->req);
gbinder_client_unref(tx->client);
g_free(tx);
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
GBinderClient*
gbinder_client_new2(
GBinderRemoteObject* remote,
const GBinderClientIfaceInfo* ifaces,
gsize count)
{
if (remote) {
GBinderClient* self = g_new0(GBinderClient, 1);
g_atomic_int_set(&self->refcount, 1);
self->remote = gbinder_remote_object_ref(remote);
if (count > 0) {
gsize i;
self->nr = count;
self->ranges = g_new(TestGBinderClientIfaceRange, self->nr);
for (i = 0; i < count; i++) {
test_gbinder_client_init_range(self->ranges + i, ifaces + i);
}
qsort(self->ranges, count, sizeof(TestGBinderClientIfaceRange),
test_gbinder_client_sort_ranges);
} else {
/* No interface info */
self->nr = 1;
self->ranges = g_new0(TestGBinderClientIfaceRange, 1);
self->ranges[0].last_code = UINT_MAX;
}
return self;
}
return NULL;
}
GBinderClient*
gbinder_client_ref(
GBinderClient* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_client_unref(
GBinderClient* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
test_gbinder_client_free(self);
}
}
}
GBytes*
gbinder_client_rpc_header(
GBinderClient* self,
guint32 code)
{
if (self) {
const TestGBinderClientIfaceRange* r =
test_gbinder_client_find_range(self, code);
if (r) {
return r->header;
}
}
return NULL;
}
GBinderLocalRequest*
gbinder_client_new_request2(
GBinderClient* self,
guint32 code)
{
if (self) {
const TestGBinderClientIfaceRange* r =
test_gbinder_client_find_range(self, code);
if (r) {
return test_gbinder_local_request_new(r->iface);
}
}
return NULL;
}
GBinderRemoteReply*
gbinder_client_transact_sync_reply(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
int* status)
{
return test_gbinder_client_transact_sync(self, code, 0, req, status);
}
int
gbinder_client_transact_sync_oneway(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req)
{
int status = -1;
g_assert(!test_gbinder_client_transact_sync(self, code,
GBINDER_TX_FLAG_ONEWAY, req, &status));
return status;
}
gulong
gbinder_client_transact(
GBinderClient* self,
guint32 code,
guint32 flags,
GBinderLocalRequest* req,
GBinderClientReplyFunc reply,
GDestroyNotify destroy,
void* user_data)
{
gulong id = 0;
if (self) {
GBinderRemoteObject* obj = self->remote;
if (!test_gbinder_remote_object_dead(obj)) {
if (test_gbinder_client_tx_fail_count) {
if (test_gbinder_client_tx_fail_count > 0) {
test_gbinder_client_tx_fail_count--;
}
GDEBUG("Simulating transaction failure");
} else {
GBinderLocalRequest* tmp = NULL;
if (!req) {
const TestGBinderClientIfaceRange* r =
test_gbinder_client_find_range(self, code);
if (r) {
req = tmp = test_gbinder_local_request_new(r->iface);
}
}
if (req) {
TestGBinderClientTx* tx = g_new0(TestGBinderClientTx, 1);
tx->client = gbinder_client_ref(self);
tx->code = code;
tx->flags = flags;
tx->req = gbinder_local_request_ref(req);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
id = g_idle_add_full(G_PRIORITY_DEFAULT,
test_gbinder_client_tx_handle, tx,
test_gbinder_client_tx_destroy);
}
gbinder_local_request_unref(tmp);
}
} else {
GDEBUG("Refusing to perform transaction with a dead object");
}
}
return id;
}
void
gbinder_client_cancel(
GBinderClient* self,
gulong id)
{
if (id) {
g_source_remove((guint)id);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,153 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
#include <gutil_strv.h>
struct gbinder_local_object {
guint32 refcount;
char** ifaces;
GBinderLocalTransactFunc txproc;
void* user_data;
};
static const char hidl_base_interface[] = "android.hidl.base@1.0::IBase";
static
void
test_gbinder_local_object_free(
GBinderLocalObject* self)
{
g_strfreev(self->ifaces);
g_free(self);
}
/*==========================================================================*
* Internal API
*==========================================================================*/
GBinderLocalObject*
test_gbinder_local_object_new(
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
{
GBinderLocalObject* self = g_new0(GBinderLocalObject, 1);
guint i = 0, n = gutil_strv_length((char**)ifaces);
gboolean append_base_interface;
if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
append_base_interface = TRUE;
n++;
} else {
append_base_interface = FALSE;
}
self->ifaces = g_new(char*, n + 1);
if (ifaces) {
while (*ifaces) {
self->ifaces[i++] = g_strdup(*ifaces++);
}
}
if (append_base_interface) {
self->ifaces[i++] = g_strdup(hidl_base_interface);
}
self->ifaces[i] = NULL;
self->txproc = txproc;
self->user_data = user_data;
g_atomic_int_set(&self->refcount, 1);
return self;
}
GBinderLocalReply*
test_gbinder_local_object_handle_tx(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
return (self && self->txproc) ?
self->txproc(self, req, code, flags, status, self->user_data) :
NULL;
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
GBinderLocalObject*
gbinder_local_object_ref(
GBinderLocalObject* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_local_object_unref(
GBinderLocalObject* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
test_gbinder_local_object_free(self);
}
}
}
void
gbinder_local_object_drop(
GBinderLocalObject* self)
{
if (self) {
self->txproc = NULL;
self->user_data = NULL;
gbinder_local_object_unref(self);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
struct gbinder_local_reply {
guint32 refcount;
TestGBinderData* data;
char* iface;
};
static
void
test_gbinder_local_reply_free(
GBinderLocalReply* self)
{
test_gbinder_data_unref(self->data);
g_free(self->iface);
g_free(self);
}
/*==========================================================================*
* Internal API
*==========================================================================*/
GBinderLocalReply*
test_gbinder_local_reply_new(
void)
{
GBinderLocalReply* self = g_new0(GBinderLocalReply, 1);
g_atomic_int_set(&self->refcount, 1);
self->data = test_gbinder_data_new(NULL);
return self;
}
TestGBinderData*
test_gbinder_local_reply_data(
GBinderLocalReply* self)
{
return self ? self->data : NULL;
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
GBinderLocalReply*
gbinder_local_reply_ref(
GBinderLocalReply* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_local_reply_unref(
GBinderLocalReply* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
test_gbinder_local_reply_free(self);
}
}
}
void
gbinder_local_reply_init_writer(
GBinderLocalReply* self,
GBinderWriter* writer)
{
test_gbinder_data_init_writer(self->data, writer);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
struct gbinder_local_request {
guint32 refcount;
TestGBinderData* data;
char* iface;
};
static
void
test_gbinder_local_request_free(
GBinderLocalRequest* self)
{
test_gbinder_data_unref(self->data);
g_free(self->iface);
g_free(self);
}
/*==========================================================================*
* Internal API
*==========================================================================*/
GBinderLocalRequest*
test_gbinder_local_request_new(
const char* iface)
{
GBinderLocalRequest* self = g_new0(GBinderLocalRequest, 1);
g_assert(iface);
g_atomic_int_set(&self->refcount, 1);
self->data = test_gbinder_data_new(iface);
self->iface = g_strdup(iface);
return self;
}
const char*
test_gbinder_local_request_interface(
GBinderLocalRequest* self)
{
return self ? self->iface : NULL;
}
TestGBinderData*
test_gbinder_local_request_data(
GBinderLocalRequest* self)
{
return self ? self->data : NULL;
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
GBinderLocalRequest*
gbinder_local_request_ref(
GBinderLocalRequest* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_local_request_unref(
GBinderLocalRequest* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
test_gbinder_local_request_free(self);
}
}
}
void
gbinder_local_request_init_writer(
GBinderLocalRequest* self,
GBinderWriter* writer)
{
test_gbinder_data_init_writer(self->data, writer);
}
GBinderLocalRequest*
gbinder_local_request_append_int32(
GBinderLocalRequest* self,
guint32 value)
{
if (self) {
GBinderWriter writer;
test_gbinder_data_init_writer(self->data, &writer);
gbinder_writer_append_int32(&writer, value);
}
return self;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,488 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
#include <gutil_misc.h>
#include <gutil_idlepool.h>
typedef enum test_gbinder_data_type {
DATA_TYPE_BOOLEAN,
DATA_TYPE_INT32,
DATA_TYPE_BUFFER,
DATA_TYPE_LOCAL_OBJ
} DATA_TYPE;
typedef struct test_gbinder_data_item TestGBinderDataItem;
struct test_gbinder_data_item {
TestGBinderDataItem* next;
DATA_TYPE type;
union {
gboolean b;
gint32 i32;
struct {
void* buf;
gsize size;
} blob;
GBinderLocalObject* obj;
} data;
void (*destroy)(TestGBinderDataItem*);
};
struct test_gbinder_data {
guint32 refcount;
TestGBinderDataItem* items;
GUtilIdlePool* pool;
char* iface;
};
typedef struct test_gbinder_reader {
TestGBinderDataItem* item;
} TestGBinderReader;
typedef struct test_gbinder_writer {
TestGBinderData* data;
} TestGBinderWriter;
static inline TestGBinderReader* test_gbinder_reader_cast(GBinderReader* reader)
{ return (TestGBinderReader*)reader; }
static inline TestGBinderWriter* test_gbinder_writer_cast(GBinderWriter* writer)
{ return (TestGBinderWriter*)writer; }
static
void
test_gbinder_data_item_destroy_local_obj(
TestGBinderDataItem* item)
{
g_assert_cmpint(item->type, == ,DATA_TYPE_LOCAL_OBJ);
gbinder_local_object_unref(item->data.obj);
}
static
void
test_gbinder_data_item_destroy_buffer(
TestGBinderDataItem* item)
{
g_assert_cmpint(item->type, == ,DATA_TYPE_BUFFER);
g_free(item->data.blob.buf);
}
static
TestGBinderDataItem*
test_gbinder_data_item_new(
DATA_TYPE type)
{
TestGBinderDataItem* item = g_new0(TestGBinderDataItem, 1);
item->type = type;
return item;
}
static
void
test_gbinder_data_item_free(
TestGBinderDataItem* item)
{
if (item) {
test_gbinder_data_item_free(item->next);
if (item->destroy) {
item->destroy(item);
}
g_free(item);
}
}
static
void
test_gbinder_data_free(
TestGBinderData* data)
{
test_gbinder_data_item_free(data->items);
gutil_idle_pool_destroy(data->pool);
g_free(data->iface);
g_free(data);
}
static
guint
test_gbinder_data_count_buffers(
TestGBinderData* data)
{
TestGBinderDataItem* item;
guint n;
for (n = 0, item = data->items; item; item = item->next) {
if (item->type == DATA_TYPE_BUFFER) {
n++;
}
}
return n;
}
static
void
test_gbinder_data_append(
TestGBinderData* data,
TestGBinderDataItem* item)
{
TestGBinderDataItem* last = data->items;
if (last) {
while (last->next) {
last = last->next;
}
last->next = item;
} else {
data->items = item;
}
}
static
gsize
test_gbinder_data_item_size(
TestGBinderDataItem* item)
{
switch (item->type) {
case DATA_TYPE_BOOLEAN:
return sizeof(item->data.b);
case DATA_TYPE_INT32:
return sizeof(item->data.i32);
case DATA_TYPE_BUFFER:
return sizeof(item->data.blob);
case DATA_TYPE_LOCAL_OBJ:
return sizeof(item->data.obj);
}
return 0;
}
static
void*
test_gbinder_data_buffer(
TestGBinderData* data,
gsize* out_size)
{
gsize size = 0;
void* ptr = NULL;
if (data) {
TestGBinderDataItem* item;
GByteArray* buf = g_byte_array_new();
if (data->iface) {
gsize header_size = strlen(data->iface);
g_byte_array_append(buf, (void*)data->iface, header_size);
size += header_size;
}
for (item = data->items; item; item = item->next) {
gsize item_size = test_gbinder_data_item_size(item);
g_byte_array_append(buf, (void*)&item->data, item_size);
size += item_size;
}
ptr = g_byte_array_free(buf, FALSE);
}
if (out_size) *out_size = size;
return ptr;
}
static
gsize
test_gbinder_data_size(
TestGBinderData* data)
{
gsize size = 0;
if (data) {
TestGBinderDataItem* item;
if (data->iface) size += strlen(data->iface);
for (item = data->items; item; item = item->next) {
size += test_gbinder_data_item_size(item);
}
}
return size;
}
static
guint32
test_gbinder_date_replace_int32(
TestGBinderData* data,
gsize offset,
guint32 value)
{
if (data) {
gsize size = 0;
TestGBinderDataItem* item;
if (data->iface) size += strlen(data->iface);
for (item = data->items; item; item = item->next) {
if (size == offset) {
guint32 prev;
g_assert_cmpint(item->type, == ,DATA_TYPE_INT32);
prev = item->data.i32;
item->data.i32 = value;
return prev;
}
size += test_gbinder_data_item_size(item);
}
}
return 0;
}
/*==========================================================================*
* Internal API
*==========================================================================*/
TestGBinderData*
test_gbinder_data_new(
const char* iface)
{
TestGBinderData* data = g_new0(TestGBinderData, 1);
g_atomic_int_set(&data->refcount, 1);
data->iface = g_strdup(iface); /* Doubles as a request header */
return data;
}
TestGBinderData*
test_gbinder_data_ref(
TestGBinderData* data)
{
if (data) {
g_assert_cmpint(data->refcount, > ,0);
g_atomic_int_inc(&data->refcount);
}
return data;
}
void
test_gbinder_data_unref(
TestGBinderData* data)
{
if (data) {
g_assert_cmpint(data->refcount, > ,0);
if (g_atomic_int_dec_and_test(&data->refcount)) {
test_gbinder_data_free(data);
}
}
}
void
test_gbinder_data_init_reader(
TestGBinderData* data,
GBinderReader* reader)
{
memset(reader, 0, sizeof(*reader));
if (data) {
test_gbinder_reader_cast(reader)->item = data->items;
}
}
void
test_gbinder_data_init_writer(
TestGBinderData* data,
GBinderWriter* writer)
{
if (writer) {
memset(writer, 0, sizeof(*writer));
if (data) {
test_gbinder_writer_cast(writer)->data = data;
}
}
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
gboolean
gbinder_reader_read_uint32(
GBinderReader* reader,
guint32* value)
{
TestGBinderReader* self = test_gbinder_reader_cast(reader);
TestGBinderDataItem* item = self->item;
if (item && item->type == DATA_TYPE_INT32) {
if (value) {
*value = item->data.i32;
}
self->item = item->next;
return TRUE;
}
return FALSE;
}
gboolean
gbinder_reader_read_int32(
GBinderReader* reader,
gint32* value)
{
return gbinder_reader_read_uint32(reader, (guint32*)value);
}
const void*
gbinder_reader_read_hidl_struct1(
GBinderReader* reader,
gsize size)
{
TestGBinderReader* self = test_gbinder_reader_cast(reader);
TestGBinderDataItem* item = self->item;
if (item && item->type == DATA_TYPE_BUFFER &&
item->data.blob.size == size) {
self->item = item->next;
return item->data.blob.buf;
}
return NULL;
}
GBinderRemoteObject*
gbinder_reader_read_object(
GBinderReader* reader)
{
TestGBinderReader* self = test_gbinder_reader_cast(reader);
TestGBinderDataItem* item = self->item;
if (item && item->type == DATA_TYPE_LOCAL_OBJ) {
self->item = item->next;
return test_gbinder_remote_object_new(item->data.obj);
}
return NULL;
}
const void*
gbinder_writer_get_data(
GBinderWriter* writer,
gsize* size)
{
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
TestGBinderData* data = self->data;
void* buf = test_gbinder_data_buffer(data, size);
if (buf) {
if (!data->pool) {
data->pool = gutil_idle_pool_new();
}
gutil_idle_pool_add(data->pool, buf, g_free);
}
return buf;
}
gsize
gbinder_writer_bytes_written(
GBinderWriter* writer)
{
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
return test_gbinder_data_size(self->data);
}
void
gbinder_writer_append_int32(
GBinderWriter* writer,
guint32 value)
{
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_INT32);
item->data.i32 = value;
test_gbinder_data_append(self->data, item);
}
void
gbinder_writer_overwrite_int32(
GBinderWriter* writer,
gsize offset,
gint32 value)
{
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
test_gbinder_date_replace_int32(self->data, offset, value);
}
void
gbinder_writer_append_bool(
GBinderWriter* writer,
gboolean value)
{
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_BOOLEAN);
item->data.b = value;
test_gbinder_data_append(self->data, item);
}
guint
gbinder_writer_append_buffer_object(
GBinderWriter* writer,
const void* buf,
gsize size)
{
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_BUFFER);
const guint index = test_gbinder_data_count_buffers(self->data);
item->destroy = test_gbinder_data_item_destroy_buffer;
item->data.blob.buf = gutil_memdup(buf, size);
item->data.blob.size = size;
test_gbinder_data_append(self->data, item);
return index;
}
void
gbinder_writer_append_local_object(
GBinderWriter* writer,
GBinderLocalObject* obj)
{
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_LOCAL_OBJ);
item->data.obj = gbinder_local_object_ref(obj);
item->destroy = test_gbinder_data_item_destroy_local_obj;
test_gbinder_data_append(self->data, item);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,180 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
#include <glib-object.h>
struct gbinder_remote_object {
GObject parent;
GBinderLocalObject* local;
gboolean dead;
};
typedef GObjectClass GBinderRemoteObjectClass;
G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT)
#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,
SIGNAL_COUNT
};
#define SIGNAL_DEATH_NAME "death"
static guint remote_object_signals[SIGNAL_COUNT] = { 0 };
static
void
gbinder_remote_object_init(
GBinderRemoteObject* self)
{
}
static
void
gbinder_remote_object_finalize(
GObject* object)
{
GBinderRemoteObject* self = THIS(object);
gbinder_local_object_unref(self->local);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
gbinder_remote_object_class_init(
GBinderRemoteObjectClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = gbinder_remote_object_finalize;
remote_object_signals[SIGNAL_DEATH] =
g_signal_new(SIGNAL_DEATH_NAME, G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*==========================================================================*
* Internal API
*==========================================================================*/
GBinderRemoteObject*
test_gbinder_remote_object_new(
GBinderLocalObject* local)
{
GBinderRemoteObject* self = g_object_new(THIS_TYPE, NULL);
g_assert(local);
self->local = gbinder_local_object_ref(local);
return self;
}
void
test_gbinder_remote_object_kill(
GBinderRemoteObject* self)
{
if (self && !self->dead) {
self->dead = TRUE;
g_signal_emit(self, remote_object_signals[SIGNAL_DEATH], 0);
}
}
gboolean
test_gbinder_remote_object_dead(
GBinderRemoteObject* self)
{
return !self || self->dead;
}
GBinderLocalObject*
test_gbinder_remote_object_to_local(
GBinderRemoteObject* self)
{
return self ? self->local : NULL;
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
GBinderRemoteObject*
gbinder_remote_object_ref(
GBinderRemoteObject* self)
{
if (self) {
g_object_ref(THIS(self));
}
return self;
}
void
gbinder_remote_object_unref(
GBinderRemoteObject* self)
{
if (self) {
g_object_unref(THIS(self));
}
}
gulong
gbinder_remote_object_add_death_handler(
GBinderRemoteObject* self,
GBinderRemoteObjectNotifyFunc fn,
void* data)
{
return (self && fn) ? g_signal_connect(self, SIGNAL_DEATH_NAME,
G_CALLBACK(fn), data) : 0;
}
void
gbinder_remote_object_remove_handler(
GBinderRemoteObject* self,
gulong id)
{
if (self && id) {
g_signal_handler_disconnect(self, id);
}
}
/*
* Remote Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
struct gbinder_remote_reply {
guint32 refcount;
TestGBinderData* data;
};
static
void
test_gbinder_remote_reply_free(
GBinderRemoteReply* self)
{
test_gbinder_data_unref(self->data);
g_free(self);
}
/*==========================================================================*
* Internal API
*==========================================================================*/
GBinderRemoteReply*
test_gbinder_remote_reply_new(
GBinderLocalReply* reply)
{
if (reply) {
GBinderRemoteReply* self = g_new0(GBinderRemoteReply, 1);
TestGBinderData* data = test_gbinder_local_reply_data(reply);
g_atomic_int_set(&self->refcount, 1);
self->data = test_gbinder_data_ref(data);
return self;
} else {
return NULL;
}
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
GBinderRemoteReply*
gbinder_remote_reply_ref(
GBinderRemoteReply* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_remote_reply_unref(
GBinderRemoteReply* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
test_gbinder_remote_reply_free(self);
}
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
struct gbinder_remote_request {
guint32 refcount;
TestGBinderData* data;
char* iface;
};
static
void
test_gbinder_remote_request_free(
GBinderRemoteRequest* self)
{
test_gbinder_data_unref(self->data);
g_free(self->iface);
g_free(self);
}
/*==========================================================================*
* Internal API
*==========================================================================*/
GBinderRemoteRequest*
test_gbinder_remote_request_new(
GBinderLocalRequest* req)
{
GBinderRemoteRequest* self = g_new0(GBinderRemoteRequest, 1);
g_atomic_int_set(&self->refcount, 1);
self->data = test_gbinder_data_ref(test_gbinder_local_request_data(req));
self->iface = g_strdup(test_gbinder_local_request_interface(req));
return self;
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
GBinderRemoteRequest*
gbinder_remote_request_ref(
GBinderRemoteRequest* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_remote_request_unref(
GBinderRemoteRequest* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
test_gbinder_remote_request_free(self);
}
}
}
const char*
gbinder_remote_request_interface(
GBinderRemoteRequest* self)
{
return self ? self->iface : NULL;
}
void
gbinder_remote_request_init_reader(
GBinderRemoteRequest* self,
GBinderReader* reader)
{
test_gbinder_data_init_reader(self->data, reader);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,180 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_gbinder.h"
#include <gutil_idlepool.h>
#include <gutil_log.h>
struct gbinder_servicemanager {
guint32 refcount;
GHashTable* services;
GUtilIdlePool* pool;
char* dev;
};
static GHashTable* test_servermanagers = NULL;
static
void
test_gbinder_servicemanager_free(
GBinderServiceManager* self)
{
/* Update the global table */
g_assert(test_servermanagers);
g_assert(g_hash_table_contains(test_servermanagers, self->dev));
g_hash_table_remove(test_servermanagers, self->dev); /* Frees self->dev */
if (g_hash_table_size(test_servermanagers) == 0) {
g_hash_table_unref(test_servermanagers);
test_servermanagers = NULL;
}
gutil_idle_pool_destroy(self->pool);
g_hash_table_destroy(self->services);
g_free(self);
}
/*==========================================================================*
* Internal API
*==========================================================================*/
GBinderRemoteObject*
test_gbinder_servicemanager_new_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* local)
{
GBinderRemoteObject* remote = test_gbinder_remote_object_new(local);
g_hash_table_replace(self->services, g_strdup(name), remote);
return gbinder_remote_object_ref(remote);
}
/*==========================================================================*
* libgbinder API
*==========================================================================*/
GBinderServiceManager*
gbinder_servicemanager_new(
const char* dev)
{
GBinderServiceManager* self = NULL;
g_assert(dev && dev[0]);
if (test_servermanagers) {
self = g_hash_table_lookup(test_servermanagers, dev);
}
if (self) {
gbinder_servicemanager_ref(self);
} else {
self = g_new0(GBinderServiceManager, 1);
g_atomic_int_set(&self->refcount, 1);
self->pool = gutil_idle_pool_new();
self->dev = g_strdup(dev); /* Owned by test_servermanagers */
self->services = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify) gbinder_remote_object_unref);
/* Update the global table */
if (!test_servermanagers) {
test_servermanagers = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
}
g_hash_table_replace(test_servermanagers, self->dev, self);
}
return self;
}
GBinderServiceManager*
gbinder_servicemanager_ref(
GBinderServiceManager* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_servicemanager_unref(
GBinderServiceManager* self)
{
if (self) {
g_assert_cmpint(self->refcount, > ,0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
test_gbinder_servicemanager_free(self);
}
}
}
GBinderRemoteObject* /* autoreleased */
gbinder_servicemanager_get_service_sync(
GBinderServiceManager* self,
const char* name,
int* status)
{
if (self && name) {
GBinderRemoteObject* obj = g_hash_table_lookup(self->services, name);
if (obj) {
gutil_idle_pool_add(self->pool, gbinder_remote_object_ref(obj),
(GDestroyNotify) gbinder_remote_object_unref);
return obj;
} else {
GDEBUG("Name %s not found", name);
}
}
return NULL;
}
GBinderLocalObject*
gbinder_servicemanager_new_local_object2(
GBinderServiceManager* self,
const char* const* ifaces,
GBinderLocalTransactFunc fn,
void* user_data)
{
return self ? test_gbinder_local_object_new(ifaces, fn, user_data) : NULL;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

166
unit/common/test_main.c Normal file
View File

@@ -0,0 +1,166 @@
/*
* 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 "test_common.h"
#include <gutil_log.h>
typedef struct test_quit_later_data{
GMainLoop* loop;
guint n;
} TestQuitLaterData;
typedef struct test_context_data{
GMainLoop* loop;
GTestFunc func;
} TestContextData;
static
gboolean
test_timeout_expired(
gpointer data)
{
g_assert(!"TIMEOUT");
return G_SOURCE_REMOVE;
}
static
void
test_quit_later_n_free(
gpointer user_data)
{
TestQuitLaterData* data = user_data;
g_main_loop_unref(data->loop);
g_free(data);
}
static
gboolean
test_quit_later_n_func(
gpointer user_data)
{
TestQuitLaterData* data = user_data;
if (data->n > 0) {
data->n--;
return G_SOURCE_CONTINUE;
} else {
g_main_loop_quit(data->loop);
return G_SOURCE_REMOVE;
}
}
void
test_quit_later_n(
GMainLoop* loop,
guint n)
{
TestQuitLaterData* data = g_new0(TestQuitLaterData, 1);
data->loop = g_main_loop_ref(loop);
data->n = n;
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_quit_later_n_func, data,
test_quit_later_n_free);
}
static
gboolean
test_quit_later_cb(
gpointer data)
{
g_main_loop_quit((GMainLoop*)data);
return G_SOURCE_REMOVE;
}
void
test_quit_later(
GMainLoop* loop)
{
g_idle_add(test_quit_later_cb, loop);
}
void
test_run(
const TestOpt* opt,
GMainLoop* loop)
{
if (opt->flags & TEST_FLAG_DEBUG) {
g_main_loop_run(loop);
} else {
const guint timeout_id = g_timeout_add_seconds(TEST_TIMEOUT_SEC,
test_timeout_expired, NULL);
g_main_loop_run(loop);
g_source_remove(timeout_id);
}
}
void
test_init(
TestOpt* opt,
int argc,
char* argv[])
{
const char* sep1;
const char* sep2;
int i;
memset(opt, 0, sizeof(*opt));
for (i=1; i<argc; i++) {
const char* arg = argv[i];
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
opt->flags |= TEST_FLAG_DEBUG;
} else if (!strcmp(arg, "-v")) {
GTestConfig* config = (GTestConfig*)g_test_config_vars;
config->test_verbose = TRUE;
} else {
GWARN("Unsupported command line option %s", arg);
}
}
/* Setup logging */
sep1 = strrchr(argv[0], '/');
sep2 = strrchr(argv[0], '\\');
gutil_log_default.name = (sep1 && sep2) ? (MAX(sep1, sep2) + 1) :
sep1 ? (sep1 + 1) : sep2 ? (sep2 + 1) : argv[0];
gutil_log_default.level = g_test_verbose() ?
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
gutil_log_timestamp = FALSE;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

56
unit/coverage/run Executable file
View File

@@ -0,0 +1,56 @@
#!/bin/bash
#
# This script requires lcov, dirname
#
TESTS="\
unit_client \
unit_config \
unit_instance \
unit_registry \
unit_util"
function err() {
echo "*** ERROR!" $1
exit 1
}
# Check the required tools
which lcov >> /dev/null || err "Please install lcov"
which dirname >> /dev/null || err "Please install dirname"
# LCOV 1.10 has branch coverage disabled per default
# Previous versions didn't have the --rc option
if [ ! -z "$(lcov --help | grep ' --rc ')" ] ; then
LCOV_OPT="--rc lcov_branch_coverage=1"
GENHTML_OPT="--branch-coverage"
fi
pushd `dirname $0` > /dev/null
COV_DIR="$PWD"
pushd .. > /dev/null
TEST_DIR="$PWD"
pushd .. > /dev/null
TOP_DIR="$PWD"
popd > /dev/null
popd > /dev/null
popd > /dev/null
make -C "$TOP_DIR" clean
for t in $TESTS ; do
pushd "$TEST_DIR/$t"
make -C "$TEST_DIR/$t" clean coverage || exit 1
build/coverage/$t || exit 1
popd
done
# Sometimes you need this, sometimes that :S
BASE_DIR="$TOP_DIR"
#BASE_DIR="$TOP_DIR/src"
FULL_COV="$COV_DIR/full.gcov"
LIB_COV="$COV_DIR/lib.gcov"
rm -f "$FULL_COV" "$LIB_COV"
lcov $LCOV_OPT -c -d "$TOP_DIR/build/coverage" -b "$BASE_DIR" -o "$FULL_COV" || exit 1
lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/*" -o "$LIB_COV" || exit 1
genhtml $GENHTML_OPT "$LIB_COV" -t "libgbinder-radio" --output-directory "$COV_DIR/report" || exit 1

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,915 @@
/*
* Copyright (C) 2022 Jolla Ltd.
* Copyright (C) 2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_common.h"
#include "test_gbinder.h"
#include "radio_config.h"
#include "radio_request_p.h"
#include <gutil_strv.h>
#include <gutil_log.h>
#define DEV GBINDER_DEFAULT_HWBINDER
static TestOpt test_opt;
static const GBinderClientIfaceInfo radio_config_ind_iface_info[] = {
{RADIO_CONFIG_INDICATION_1_0, RADIO_CONFIG_1_0_IND_LAST }
};
static const GBinderClientIfaceInfo radio_config_resp_iface_info[] = {
{RADIO_CONFIG_RESPONSE_1_1, RADIO_CONFIG_1_1_RESP_LAST },
{RADIO_CONFIG_RESPONSE_1_0, RADIO_CONFIG_1_0_RESP_LAST }
};
static const char* const radio_config_req_ifaces[] = {
RADIO_CONFIG_1_1,
RADIO_CONFIG_1_0,
NULL
};
static const char* const radio_config_fqnames[] = {
RADIO_CONFIG_1_0_FQNAME,
RADIO_CONFIG_1_1_FQNAME
};
static
void
test_complete_not_reached(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_CONFIG_RESP resp,
RADIO_ERROR error,
const GBinderReader* reader,
gpointer user_data)
{
g_assert_not_reached();
}
static
void
test_destroy_once(
gpointer user_data)
{
gboolean* destroyed = user_data;
g_assert(!*destroyed);
*destroyed = TRUE;
}
static
void
test_ind_not_reached(
RadioConfig* config,
RADIO_CONFIG_IND code,
const GBinderReader* args,
gpointer user_data)
{
g_assert_not_reached();
}
static
void
test_inc_cb(
gpointer user_data)
{
(*((int*)user_data))++;
}
static
void
test_config_inc_cb(
RadioConfig* config,
gpointer user_data)
{
(*((int*)user_data))++;
}
static
RADIO_CONFIG_RESP
test_config_req_resp(
RADIO_CONFIG_REQ req)
{
switch (req) {
#define REQ_RESP_(req,resp,Name,NAME) \
case RADIO_CONFIG_REQ_##NAME: return RADIO_CONFIG_RESP_##NAME;
RADIO_CONFIG_CALL_1_0(REQ_RESP_)
RADIO_CONFIG_CALL_1_1(REQ_RESP_)
#undef REQ_RESP_
case RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS:
return RADIO_CONFIG_RESP_NONE;
case RADIO_CONFIG_REQ_ANY:
break;
}
g_assert_not_reached();
return RADIO_CONFIG_RESP_NONE;
}
/*==========================================================================*
* Test IRadioConfig service
*==========================================================================*/
typedef struct test_config_service {
GBinderLocalObject* obj;
GBinderClient* resp_client;
GBinderClient* ind_client;
GHashTable* req_count;
} TestConfigService;
#define FAIL_REQ RADIO_CONFIG_REQ_GET_PHONE_CAPABILITY
#define ERROR_REQ RADIO_CONFIG_REQ_SET_SIM_SLOTS_MAPPING
#define ERROR_RESP RADIO_CONFIG_RESP_SET_SIM_SLOTS_MAPPING
#define IGNORE_REQ RADIO_CONFIG_REQ_SET_MODEMS_CONFIG
static
int
test_config_service_req_count(
TestConfigService* service,
RADIO_CONFIG_REQ req)
{
return GPOINTER_TO_INT(g_hash_table_lookup(service->req_count,
GINT_TO_POINTER(req)));
}
static
GBinderLocalReply*
test_config_service_txproc(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
TestConfigService* service = user_data;
const char* iface = gbinder_remote_request_interface(req);
if (gutil_strv_contains((const GStrV*)radio_config_req_ifaces, iface)) {
const int count = test_config_service_req_count(service, code) + 1;
GBinderReader reader;
GDEBUG("%s %s %d", iface, radio_config_req_name(NULL, code), count);
g_hash_table_insert(service->req_count, GINT_TO_POINTER(code),
GINT_TO_POINTER(count));
gbinder_remote_request_init_reader(req, &reader);
if (code == RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS) {
GBinderRemoteObject* resp_obj = gbinder_reader_read_object(&reader);
GBinderRemoteObject* ind_obj = gbinder_reader_read_object(&reader);
g_assert(resp_obj);
g_assert(ind_obj);
gbinder_client_unref(service->resp_client);
gbinder_client_unref(service->ind_client);
service->resp_client = gbinder_client_new2(resp_obj,
TEST_ARRAY_AND_COUNT(radio_config_resp_iface_info));
service->ind_client = gbinder_client_new2(ind_obj,
TEST_ARRAY_AND_COUNT(radio_config_ind_iface_info));
gbinder_remote_object_unref(resp_obj);
gbinder_remote_object_unref(ind_obj);
} else if (code == FAIL_REQ) {
GDEBUG("failing request transaction");
*status = GBINDER_STATUS_FAILED;
return NULL;
} else if (code == IGNORE_REQ) {
GDEBUG("ignoring request transaction");
} else {
RadioResponseInfo info;
GBinderWriter writer;
RADIO_CONFIG_RESP resp_code = test_config_req_resp(code);
GBinderLocalRequest* resp = gbinder_client_new_request2
(service->resp_client, resp_code);
memset(&info, 0, sizeof(info));
info.type = RADIO_RESP_SOLICITED;
info.error = (code == ERROR_REQ) ?
RADIO_ERROR_GENERIC_FAILURE :
RADIO_ERROR_NONE;
g_assert(gbinder_reader_read_uint32(&reader, &info.serial));
GDEBUG("serial %08x", info.serial);
g_assert(resp);
gbinder_local_request_init_writer(resp, &writer);
gbinder_writer_append_buffer_object(&writer, &info, sizeof(info));
switch (code) {
case RADIO_CONFIG_REQ_SET_PREFERRED_DATA_MODEM:
g_assert(gbinder_client_transact(service->resp_client,
resp_code, GBINDER_TX_FLAG_ONEWAY, resp, NULL, NULL, NULL));
break;
default:
/* No expecting anything else */
g_assert_not_reached();
break;
}
gbinder_local_request_unref(resp);
}
*status = GBINDER_STATUS_OK;
return NULL;
} else {
GDEBUG("%s %u", iface, code);
*status = GBINDER_STATUS_FAILED;
return NULL;
}
}
static
void
test_config_service_init(
TestConfigService* service)
{
memset(service, 0, sizeof(*service));
service->obj = test_gbinder_local_object_new(NULL,
test_config_service_txproc, service);
service->req_count = g_hash_table_new(g_direct_hash, g_direct_equal);
}
static
void
test_config_service_cleanup(
TestConfigService* service)
{
g_hash_table_destroy(service->req_count);
gbinder_client_unref(service->resp_client);
gbinder_client_unref(service->ind_client);
gbinder_local_object_unref(service->obj);
memset(service, 0, sizeof(*service));
}
/*==========================================================================*
* Common setup for all tests
*==========================================================================*/
typedef struct test_common {
TestConfigService service;
GBinderServiceManager* sm;
GBinderRemoteObject* remote[RADIO_CONFIG_INTERFACE_COUNT];
RadioConfig* client;
} TestCommon;
static
RadioConfig*
test_common_init(
TestCommon* test,
RADIO_CONFIG_INTERFACE version)
{
RADIO_CONFIG_INTERFACE v;
memset(test, 0, sizeof(*test));
test->sm = gbinder_servicemanager_new(DEV);
test_config_service_init(&test->service);
for (v = RADIO_CONFIG_INTERFACE_1_0; v <= version; v++) {
test->remote[v] = test_gbinder_servicemanager_new_service(test->sm,
radio_config_fqnames[v], test->service.obj);
}
test->client = radio_config_new();
g_assert(test->client);
return test->client;
}
static
void
test_common_cleanup(
TestCommon* test)
{
int i;
radio_config_unref(test->client);
test_config_service_cleanup(&test->service);
for (i = 0; i < G_N_ELEMENTS(test->remote); i++) {
gbinder_remote_object_unref(test->remote[i]);
}
gbinder_servicemanager_unref(test->sm);
}
/*==========================================================================*
* Another common setup
*==========================================================================*/
typedef struct test_simple_data {
TestCommon common;
GMainLoop* loop;
int completed; /* Typically used as a boolean */
int destroyed; /* Typically used as a boolean */
} TestSimple;
static
RadioConfig*
test_simple_init(
TestSimple* test)
{
memset(test, 0, sizeof(*test));
test->loop = g_main_loop_new(NULL, FALSE);
return test_common_init(&test->common, RADIO_CONFIG_INTERFACE_1_1);
}
static
void
test_simple_cleanup(
TestSimple* test)
{
g_main_loop_unref(test->loop);
test_common_cleanup(&test->common);
}
static
void
test_simple_destroy_cb(
gpointer user_data)
{
TestSimple* test = user_data;
GDEBUG("done");
g_assert(test->completed);
g_assert(!test->destroyed);
test->destroyed = TRUE;
test_quit_later(test->loop);
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
g_assert(!radio_config_ref(NULL));
g_assert(radio_config_dead(NULL));
g_assert_cmpint(radio_config_interface(NULL),==,RADIO_CONFIG_INTERFACE_NONE);
g_assert(!radio_config_rpc_header_size(NULL, RADIO_CONFIG_REQ_NONE));
g_assert(!radio_config_req_name(NULL, RADIO_CONFIG_REQ_NONE));
g_assert(!radio_config_resp_name(NULL, RADIO_CONFIG_RESP_NONE));
g_assert(!radio_config_ind_name(NULL, RADIO_CONFIG_IND_NONE));
g_assert(!radio_config_add_death_handler(NULL, NULL, NULL));
g_assert(!radio_config_add_request_observer(NULL,
RADIO_CONFIG_REQ_ANY, NULL, NULL));
g_assert(!radio_config_add_request_observer_with_priority(NULL,
RADIO_CONFIG_REQ_ANY, RADIO_OBSERVER_PRIORITY_LOWEST, NULL, NULL));
radio_config_unref(NULL);
g_assert(!radio_config_add_response_observer(NULL,
RADIO_CONFIG_RESP_ANY, NULL, NULL));
g_assert(!radio_config_add_response_observer_with_priority(NULL,
RADIO_CONFIG_RESP_ANY, RADIO_OBSERVER_PRIORITY_LOWEST, NULL, NULL));
g_assert(!radio_config_add_indication_observer(NULL,
RADIO_CONFIG_IND_ANY, NULL, NULL));
g_assert(!radio_config_add_indication_observer_with_priority(NULL,
RADIO_CONFIG_IND_ANY, RADIO_OBSERVER_PRIORITY_LOWEST, NULL, NULL));
g_assert(!radio_config_request_new(NULL, ERROR_REQ, NULL, NULL, NULL, NULL));
radio_config_unref(NULL);
radio_config_remove_handler(NULL, 0);
radio_config_remove_handlers(NULL, NULL, 0);
}
/*==========================================================================*
* name
*==========================================================================*/
static
void
test_name(
void)
{
TestCommon test;
RadioConfig* client = test_common_init(&test, RADIO_CONFIG_INTERFACE_1_1);
g_assert_cmpstr(radio_config_req_name(client,
RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS), == ,
"setResponseFunctions");
g_assert_cmpstr(radio_config_req_name(client,
RADIO_CONFIG_REQ_GET_SIM_SLOTS_STATUS), == ,
"getSimSlotsStatus");
g_assert_cmpstr(radio_config_req_name(client,
RADIO_CONFIG_REQ_GET_PHONE_CAPABILITY), == ,
"getPhoneCapability");
g_assert_cmpstr(radio_config_req_name(client,
(RADIO_CONFIG_REQ)123), == ,
"123");
g_assert_cmpstr(radio_config_resp_name(client,
RADIO_CONFIG_RESP_GET_SIM_SLOTS_STATUS), == ,
"getSimSlotsStatusResponse");
g_assert_cmpstr(radio_config_resp_name(client,
RADIO_CONFIG_RESP_GET_PHONE_CAPABILITY), == ,
"getPhoneCapabilityResponse");
g_assert_cmpstr(radio_config_resp_name(client,
(RADIO_CONFIG_RESP)1234), == ,
"1234");
g_assert_cmpstr(radio_config_ind_name(client,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED), == ,
"simSlotsStatusChanged");
g_assert_cmpstr(radio_config_ind_name(client,
(RADIO_CONFIG_IND)12345), == ,
"12345");
test_common_cleanup(&test);
}
/*==========================================================================*
* none
*==========================================================================*/
static
void
test_none(
void)
{
/* No service => no client */
g_assert(!radio_config_new());
}
/*==========================================================================*
* basic
*==========================================================================*/
static
void
test_basic(
void)
{
TestCommon test;
RADIO_CONFIG_INTERFACE version = RADIO_CONFIG_INTERFACE_1_0;
RadioConfig* client = test_common_init(&test, version);
RadioRequest* req;
int destroyed = 0;
g_assert(!radio_config_dead(client));
g_assert(radio_config_rpc_header_size(client,
RADIO_CONFIG_REQ_GET_SIM_SLOTS_STATUS));
g_assert_cmpint(radio_config_interface(client), == ,version);
g_assert(radio_config_ref(client) == client);
radio_config_unref(client);
/* Instances are reused */
g_assert(radio_config_new() == client);
radio_config_unref(client);
g_assert(radio_config_new_with_version(version) == client);
radio_config_unref(client);
g_assert(radio_config_new_with_version(RADIO_CONFIG_INTERFACE_COUNT) ==
client);
radio_config_unref(client);
/* Adding NULL observer is a nop */
g_assert(!radio_config_add_death_handler(client, NULL, NULL));
g_assert(!radio_config_add_request_observer(client,
RADIO_CONFIG_REQ_ANY, NULL, NULL));
g_assert(!radio_config_add_response_observer(client,
RADIO_CONFIG_RESP_ANY, NULL, NULL));
g_assert(!radio_config_add_indication_observer(client,
RADIO_CONFIG_IND_ANY, NULL, NULL));
/* Zero handler id is tolerated */
radio_config_remove_handler(client, 0);
/* Create and destroy the request */
req = radio_config_request_new(client, RADIO_CONFIG_REQ_GET_MODEMS_CONFIG,
NULL, NULL, test_inc_cb, &destroyed);
g_assert(req);
radio_request_unref(req);
g_assert(destroyed);
test_common_cleanup(&test);
}
/*==========================================================================*
* ind
*==========================================================================*/
typedef struct test_ind_data {
TestCommon common;
GMainLoop* loop;
RADIO_CONFIG_IND ind;
} TestInd;
static
void
test_ind_cb(
RadioConfig* config,
RADIO_CONFIG_IND code,
const GBinderReader* args,
gpointer user_data)
{
TestInd* test = user_data;
/* This one is invoked first */
GDEBUG("first indication %d", code);
g_assert_cmpint(code, == ,RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
g_assert_cmpint(test->ind, == ,RADIO_CONFIG_IND_NONE);
test->ind = code;
}
static
void
test_ind_cb2(
RadioConfig* config,
RADIO_CONFIG_IND code,
const GBinderReader* args,
gpointer user_data)
{
TestInd* test = user_data;
/* This one is invoked second */
GDEBUG("second indication %d", code);
g_assert_cmpint(test->ind, == ,RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
g_assert_cmpint(code, == ,RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
test_quit_later(test->loop);
}
static
void
test_ind(
void)
{
GBinderLocalRequest* req;
GBinderClient* ind_client;
RadioConfig* client;
TestInd test;
gulong id[2];
memset(&test, 0, sizeof(test));
test.loop = g_main_loop_new(NULL, FALSE);
client = test_common_init(&test.common, RADIO_CONFIG_INTERFACE_1_1);
ind_client = test.common.service.ind_client;
/* Register and unregister one listener */
id[0] = radio_config_add_indication_observer(client, RADIO_CONFIG_IND_ANY,
test_ind_not_reached, NULL);
radio_config_remove_handler(client, id[0]);
/* Register actual listeners */
id[0] = radio_config_add_indication_observer_with_priority(client,
RADIO_OBSERVER_PRIORITY_HIGHEST,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED,
test_ind_cb, &test);
id[1] = radio_config_add_indication_observer_with_priority(client,
RADIO_OBSERVER_PRIORITY_DEFAULT,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED,
test_ind_cb2, &test);
/* This one will be ignored because type is missing */
req = gbinder_client_new_request2(ind_client,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
g_assert_cmpint(gbinder_client_transact(ind_client,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED, GBINDER_TX_FLAG_ONEWAY,
req, NULL, NULL, NULL), != ,0);
gbinder_local_request_unref(req);
/* This one will be ignored because RADIO_IND_ACK_EXP is not expected */
req = gbinder_client_new_request2(ind_client,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
gbinder_local_request_append_int32(req, RADIO_IND_ACK_EXP);
g_assert_cmpint(gbinder_client_transact(ind_client,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED, GBINDER_TX_FLAG_ONEWAY,
req, NULL, NULL, NULL), != ,0);
gbinder_local_request_unref(req);
/* And this one will be handled */
req = gbinder_client_new_request2(ind_client,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
gbinder_local_request_append_int32(req, RADIO_IND_UNSOLICITED);
/*
* RadioIndicationType should be followed by vec<SimSlotStatus> but
* that's not required for the purposes of this unit test.
*/
g_assert_cmpint(gbinder_client_transact(ind_client,
RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED, GBINDER_TX_FLAG_ONEWAY,
req, NULL, NULL, NULL), != ,0);
gbinder_local_request_unref(req);
/* And wait for test_ind_cb2 to terminate the loop */
test_run(&test_opt, test.loop);
g_assert_cmpint(test.ind, == ,RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
/* Cleanup */
radio_config_remove_all_handlers(client, id);
g_main_loop_unref(test.loop);
test_common_cleanup(&test.common);
}
/*==========================================================================*
* resp
*==========================================================================*/
static
void
test_resp_observe_req1(
RadioConfig* config,
RADIO_CONFIG_REQ code,
GBinderLocalRequest* args,
gpointer user_data)
{
int* observed = user_data;
GDEBUG("high prio observed req %d", code);
g_assert(!*observed);
*observed = -((int)code);
}
static
void
test_resp_observe_req2(
RadioConfig* config,
RADIO_CONFIG_REQ code,
GBinderLocalRequest* args,
gpointer user_data)
{
int* observed = user_data;
GDEBUG("low prio observed req %d", code);
g_assert_cmpint(*observed, == ,-((int)code));
*observed = code;
}
static
void
test_resp_observe_resp1(
RadioConfig* config,
RADIO_CONFIG_RESP code,
const RadioResponseInfo* info,
const GBinderReader* args,
gpointer user_data)
{
int* observed = user_data;
GDEBUG("high prio observed resp %d", code);
g_assert(!*observed);
*observed = -((int)code);
}
static
void
test_resp_observe_resp2(
RadioConfig* config,
RADIO_CONFIG_RESP code,
const RadioResponseInfo* info,
const GBinderReader* args,
gpointer user_data)
{
int* observed = user_data;
GDEBUG("low prio observed resp %d", code);
g_assert_cmpint(*observed, == ,-((int)code));
*observed = code;
}
static
void
test_resp_complete_cb(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_CONFIG_RESP resp,
RADIO_ERROR error,
const GBinderReader* reader,
gpointer user_data)
{
TestSimple* test = user_data;
GDEBUG("resp %d", resp);
g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
g_assert_cmpint(resp, == ,RADIO_CONFIG_RESP_SET_PREFERRED_DATA_MODEM);
g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
g_assert(!test->completed);
g_assert(!test->destroyed);
test->completed = TRUE;
}
static
void
test_resp(
void)
{
TestSimple test;
RadioConfig* client = test_simple_init(&test);
RadioRequest* req = radio_config_request_new(client,
RADIO_CONFIG_REQ_SET_PREFERRED_DATA_MODEM, NULL,
test_resp_complete_cb, test_simple_destroy_cb, &test);
int observed_req = 0, observed_resp = 0;
gulong id[4];
id[0] = radio_config_add_request_observer_with_priority(client,
RADIO_OBSERVER_PRIORITY_HIGHEST, RADIO_CONFIG_REQ_ANY,
test_resp_observe_req1, &observed_req);
id[1] = radio_config_add_request_observer_with_priority(client,
RADIO_OBSERVER_PRIORITY_LOWEST, RADIO_CONFIG_REQ_ANY,
test_resp_observe_req2, &observed_req);
id[2] = radio_config_add_response_observer_with_priority(client,
RADIO_OBSERVER_PRIORITY_HIGHEST, RADIO_CONFIG_RESP_ANY,
test_resp_observe_resp1, &observed_resp);
id[3] = radio_config_add_response_observer_with_priority(client,
RADIO_OBSERVER_PRIORITY_LOWEST, RADIO_CONFIG_RESP_ANY,
test_resp_observe_resp2, &observed_resp);
g_assert(radio_request_submit(req));
radio_request_unref(req);
test_run(&test_opt, test.loop);
g_assert(test.completed);
g_assert(test.destroyed);
g_assert_cmpint(observed_req,==,RADIO_CONFIG_REQ_SET_PREFERRED_DATA_MODEM);
g_assert_cmpint(observed_resp,==,RADIO_CONFIG_RESP_SET_PREFERRED_DATA_MODEM);
/* Cleanup */
radio_config_remove_all_handlers(client, id);
test_simple_cleanup(&test);
}
/*==========================================================================*
* cancel
*==========================================================================*/
static
void
test_cancel(
void)
{
TestCommon test;
gboolean destroyed = FALSE;
RadioConfig* client = test_common_init(&test, RADIO_CONFIG_INTERFACE_1_0);
RadioRequest* req = radio_config_request_new(client,
RADIO_CONFIG_REQ_GET_MODEMS_CONFIG, NULL,
test_complete_not_reached, test_destroy_once, &destroyed);
g_assert(radio_request_submit(req));
radio_request_cancel(req);
g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_CANCELLED);
radio_request_unref(req);
g_assert(destroyed);
test_common_cleanup(&test);
}
/*==========================================================================*
* fail_tx
*==========================================================================*/
static
void
test_fail_tx(
void)
{
TestCommon test;
gboolean destroyed = FALSE;
RadioConfig* client = test_common_init(&test, RADIO_CONFIG_INTERFACE_1_0);
RadioRequest* req = radio_config_request_new(client,
RADIO_CONFIG_REQ_GET_MODEMS_CONFIG, NULL,
test_complete_not_reached, test_destroy_once, &destroyed);
g_assert(req);
g_assert(req->serial);
/* Fail one transaction */
test_gbinder_client_tx_fail_count = 1;
/* Request switches in the FAILED state */
g_assert(req);
g_assert(!radio_request_submit(req));
g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_FAILED);
g_assert(!destroyed);
radio_request_drop(req);
g_assert(destroyed);
test_common_cleanup(&test);
}
/*==========================================================================*
* death
*==========================================================================*/
static
void
test_death_complete_cb(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_CONFIG_RESP resp,
RADIO_ERROR error,
const GBinderReader* reader,
gpointer user_data)
{
TestSimple* test = user_data;
GDEBUG("status %u", status);
g_assert_cmpint(status, == ,RADIO_TX_STATUS_FAILED);
g_assert_cmpint(resp, == ,RADIO_CONFIG_RESP_NONE);
g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
test->completed++;
}
static
void
test_death_destroy_cb(
gpointer user_data)
{
TestSimple* test = user_data;
test->destroyed++;
GDEBUG("done");
g_assert_cmpint(test->completed, == ,test->destroyed);
test_quit_later(test->loop);
}
static
void
test_death(
void)
{
TestSimple test;
RadioConfig* client = test_simple_init(&test);
RadioRequest* req = radio_config_request_new(client,
RADIO_CONFIG_REQ_GET_MODEMS_CONFIG, NULL,
test_death_complete_cb, test_death_destroy_cb, &test);
RADIO_CONFIG_INTERFACE v;
int death_count = 0;
gulong id = radio_config_add_death_handler(client, test_config_inc_cb,
&death_count);
g_assert(radio_request_submit(req));
radio_request_unref(req);
/* Kill the remote objects */
g_assert(!radio_config_dead(client));
for (v = RADIO_CONFIG_INTERFACE_1_0;
v <= radio_config_interface(client); v++) {
test_gbinder_remote_object_kill(test.common.remote[v]);
}
g_assert(radio_config_dead(client));
g_assert_cmpint(death_count, == ,1);
/* Now expect the request to fail */
test_run(&test_opt, test.loop);
g_assert(test.completed);
g_assert(test.destroyed);
/* Cleanup */
radio_config_remove_handler(client, id);
test_simple_cleanup(&test);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/config/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("name"), test_name);
g_test_add_func(TEST_("none"), test_none);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("ind"), test_ind);
g_test_add_func(TEST_("resp"), test_resp);
g_test_add_func(TEST_("cancel"), test_cancel);
g_test_add_func(TEST_("fail_tx"), test_fail_tx);
g_test_add_func(TEST_("death"), test_death);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,170 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_common.h"
#include "radio_instance.h"
#include "radio_registry_p.h"
#include <glib-object.h>
static TestOpt test_opt;
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
radio_registry_instance_added(NULL);
radio_registry_instance_removed(NULL);
radio_registry_remove_handler(NULL, 0);
radio_registry_remove_handlers(NULL, NULL, 0);
radio_registry_unref(NULL);
g_assert(!radio_registry_ref(NULL));
g_assert(!radio_registry_add_instance_added_handler(NULL,NULL,NULL,NULL));
g_assert(!radio_registry_add_instance_removed_handler(NULL,NULL,NULL,NULL));
}
/*==========================================================================*
* basic
*==========================================================================*/
static const char* test_basic_key = "foo";
static const char* test_basic_bad_key = "bar";
static
void
test_basic_add_cb(
RadioRegistry* registry,
RadioInstance* radio,
gpointer user_data)
{
(*((int*)user_data))++;
}
static
void
test_basic_remove_cb(
RadioRegistry* registry,
const char* str,
gpointer user_data)
{
g_assert_cmpstr(str, == ,test_basic_key);
(*((int*)user_data))++;
}
static
void
test_basic(
void)
{
RadioRegistry* reg = radio_registry_new();
int add_count = 0, remove_count = 0;
gulong id[6];
GObject* instance;
g_assert(reg);
g_assert(reg == radio_registry_new()); /* New ref to the same instance */
radio_registry_unref(reg);
g_assert(!radio_registry_add_instance_added_handler(reg,NULL,NULL,NULL));
g_assert(!radio_registry_add_instance_removed_handler(reg,NULL,NULL,NULL));
/* Add/remove handlers */
id[0] = radio_registry_add_instance_added_handler(reg, "",
test_basic_add_cb, &add_count);
radio_registry_remove_handler(reg, id[0]);
id[0] = radio_registry_add_instance_added_handler(reg, NULL,
test_basic_add_cb, &add_count);
id[1] = radio_registry_add_instance_added_handler(reg, test_basic_bad_key,
test_basic_add_cb, &add_count); /* won't get called */
id[2] = radio_registry_add_instance_removed_handler(reg, NULL,
test_basic_remove_cb, &remove_count);
id[3] = radio_registry_add_instance_removed_handler(reg, "",
test_basic_remove_cb, &remove_count);
id[4] = radio_registry_add_instance_removed_handler(reg, test_basic_key,
test_basic_remove_cb, &remove_count);
id[5] = radio_registry_add_instance_removed_handler(reg, test_basic_bad_key,
test_basic_remove_cb, &remove_count); /* won't get called */
/* Well, this wouldn't be a real functional instance but we don't care */
instance = g_object_new(RADIO_TYPE_INSTANCE, NULL);
radio_registry_instance_added(RADIO_INSTANCE(instance));
g_assert_cmpint(add_count, == ,1); /* 1 out of 2 is called */
g_assert_cmpint(remove_count, == ,0);
radio_registry_instance_removed(test_basic_key);
g_assert_cmpint(add_count, == ,1);
g_assert_cmpint(remove_count, == ,3); /* 3 our of 4 are called */
g_object_unref(instance);
/* remove_all zeros the ids */
radio_registry_remove_all_handlers(reg, id);
g_assert(!id[0]);
g_assert(!id[4]);
radio_registry_remove_handler(reg, 0); /* No effect */
radio_registry_unref(reg);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/registry/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("basic"), test_basic);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

5
unit/unit_util/Makefile Normal file
View File

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

363
unit/unit_util/unit_util.c Normal file
View File

@@ -0,0 +1,363 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* any official policies, either expressed or implied.
*/
#include "test_common.h"
#include "radio_util.h"
#define UNKNOWN_VALUE (0x7fffffff)
#define UNKNOWN_REQ ((RADIO_REQ)UNKNOWN_VALUE)
#define UNKNOWN_IND ((RADIO_REQ)UNKNOWN_VALUE)
#define UNKNOWN_RESP ((RADIO_RESP)UNKNOWN_VALUE)
static TestOpt test_opt;
/*==========================================================================*
* req_name
*==========================================================================*/
static
void
test_req_name(
void)
{
g_assert(!radio_req_name(UNKNOWN_REQ));
g_assert(!radio_req_name(RADIO_REQ_ANY));
g_assert_cmpstr(radio_req_name(RADIO_REQ_GET_ICC_CARD_STATUS),==,
"getIccCardStatus");
g_assert_cmpstr(radio_req_name(RADIO_REQ_START_NETWORK_SCAN),==,
"startNetworkScan");
g_assert_cmpstr(radio_req_name(RADIO_REQ_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA),==,
"setSignalStrengthReportingCriteria");
g_assert_cmpstr(radio_req_name(RADIO_REQ_SET_SYSTEM_SELECTION_CHANNELS),==,
"setSystemSelectionChannels");
g_assert_cmpstr(radio_req_name(RADIO_REQ_EMERGENCY_DIAL),==,
"emergencyDial");
}
/*==========================================================================*
* resp_name
*==========================================================================*/
static
void
test_resp_name(
void)
{
g_assert(!radio_resp_name(UNKNOWN_RESP));
g_assert(!radio_resp_name(RADIO_RESP_ANY));
g_assert_cmpstr(radio_resp_name(RADIO_RESP_GET_ICC_CARD_STATUS),==,
"getIccCardStatusResponse");
g_assert_cmpstr(radio_resp_name(RADIO_RESP_START_NETWORK_SCAN),==,
"startNetworkScanResponse");
g_assert_cmpstr(radio_resp_name(RADIO_RESP_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA),==,
"setSignalStrengthReportingCriteriaResponse");
g_assert_cmpstr(radio_resp_name(RADIO_RESP_SET_SYSTEM_SELECTION_CHANNELS),==,
"setSystemSelectionChannelsResponse");
g_assert_cmpstr(radio_resp_name(RADIO_RESP_EMERGENCY_DIAL),==,
"emergencyDialResponse");
}
/*==========================================================================*
* ind_name
*==========================================================================*/
static
void
test_ind_name(
void)
{
g_assert(!radio_ind_name(UNKNOWN_IND));
g_assert(!radio_ind_name(RADIO_IND_ANY));
g_assert_cmpstr(radio_ind_name(RADIO_IND_RADIO_STATE_CHANGED),==,
"radioStateChanged");
g_assert_cmpstr(radio_ind_name(RADIO_IND_NETWORK_SCAN_RESULT),==,
"networkScanResult");
g_assert_cmpstr(radio_ind_name(RADIO_IND_CURRENT_LINK_CAPACITY_ESTIMATE),==,
"currentLinkCapacityEstimate");
g_assert_cmpstr(radio_ind_name(RADIO_IND_CURRENT_EMERGENCY_NUMBER_LIST),==,
"currentEmergencyNumberList");
}
/*==========================================================================*
* req_resp
*==========================================================================*/
static
void
test_req_resp(
void)
{
static const struct radio_req_resp_data {
RADIO_REQ req;
RADIO_RESP resp;
} tests[] = {
{ UNKNOWN_REQ, RADIO_RESP_NONE },
{ RADIO_REQ_ANY, RADIO_RESP_NONE },
{ RADIO_REQ_SETUP_DATA_CALL_1_2, RADIO_RESP_SETUP_DATA_CALL },
{ RADIO_REQ_DEACTIVATE_DATA_CALL_1_2, RADIO_RESP_DEACTIVATE_DATA_CALL },
{ RADIO_REQ_START_NETWORK_SCAN_1_2, RADIO_RESP_START_NETWORK_SCAN },
{ RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4,
RADIO_RESP_SET_INITIAL_ATTACH_APN },
{ RADIO_REQ_SET_DATA_PROFILE_1_4, RADIO_RESP_SET_DATA_PROFILE },
{ RADIO_REQ_SET_INDICATION_FILTER_1_2,
RADIO_RESP_SET_INDICATION_FILTER },
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_RESP_GET_ICC_CARD_STATUS },
{ RADIO_REQ_START_NETWORK_SCAN, RADIO_RESP_START_NETWORK_SCAN },
{ RADIO_REQ_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA,
RADIO_RESP_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA },
{ RADIO_REQ_SET_SYSTEM_SELECTION_CHANNELS,
RADIO_RESP_SET_SYSTEM_SELECTION_CHANNELS },
{ RADIO_REQ_EMERGENCY_DIAL, RADIO_RESP_EMERGENCY_DIAL }
};
int i;
for (i = 0; i < G_N_ELEMENTS(tests); i++) {
g_assert_cmpint(radio_req_resp(tests[i].req), ==, tests[i].resp);
}
}
/*==========================================================================*
* req_resp2
*==========================================================================*/
static
void
test_req_resp2(
void)
{
static const struct radio_req_resp2_data {
RADIO_REQ req;
RADIO_INTERFACE iface;
RADIO_RESP resp;
} tests[] = {
{ UNKNOWN_REQ, RADIO_INTERFACE_NONE, RADIO_RESP_NONE },
{ RADIO_REQ_SUPPLY_ICC_PIN_FOR_APP, RADIO_INTERFACE_1_0,
RADIO_RESP_SUPPLY_ICC_PIN_FOR_APP },
{ RADIO_REQ_SUPPLY_ICC_PUK_FOR_APP, RADIO_INTERFACE_1_1,
RADIO_RESP_SUPPLY_ICC_PUK_FOR_APP },
{ RADIO_REQ_SUPPLY_ICC_PIN2_FOR_APP, RADIO_INTERFACE_1_2,
RADIO_RESP_SUPPLY_ICC_PIN2_FOR_APP },
{ RADIO_REQ_SUPPLY_ICC_PUK2_FOR_APP, RADIO_INTERFACE_1_3,
RADIO_RESP_SUPPLY_ICC_PUK2_FOR_APP },
{ RADIO_REQ_CHANGE_ICC_PIN_FOR_APP, RADIO_INTERFACE_1_4,
RADIO_RESP_CHANGE_ICC_PIN_FOR_APP },
{ RADIO_REQ_CHANGE_ICC_PIN2_FOR_APP, RADIO_INTERFACE_COUNT,
RADIO_RESP_CHANGE_ICC_PIN2_FOR_APP },
{ RADIO_REQ_SETUP_DATA_CALL_1_2, RADIO_INTERFACE_1_2,
RADIO_RESP_SETUP_DATA_CALL },
{ RADIO_REQ_SETUP_DATA_CALL_1_2, RADIO_INTERFACE_1_4,
RADIO_RESP_SETUP_DATA_CALL },
{ RADIO_REQ_DEACTIVATE_DATA_CALL_1_2, RADIO_INTERFACE_1_2,
RADIO_RESP_DEACTIVATE_DATA_CALL },
{ RADIO_REQ_DEACTIVATE_DATA_CALL_1_2, RADIO_INTERFACE_1_4,
RADIO_RESP_DEACTIVATE_DATA_CALL },
{ RADIO_REQ_START_NETWORK_SCAN_1_2, RADIO_INTERFACE_1_2,
RADIO_RESP_START_NETWORK_SCAN },
{ RADIO_REQ_START_NETWORK_SCAN_1_2, RADIO_INTERFACE_1_4,
RADIO_RESP_START_NETWORK_SCAN },
{ RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4, RADIO_INTERFACE_1_4,
RADIO_RESP_SET_INITIAL_ATTACH_APN },
{ RADIO_REQ_SET_DATA_PROFILE_1_4, RADIO_INTERFACE_1_4,
RADIO_RESP_SET_DATA_PROFILE },
{ RADIO_REQ_SET_INDICATION_FILTER_1_2, RADIO_INTERFACE_1_2,
RADIO_RESP_SET_INDICATION_FILTER },
{ RADIO_REQ_SET_INDICATION_FILTER_1_2, RADIO_INTERFACE_1_4,
RADIO_RESP_SET_INDICATION_FILTER },
/*
{ RADIO_REQ_SET_INDICATION_FILTER_1_5, RADIO_INTERFACE_1_5,
RADIO_RESP_SET_INDICATION_FILTER },
*/
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_0,
RADIO_RESP_GET_ICC_CARD_STATUS },
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_1,
RADIO_RESP_GET_ICC_CARD_STATUS },
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_2,
RADIO_RESP_GET_ICC_CARD_STATUS_1_2 },
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_3,
RADIO_RESP_GET_ICC_CARD_STATUS_1_2 },
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_4,
RADIO_RESP_GET_ICC_CARD_STATUS_1_4 },
/*
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_5,
RADIO_RESP_GET_ICC_CARD_STATUS_1_5 },
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_COUNT,
RADIO_RESP_GET_ICC_CARD_STATUS_1_5 },
*/
{ RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_NONE,
RADIO_RESP_NONE },
{ RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_0,
RADIO_RESP_GET_CELL_INFO_LIST },
{ RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_1,
RADIO_RESP_GET_CELL_INFO_LIST },
{ RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_2,
RADIO_RESP_GET_CELL_INFO_LIST_1_2 },
{ RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_3,
RADIO_RESP_GET_CELL_INFO_LIST_1_2 },
{ RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_4,
RADIO_RESP_GET_CELL_INFO_LIST_1_4 },
/*
{ RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_5,
RADIO_RESP_GET_CELL_INFO_LIST_1_5 },
{ RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_COUNT,
RADIO_RESP_GET_CELL_INFO_LIST_1_5 },
*/
{ RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_NONE,
RADIO_RESP_NONE },
{ RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_0,
RADIO_RESP_GET_CURRENT_CALLS },
{ RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_1,
RADIO_RESP_GET_CURRENT_CALLS },
{ RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_2,
RADIO_RESP_GET_CURRENT_CALLS_1_2 },
{ RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_3,
RADIO_RESP_GET_CURRENT_CALLS_1_2 },
{ RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_4,
RADIO_RESP_GET_CURRENT_CALLS_1_2 },
{ RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_COUNT,
RADIO_RESP_GET_CURRENT_CALLS_1_2 },
{ RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_NONE,
RADIO_RESP_NONE },
{ RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_0,
RADIO_RESP_GET_SIGNAL_STRENGTH },
{ RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_1,
RADIO_RESP_GET_SIGNAL_STRENGTH },
{ RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_2,
RADIO_RESP_GET_SIGNAL_STRENGTH_1_2 },
{ RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_3,
RADIO_RESP_GET_SIGNAL_STRENGTH_1_2 },
{ RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_4,
RADIO_RESP_GET_SIGNAL_STRENGTH_1_2 },
{ RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_COUNT,
RADIO_RESP_GET_SIGNAL_STRENGTH_1_2 },
{ RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_NONE,
RADIO_RESP_NONE },
{ RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_0,
RADIO_RESP_GET_VOICE_REGISTRATION_STATE },
{ RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_1,
RADIO_RESP_GET_VOICE_REGISTRATION_STATE },
{ RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_2,
RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2 },
{ RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_3,
RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2 },
{ RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_4,
RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2 },
{ RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_COUNT,
RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2 },
{ RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_NONE,
RADIO_RESP_NONE },
{ RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_0,
RADIO_RESP_GET_DATA_REGISTRATION_STATE },
{ RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_1,
RADIO_RESP_GET_DATA_REGISTRATION_STATE },
{ RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_2,
RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_2 },
{ RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_3,
RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_2 },
{ RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_4,
RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_4 },
{ RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_COUNT,
RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_4 },
{ RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_NONE,
RADIO_RESP_NONE },
{ RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_0,
RADIO_RESP_GET_DATA_CALL_LIST },
{ RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_1,
RADIO_RESP_GET_DATA_CALL_LIST },
{ RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_2,
RADIO_RESP_GET_DATA_CALL_LIST },
{ RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_3,
RADIO_RESP_GET_DATA_CALL_LIST },
{ RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_4,
RADIO_RESP_GET_DATA_CALL_LIST_1_4 },
/*
{ RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_5,
RADIO_RESP_GET_DATA_CALL_LIST_1_5 },
{ RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_COUNT,
RADIO_RESP_GET_DATA_CALL_LIST_1_5 },
*/
{ RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_NONE,
RADIO_RESP_NONE }
};
int i;
for (i = 0; i < G_N_ELEMENTS(tests); i++) {
g_assert_cmpint(radio_req_resp2(tests[i].req, tests[i].iface), ==,
tests[i].resp);
}
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/util/"
#define TEST_(t) TEST_PREFIX t
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_("req_name"), test_req_name);
g_test_add_func(TEST_("resp_name"), test_resp_name);
g_test_add_func(TEST_("ind_name"), test_ind_name);
g_test_add_func(TEST_("req_resp"), test_req_resp);
g_test_add_func(TEST_("req_resp2"), test_req_resp2);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/