[gbinder-radio] Added RadioConfig API. JB#56824

Simplifies talking to IRadioConfig binder service.
This commit is contained in:
Slava Monich
2022-01-08 20:46:00 +02:00
parent 0af836aa7a
commit b50d08ddd9
22 changed files with 2536 additions and 112 deletions

View File

@@ -49,6 +49,7 @@ LIB = $(LIB_NAME).a
SRC = \
radio_base.c \
radio_client.c \
radio_config.c \
radio_instance.c \
radio_registry.c \
radio_request.c \

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-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -62,11 +62,11 @@ struct radio_instance {
gboolean connected; /* rilConnected received */
};
typedef enum radio_instance_priority {
RADIO_INSTANCE_PRIORITY_LOWEST,
RADIO_INSTANCE_PRIORITY_DEFAULT = 2,
RADIO_INSTANCE_PRIORITY_HIGHEST = 7
} RADIO_INSTANCE_PRIORITY; /* Since 1.4.3 */
/* 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
@@ -229,7 +229,7 @@ radio_instance_add_request_observer(
gulong
radio_instance_add_request_observer_with_priority(
RadioInstance* radio,
RADIO_INSTANCE_PRIORITY priority,
RADIO_OBSERVER_PRIORITY priority,
RADIO_REQ code,
RadioRequestObserverFunc func,
gpointer user_data); /* Since 1.4.3 */
@@ -244,7 +244,7 @@ radio_instance_add_response_observer(
gulong
radio_instance_add_response_observer_with_priority(
RadioInstance* radio,
RADIO_INSTANCE_PRIORITY priority,
RADIO_OBSERVER_PRIORITY priority,
RADIO_RESP code,
RadioResponseObserverFunc func,
gpointer user_data); /* Since 1.4.3 */
@@ -259,7 +259,7 @@ radio_instance_add_indication_observer(
gulong
radio_instance_add_indication_observer_with_priority(
RadioInstance* radio,
RADIO_INSTANCE_PRIORITY priority,
RADIO_OBSERVER_PRIORITY priority,
RADIO_IND code,
RadioIndicationObserverFunc func,
gpointer user_data); /* Since 1.4.3 */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -39,7 +39,7 @@
/* This API exists since 1.4.3 */
#include <radio_types.h>
#include <radio_config_types.h>
/*
* Basic workflow
@@ -70,9 +70,11 @@ typedef enum radio_tx_status {
/*
* RadioRequestCompleteFunc
* RadioConfigRequestCompleteFunc
*
* Invoked upon completion of each request. If an error occurs,
* resp is set to RADIO_RESP_NONE (zero) and args is NULL.
* 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
@@ -92,6 +94,16 @@ void
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
*
@@ -110,7 +122,7 @@ gboolean
(*RadioRequestRetryFunc)(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_RESP resp,
guint32 resp, /* Was RADIO_RESP before 1.4.6 */
RADIO_ERROR error,
const GBinderReader* args,
void* user_data);
@@ -119,7 +131,7 @@ RadioRequest*
radio_request_new(
RadioClient* client,
RADIO_REQ code,
GBinderWriter* writer, /* NULL if serial is the only arg */
GBinderWriter* args, /* NULL if serial is the only arg */
RadioRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
@@ -129,12 +141,22 @@ RadioRequest*
radio_request_new2(
RadioRequestGroup* group,
RADIO_REQ code,
GBinderWriter* writer, /* NULL if serial is the only arg */
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);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021 Open Mobile Platform LLC.
*
* You may use this file under the terms of the BSD license as follows:
@@ -43,6 +43,7 @@
G_BEGIN_DECLS
typedef struct radio_client RadioClient;
typedef struct radio_config RadioConfig;
typedef struct radio_instance RadioInstance;
typedef struct radio_registry RadioRegistry;
typedef struct radio_request RadioRequest;
@@ -64,6 +65,12 @@ typedef enum radio_interface {
RADIO_INTERFACE_COUNT
} RADIO_INTERFACE; /* Since 1.2.0 */
typedef enum radio_observer_priority {
RADIO_OBSERVER_PRIORITY_LOWEST,
RADIO_OBSERVER_PRIORITY_DEFAULT = 2,
RADIO_OBSERVER_PRIORITY_HIGHEST = 7
} RADIO_OBSERVER_PRIORITY; /* Since 1.4.6 */
#define RADIO_IFACE_PREFIX "android.hardware.radio@"
#define RADIO_IFACE "IRadio"
#define RADIO_RESPONSE_IFACE "IRadioResponse"
@@ -93,6 +100,19 @@ typedef enum radio_interface {
#define RADIO_ALIGNED(x) __attribute__ ((aligned(x)))
typedef enum radio_resp_type {
RADIO_RESP_SOLICITED,
RADIO_RESP_SOLICITED_ACK,
RADIO_RESP_SOLICITED_ACK_EXP
} RADIO_RESP_TYPE;
G_STATIC_ASSERT(sizeof(RADIO_RESP_TYPE) == 4);
typedef enum radio_ind_type {
RADIO_IND_UNSOLICITED,
RADIO_IND_ACK_EXP
} RADIO_IND_TYPE;
G_STATIC_ASSERT(sizeof(RADIO_IND_TYPE) == 4);
typedef enum radio_error {
RADIO_ERROR_NONE = 0,
RADIO_ERROR_RADIO_NOT_AVAILABLE = 1,
@@ -181,19 +201,6 @@ typedef enum radio_error {
} RADIO_ERROR; /* Since 1.4.3 */
G_STATIC_ASSERT(sizeof(RADIO_ERROR) == 4);
typedef enum radio_resp_type {
RADIO_RESP_SOLICITED,
RADIO_RESP_SOLICITED_ACK,
RADIO_RESP_SOLICITED_ACK_EXP
} RADIO_RESP_TYPE;
G_STATIC_ASSERT(sizeof(RADIO_RESP_TYPE) == 4);
typedef enum radio_ind_type {
RADIO_IND_UNSOLICITED,
RADIO_IND_ACK_EXP
} RADIO_IND_TYPE;
G_STATIC_ASSERT(sizeof(RADIO_IND_TYPE) == 4);
typedef enum radio_state {
RADIO_STATE_OFF = 0,
RADIO_STATE_UNAVAILABLE = 1,
@@ -1221,8 +1228,6 @@ typedef struct radio_data_call_1_4 {
} RADIO_ALIGNED(8) RadioDataCall_1_4; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RadioDataCall_1_4) == 112);
#define DATA_CALL_VERSION (11)
typedef struct radio_sms_write_args {
gint32 status RADIO_ALIGNED(4);
GBinderHidlString pdu RADIO_ALIGNED(8);
@@ -2029,6 +2034,7 @@ typedef enum radio_req {
RADIO_1_4_REQ_LAST = RADIO_REQ_GET_SIGNAL_STRENGTH_1_4
#undef RADIO_REQ_
} RADIO_REQ;
G_STATIC_ASSERT(sizeof(RADIO_REQ) == 4);
typedef enum radio_resp {
RADIO_RESP_ANY = 0,
@@ -2067,6 +2073,7 @@ typedef enum radio_resp {
RADIO_1_4_RESP_LAST = RADIO_RESP_GET_SIGNAL_STRENGTH_1_4
#undef RADIO_RESP_
} RADIO_RESP;
G_STATIC_ASSERT(sizeof(RADIO_RESP) == 4);
/* These identifiers were shortened in 1.4.3 */
#define RADIO_RESP_GET_CELL_INFO_LIST_RESPONSE_1_4 \
@@ -2109,6 +2116,11 @@ typedef enum radio_ind {
RADIO_1_4_IND_LAST = RADIO_IND_CURRENT_SIGNAL_STRENGTH_1_4 /* Since 1.2.5 */
#undef RADIO_IND_
} RADIO_IND;
G_STATIC_ASSERT(sizeof(RADIO_IND) == 4);
/* Legacy macro. Ignore it */
#define DATA_CALL_VERSION (11)
/* Logging */

1000
src/radio_config.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -38,7 +38,7 @@
#include "radio_instance_p.h"
#include "radio_registry_p.h"
#include "radio_util.h"
#include "radio_util_p.h"
#include "radio_log.h"
#include <gbinder.h>
@@ -69,22 +69,15 @@ struct radio_instance_priv {
G_DEFINE_TYPE(RadioInstance, radio_instance, G_TYPE_OBJECT)
G_STATIC_ASSERT(RADIO_INSTANCE_PRIORITY_LOWEST == 0);
G_STATIC_ASSERT(RADIO_INSTANCE_PRIORITY_HIGHEST == 7);
#define FOREACH_PRIORITY(p) p(0) p(1) p(2) p(3) p(4) p(5) p(6) p(7)
#define RADIO_INSTANCE_PRIORITY_INDEX(p) ((p) - RADIO_INSTANCE_PRIORITY_LOWEST)
#define RADIO_INSTANCE_PRIORITY_COUNT \
(RADIO_INSTANCE_PRIORITY_INDEX(RADIO_INSTANCE_PRIORITY_HIGHEST) + 1)
typedef enum radio_instance_signal {
#define SIGNAL_INDEX(x) SIGNAL_OBSERVE_REQUEST_##x,
FOREACH_PRIORITY(SIGNAL_INDEX)
FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
#undef SIGNAL_INDEX
#define SIGNAL_INDEX(x) SIGNAL_OBSERVE_RESPONSE_##x,
FOREACH_PRIORITY(SIGNAL_INDEX)
FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
#undef SIGNAL_INDEX
#define SIGNAL_INDEX(x) SIGNAL_OBSERVE_INDICATION_##x,
FOREACH_PRIORITY(SIGNAL_INDEX)
FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
#undef SIGNAL_INDEX
SIGNAL_HANDLE_RESPONSE,
SIGNAL_HANDLE_INDICATION,
@@ -97,21 +90,21 @@ typedef enum radio_instance_signal {
static const char* radio_instance_signal_observe_request_name[] = {
#define SIGNAL_NAME(x) "radio-instance-observe-request-" #x,
FOREACH_PRIORITY(SIGNAL_NAME)
FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
#undef SIGNAL_NAME
NULL
};
static const char* radio_instance_signal_observe_response_name[] = {
#define SIGNAL_NAME(x) "radio-instance-observe-response-" #x,
FOREACH_PRIORITY(SIGNAL_NAME)
FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
#undef SIGNAL_NAME
NULL
};
static const char* radio_instance_signal_observe_indication_name[] = {
#define SIGNAL_NAME(x) "radio-instance-observe-indication-" #x,
FOREACH_PRIORITY(SIGNAL_NAME)
FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
#undef SIGNAL_NAME
NULL
};
@@ -248,20 +241,6 @@ radio_instance_resp_quark(
return q;
}
static
guint
radio_instance_priority_index(
RADIO_INSTANCE_PRIORITY priority)
{
if (priority < RADIO_INSTANCE_PRIORITY_LOWEST) {
return 0;
} else if (priority > RADIO_INSTANCE_PRIORITY_HIGHEST) {
return RADIO_INSTANCE_PRIORITY_COUNT - 1;
} else {
return priority - RADIO_INSTANCE_PRIORITY_LOWEST;
}
}
static
void
radio_instance_notify_request_observers(
@@ -272,7 +251,7 @@ radio_instance_notify_request_observers(
GQuark quark = 0;
int i;
for (i = RADIO_INSTANCE_PRIORITY_COUNT - 1; i >= 0; i--) {
for (i = RADIO_OBSERVER_PRIORITY_COUNT - 1; i >= 0; i--) {
guint id = radio_instance_signals[SIGNAL_OBSERVE_REQUEST_0 + i];
if (id) {
@@ -309,14 +288,14 @@ radio_instance_indication(
const GQuark quark = radio_instance_ind_quark(self, code);
const guint* signals = radio_instance_signals +
SIGNAL_OBSERVE_INDICATION_0;
int p = RADIO_INSTANCE_PRIORITY_HIGHEST;
int p = RADIO_OBSERVER_PRIORITY_HIGHEST;
gboolean handled = FALSE;
/* High-priority observers are notified first */
for (; p > RADIO_INSTANCE_PRIORITY_DEFAULT; p--) {
if (signals[RADIO_INSTANCE_PRIORITY_INDEX(p)]) {
for (; p > RADIO_OBSERVER_PRIORITY_DEFAULT; p--) {
if (signals[RADIO_OBSERVER_PRIORITY_INDEX(p)]) {
g_signal_emit(self, signals
[RADIO_INSTANCE_PRIORITY_INDEX(p)],
[RADIO_OBSERVER_PRIORITY_INDEX(p)],
quark, code, type, &reader);
}
}
@@ -340,10 +319,10 @@ radio_instance_indication(
quark, code, type, &reader, &handled);
/* And then remaining observers in their priority order */
for (; p >= RADIO_INSTANCE_PRIORITY_LOWEST; p--) {
if (signals[RADIO_INSTANCE_PRIORITY_INDEX(p)]) {
for (; p >= RADIO_OBSERVER_PRIORITY_LOWEST; p--) {
if (signals[RADIO_OBSERVER_PRIORITY_INDEX(p)]) {
g_signal_emit(self, signals
[RADIO_INSTANCE_PRIORITY_INDEX(p)],
[RADIO_OBSERVER_PRIORITY_INDEX(p)],
quark, code, type, &reader);
}
}
@@ -402,14 +381,14 @@ radio_instance_response(
const GQuark quark = radio_instance_resp_quark(self, code);
const guint* signals = radio_instance_signals +
SIGNAL_OBSERVE_RESPONSE_0;
int p = RADIO_INSTANCE_PRIORITY_HIGHEST;
int p = RADIO_OBSERVER_PRIORITY_HIGHEST;
gboolean handled = FALSE;
/* High-priority observers are notified first */
for (; p > RADIO_INSTANCE_PRIORITY_DEFAULT; p--) {
if (signals[RADIO_INSTANCE_PRIORITY_INDEX(p)]) {
for (; p > RADIO_OBSERVER_PRIORITY_DEFAULT; p--) {
if (signals[RADIO_OBSERVER_PRIORITY_INDEX(p)]) {
g_signal_emit(self, signals
[RADIO_INSTANCE_PRIORITY_INDEX(p)],
[RADIO_OBSERVER_PRIORITY_INDEX(p)],
quark, code, info, &reader);
}
}
@@ -420,10 +399,10 @@ radio_instance_response(
quark, code, info, &reader, &handled);
/* And then remaining observers in their priority order */
for (; p >= RADIO_INSTANCE_PRIORITY_LOWEST; p--) {
if (signals[RADIO_INSTANCE_PRIORITY_INDEX(p)]) {
for (; p >= RADIO_OBSERVER_PRIORITY_LOWEST; p--) {
if (signals[RADIO_OBSERVER_PRIORITY_INDEX(p)]) {
g_signal_emit(self, signals
[RADIO_INSTANCE_PRIORITY_INDEX(p)],
[RADIO_OBSERVER_PRIORITY_INDEX(p)],
quark, code, info, &reader);
}
}
@@ -1041,19 +1020,19 @@ radio_instance_add_request_observer(
gpointer user_data) /* Since 1.4.3 */
{
return radio_instance_add_request_observer_with_priority(self,
RADIO_INSTANCE_PRIORITY_DEFAULT, code, func, user_data);
RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
}
gulong
radio_instance_add_request_observer_with_priority(
RadioInstance* self,
RADIO_INSTANCE_PRIORITY priority,
RADIO_OBSERVER_PRIORITY priority,
RADIO_REQ code,
RadioRequestObserverFunc func,
gpointer user_data) /* Since 1.4.3 */
{
if (G_LIKELY(self) && G_LIKELY(func)) {
const guint index = radio_instance_priority_index(priority);
const guint index = radio_observer_priority_index(priority);
const RADIO_INSTANCE_SIGNAL sig = SIGNAL_OBSERVE_REQUEST_0 + index;
/* Register signal on demand */
@@ -1082,19 +1061,19 @@ radio_instance_add_response_observer(
gpointer user_data)
{
return radio_instance_add_response_observer_with_priority(self,
RADIO_INSTANCE_PRIORITY_DEFAULT, code, func, user_data);
RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
}
gulong
radio_instance_add_response_observer_with_priority(
RadioInstance* self,
RADIO_INSTANCE_PRIORITY priority,
RADIO_OBSERVER_PRIORITY priority,
RADIO_RESP code,
RadioResponseObserverFunc func,
gpointer user_data) /* Since 1.4.3 */
{
if (G_LIKELY(self) && G_LIKELY(func)) {
const guint index = radio_instance_priority_index(priority);
const guint index = radio_observer_priority_index(priority);
const RADIO_INSTANCE_SIGNAL sig = SIGNAL_OBSERVE_RESPONSE_0 + index;
/* Register signal on demand */
@@ -1123,19 +1102,19 @@ radio_instance_add_indication_observer(
gpointer user_data)
{
return radio_instance_add_indication_observer_with_priority(self,
RADIO_INSTANCE_PRIORITY_DEFAULT, code, func, user_data);
RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
}
gulong
radio_instance_add_indication_observer_with_priority(
RadioInstance* self,
RADIO_INSTANCE_PRIORITY priority,
RADIO_OBSERVER_PRIORITY priority,
RADIO_IND code,
RadioIndicationObserverFunc func,
gpointer user_data) /* Since 1.4.3 */
{
if (G_LIKELY(self) && G_LIKELY(func)) {
const guint index = radio_instance_priority_index(priority);
const guint index = radio_observer_priority_index(priority);
const RADIO_INSTANCE_SIGNAL sig = SIGNAL_OBSERVE_INDICATION_0 + index;
/* Register signal on demand */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -134,7 +134,7 @@ radio_request_object_new(
RadioRequestGroup* group,
RADIO_REQ code,
GBinderWriter* writer,
RadioRequestCompleteFunc complete,
RadioRequestGenericCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
{
@@ -201,7 +201,8 @@ radio_request_new(
void* user_data)
{
return client ? radio_request_object_new(RADIO_BASE(client), NULL,
code, writer, complete, destroy, user_data) : NULL;
code, writer, (RadioRequestGenericCompleteFunc) complete,
destroy, user_data) : NULL;
}
RadioRequest*
@@ -214,7 +215,22 @@ radio_request_new2(
void* user_data)
{
return group ? radio_request_object_new(RADIO_BASE(group->client), group,
code, writer, complete, destroy, user_data) : NULL;
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*

View File

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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -107,11 +107,21 @@ typedef enum radio_request_state {
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;
RADIO_REQ code;
guint32 code;
GBinderLocalRequest* args;
RadioRequestCompleteFunc complete;
RadioRequestGenericCompleteFunc complete;
RadioRequestRetryFunc retry;
void* user_data;
guint32 serial; /* Immutable, generated at creation time */

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021-2022 Jolla Ltd.
* Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -46,6 +46,14 @@ typedef struct radio_base RadioBase;
/* 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)
#endif /* RADIO_TYPES_PRIVATE_H */
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2021 Jolla Ltd.
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2022 Jolla Ltd.
* Copyright (C) 2018-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)

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

View File

@@ -5,6 +5,7 @@
all:
%:
@$(MAKE) -C unit_client $*
@$(MAKE) -C unit_config $*
@$(MAKE) -C unit_instance $*
@$(MAKE) -C unit_registry $*
@$(MAKE) -C unit_util $*

View File

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

View File

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

View File

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

View File

@@ -5,6 +5,7 @@
TESTS="\
unit_client \
unit_config \
unit_instance \
unit_registry \
unit_util"

View File

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

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