diff --git a/include/radio_config.h b/include/radio_config.h index d303d1e..a2f6020 100644 --- a/include/radio_config.h +++ b/include/radio_config.h @@ -40,6 +40,7 @@ /* This API exists since 1.4.6 */ #include +#include G_BEGIN_DECLS @@ -83,6 +84,12 @@ radio_config_new_with_version( RADIO_CONFIG_INTERFACE max_version) G_GNUC_WARN_UNUSED_RESULT; +RadioConfig* +radio_config_new_with_version_and_interface_type( + RADIO_CONFIG_INTERFACE max_version, + RADIO_INTERFACE_TYPE interface_type) + G_GNUC_WARN_UNUSED_RESULT; /* Since 1.6.0 */ + RadioConfig* radio_config_ref( RadioConfig* config); @@ -95,6 +102,10 @@ gboolean radio_config_dead( RadioConfig* config); +RADIO_INTERFACE_TYPE +radio_config_interface_type( + RadioConfig* self); /* Since 1.6.0 */ + RADIO_CONFIG_INTERFACE radio_config_interface( RadioConfig* config); diff --git a/include/radio_config_aidl_types.h b/include/radio_config_aidl_types.h new file mode 100644 index 0000000..e09a45f --- /dev/null +++ b/include/radio_config_aidl_types.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2024 Jollyboys Ltd + * + * 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_AIDL_TYPES_H +#define RADIO_CONFIG_AIDL_TYPES_H + +#include + +G_BEGIN_DECLS + +typedef enum radio_config_aidl_interface { + RADIO_CONFIG_AIDL_INTERFACE_NONE = -1, + RADIO_CONFIG_AIDL_INTERFACE_1, + RADIO_CONFIG_AIDL_INTERFACE_COUNT +} RADIO_CONFIG_AIDL_INTERFACE; + +#define RADIO_CONFIG_AIDL_INTERFACE_MAX (RADIO_CONFIG_AIDL_INTERFACE_COUNT - 1) + +#define RADIO_CONFIG_AIDL_INSTANCE "default" +#define RADIO_CONFIG_AIDL_IFACE_PREFIX "android.hardware.radio.config." +#define RADIO_CONFIG_AIDL_IFACE "IRadioConfig" +#define RADIO_CONFIG_AIDL_RESPONSE_IFACE "IRadioConfigResponse" +#define RADIO_CONFIG_AIDL_INDICATION_IFACE "IRadioConfigIndication" +#define RADIO_CONFIG_AIDL RADIO_CONFIG_AIDL_IFACE_PREFIX RADIO_CONFIG_AIDL_IFACE +#define RADIO_CONFIG_AIDL_FQNAME RADIO_CONFIG_AIDL "/" RADIO_CONFIG_AIDL_INSTANCE +#define RADIO_CONFIG_AIDL_RESPONSE RADIO_CONFIG_AIDL_IFACE_PREFIX RADIO_CONFIG_AIDL_RESPONSE_IFACE +#define RADIO_CONFIG_AIDL_INDICATION RADIO_CONFIG_AIDL_IFACE_PREFIX RADIO_CONFIG_AIDL_INDICATION_IFACE + +/* Types defined in android.hardware.radio.config package */ + +/* PhoneCapability */ +typedef struct radio_aidl_phone_capability { + guint8 maxActiveData RADIO_ALIGNED(4); + guint8 maxActiveInternetData RADIO_ALIGNED(4); + guint8 isInternetLingeringSupported RADIO_ALIGNED(4); + struct { + guint32 length; + guint8 data[]; + } logicalModemList; +} RadioAidlPhoneCapability; + +/* SimPortInfo */ +typedef struct radio_aidl_sim_port_info { + struct { + guint32 length; + gchar data[]; + } iccId; + gint32 logicalSlotId; + gboolean portActive; +} RadioAidlSimPortInfo; + +/* SimSlotStatus */ +typedef struct radio_aidl_sim_slot_status { + RADIO_CARD_STATE cardState; + GString* atr; + GString* eid; + struct { + guint32 length; + RadioAidlSimPortInfo data[]; + } portInfo; +} RadioAidlSimSlotStatus; + +/* Transaction codes */ + +/* c(req,resp,Name,CALL_NAME) */ +#define RADIO_CONFIG_AIDL_CALL_1(c) \ + c(1,1,getHalDeviceCapabilities,GET_HAL_DEVICE_CAPABILITIES) \ + c(2,2,getNumOfLiveModems,GET_NUM_OF_LIVE_MODEMS) \ + c(3,3,getPhoneCapability,GET_PHONE_CAPABILITY) \ + c(4,4,getSimSlotsStatus,GET_SIM_SLOTS_STATUS) \ + c(5,5,setNumOfLiveModems,SET_NUM_OF_LIVE_MODEMS) \ + c(6,6,setPreferredDataModem,SET_PREFERRED_DATA_MODEM) \ + c(8,7,setSimSlotsMapping,SET_SIM_SLOTS_MAPPING) \ + +/* i(code,Name,IND_NAME) */ +#define RADIO_CONFIG_AIDL_IND_1(i) \ + i(1,simSlotsStatusChanged,SIM_SLOTS_STATUS_CHANGED) \ + +typedef enum radio_aidl_config_req { + RADIO_CONFIG_AIDL_REQ_ANY = 0, + RADIO_CONFIG_AIDL_REQ_NONE = 0, +#define RADIO_CONFIG_AIDL_REQ_(req,resp,Name,NAME) RADIO_CONFIG_AIDL_REQ_##NAME = req, + + /* android.hardware.radio.config.IRadioConfig v1 */ + RADIO_CONFIG_AIDL_REQ_SET_RESPONSE_FUNCTIONS = 7, /* setResponseFunctions */ + RADIO_CONFIG_AIDL_CALL_1(RADIO_CONFIG_AIDL_REQ_) + RADIO_CONFIG_AIDL_1_REQ_LAST = RADIO_CONFIG_AIDL_REQ_SET_SIM_SLOTS_MAPPING, + +#undef RADIO_CONFIG_AIDL_REQ_ +} RADIO_CONFIG_AIDL_REQ; +G_STATIC_ASSERT(sizeof(RADIO_CONFIG_AIDL_REQ) == 4); + +typedef enum radio_aidl_config_resp { + RADIO_CONFIG_AIDL_RESP_ANY = 0, + RADIO_CONFIG_AIDL_RESP_NONE = 0, +#define RADIO_CONFIG_AIDL_RESP_(req,resp,Name,NAME) RADIO_CONFIG_AIDL_RESP_##NAME = resp, + + /* android.hardware.radio.config.IRadioConfigResponse v1 */ + RADIO_CONFIG_AIDL_CALL_1(RADIO_CONFIG_AIDL_RESP_) + RADIO_CONFIG_AIDL_1_RESP_LAST = RADIO_CONFIG_AIDL_RESP_SET_SIM_SLOTS_MAPPING, + +#undef RADIO_CONFIG_AIDL_RESP_ +} RADIO_CONFIG_AIDL_RESP; +G_STATIC_ASSERT(sizeof(RADIO_CONFIG_AIDL_RESP) == 4); + +typedef enum radio_aidl_config_ind { + RADIO_CONFIG_AIDL_IND_ANY = 0, + RADIO_CONFIG_AIDL_IND_NONE = 0, +#define RADIO_CONFIG_AIDL_IND_(code,Name,NAME) RADIO_CONFIG_AIDL_IND_##NAME = code, + + /* android.hardware.radio.config.IRadioConfigIndication v1 */ + RADIO_CONFIG_AIDL_IND_1(RADIO_CONFIG_AIDL_IND_) + RADIO_CONFIG_AIDL_1_IND_LAST = RADIO_CONFIG_AIDL_IND_SIM_SLOTS_STATUS_CHANGED, + +#undef RADIO_CONFIG_AIDL_IND_ +} RADIO_CONFIG_AIDL_IND; +G_STATIC_ASSERT(sizeof(RADIO_CONFIG_AIDL_IND) == 4); + +G_END_DECLS + +#endif /* RADIO_CONFIG_AIDL_TYPES_H */ + +/* + * Local Variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/radio_types.h b/include/radio_types.h index c86bc4f..c99d2fa 100644 --- a/include/radio_types.h +++ b/include/radio_types.h @@ -66,6 +66,12 @@ typedef enum radio_interface { RADIO_INTERFACE_COUNT } RADIO_INTERFACE; /* Since 1.2.0 */ +typedef enum radio_interface_type { + RADIO_INTERFACE_TYPE_NONE, + RADIO_INTERFACE_TYPE_HIDL, + RADIO_INTERFACE_TYPE_AIDL, +} RADIO_INTERFACE_TYPE; /* Since 1.6.0 */ + typedef enum radio_observer_priority { RADIO_OBSERVER_PRIORITY_LOWEST, RADIO_OBSERVER_PRIORITY_DEFAULT = 2, diff --git a/src/radio_config.c b/src/radio_config.c index 212196a..3d9d29e 100644 --- a/src/radio_config.c +++ b/src/radio_config.c @@ -56,6 +56,7 @@ typedef struct radio_config { GBinderRemoteObject* remote; GBinderLocalObject* response; GBinderLocalObject* indication; + RADIO_INTERFACE_TYPE interface_type; RADIO_CONFIG_INTERFACE version; GHashTable* req_quarks; GHashTable* resp_quarks; @@ -121,6 +122,12 @@ static const GBinderClientIfaceInfo radio_config_iface_info[] = { G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_iface_info) == RADIO_CONFIG_INTERFACE_COUNT); +static const GBinderClientIfaceInfo radio_config_aidl_iface_info[] = { + {RADIO_CONFIG_AIDL, RADIO_CONFIG_1_1_REQ_LAST } +}; +G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_aidl_iface_info) == + RADIO_CONFIG_AIDL_INTERFACE_COUNT); + static const char* const radio_config_indication_ifaces[] = { RADIO_CONFIG_INDICATION_1_2, RADIO_CONFIG_INDICATION_1_1, @@ -130,6 +137,13 @@ static const char* const radio_config_indication_ifaces[] = { G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_indication_ifaces) == RADIO_CONFIG_INTERFACE_COUNT + 1); +static const char* const radio_config_aidl_indication_ifaces[] = { + RADIO_CONFIG_AIDL_INDICATION, + NULL +}; +G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_aidl_indication_ifaces) == + RADIO_CONFIG_AIDL_INTERFACE_COUNT + 1); + static const char* const radio_config_response_ifaces[] = { RADIO_CONFIG_RESPONSE_1_2, RADIO_CONFIG_RESPONSE_1_1, @@ -139,7 +153,15 @@ static const char* const radio_config_response_ifaces[] = { G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_response_ifaces) == RADIO_CONFIG_INTERFACE_COUNT + 1); +static const char* const radio_config_aidl_response_ifaces[] = { + RADIO_CONFIG_AIDL_RESPONSE, + NULL +}; +G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_aidl_response_ifaces) == + RADIO_CONFIG_AIDL_INTERFACE_COUNT + 1); + typedef struct radio_config_interface_desc { + RADIO_INTERFACE_TYPE interface_type; RADIO_CONFIG_INTERFACE version; const char* fqname; const char* radio_iface; @@ -150,6 +172,7 @@ typedef struct radio_config_interface_desc { #define RADIO_CONFIG_INTERFACE_INDEX(x) (RADIO_CONFIG_INTERFACE_COUNT - x - 1) #define RADIO_CONFIG_INTERFACE_DESC(v) \ + RADIO_INTERFACE_TYPE_HIDL, \ RADIO_CONFIG_INTERFACE_##v, \ RADIO_CONFIG_##v##_FQNAME, \ RADIO_CONFIG_##v, \ @@ -166,9 +189,24 @@ static const RadioConfigInterfaceDesc radio_config_interfaces[] = { G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_interfaces) == RADIO_CONFIG_INTERFACE_COUNT); +static const RadioConfigInterfaceDesc radio_config_aidl_interfaces[] = { + { + RADIO_INTERFACE_TYPE_AIDL, + RADIO_CONFIG_AIDL_INTERFACE_1, + RADIO_CONFIG_AIDL_FQNAME, + RADIO_CONFIG_AIDL, + radio_config_aidl_indication_ifaces, + radio_config_aidl_response_ifaces, + } +}; +G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_aidl_interfaces) == + RADIO_CONFIG_AIDL_INTERFACE_COUNT); + /* Must have a separate instance for each interface version */ static RadioConfig* radio_config_instance[RADIO_CONFIG_INTERFACE_COUNT] = { NULL }; +static RadioConfig* radio_config_aidl_instance[RADIO_CONFIG_AIDL_INTERFACE_COUNT] = + { NULL }; typedef struct radio_config_call { RadioRequest* req; @@ -205,18 +243,31 @@ radio_config_call_complete( static const char* radio_config_known_req_name( + RadioConfig* self, RADIO_CONFIG_REQ req) { - switch (req) { - case RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS: return "setResponseFunctions"; + if (!G_LIKELY(self) || self->interface_type == RADIO_INTERFACE_TYPE_HIDL) { + switch (req) { + case RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS: return "setResponseFunctions"; #define RADIO_CONFIG_REQ_(req,resp,Name,NAME) \ - case RADIO_CONFIG_REQ_##NAME: return #Name; - RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_REQ_) - RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_REQ_) - /* 1.2 defines no new requests */ + case RADIO_CONFIG_REQ_##NAME: return #Name; + RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_REQ_) + RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_REQ_) + /* 1.2 defines no new requests */ #undef RADIO_CONFIG_REQ_ - case RADIO_CONFIG_REQ_ANY: - break; + case RADIO_CONFIG_REQ_ANY: + break; + } + } else if (self->interface_type == RADIO_INTERFACE_TYPE_AIDL) { + switch ((RADIO_CONFIG_AIDL_REQ)req) { + case RADIO_CONFIG_AIDL_REQ_SET_RESPONSE_FUNCTIONS: return "setResponseFunctions"; +#define RADIO_CONFIG_AIDL_REQ_(req,resp,Name,NAME) \ + case RADIO_CONFIG_AIDL_REQ_##NAME: return #Name; + RADIO_CONFIG_AIDL_CALL_1(RADIO_CONFIG_AIDL_REQ_) +#undef RADIO_CONFIG_AIDL_REQ_ + case RADIO_CONFIG_AIDL_REQ_ANY: + break; + } } return NULL; } @@ -224,18 +275,30 @@ radio_config_known_req_name( static const char* radio_config_known_resp_name( + RadioConfig* self, RADIO_CONFIG_RESP resp) { - switch (resp) { + if (!G_LIKELY(self) || self->interface_type == RADIO_INTERFACE_TYPE_HIDL) { + switch (resp) { #define RADIO_CONFIG_RESP_(req,resp,Name,NAME) \ - case RADIO_CONFIG_RESP_##NAME: return #Name "Response"; - RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_RESP_) - RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_RESP_) + case RADIO_CONFIG_RESP_##NAME: return #Name "Response"; + RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_RESP_) + RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_RESP_) #undef RADIO_CONFIG_RESP_ - case RADIO_CONFIG_RESP_GET_SIM_SLOTS_STATUS_1_2: - return "getSimSlotsStatusResponse_1_2"; - case RADIO_CONFIG_RESP_ANY: - break; + case RADIO_CONFIG_RESP_GET_SIM_SLOTS_STATUS_1_2: + return "getSimSlotsStatusResponse_1_2"; + case RADIO_CONFIG_RESP_ANY: + break; + } + } else if (self->interface_type == RADIO_INTERFACE_TYPE_AIDL) { + switch ((RADIO_CONFIG_AIDL_RESP)resp) { +#define RADIO_CONFIG_AIDL_RESP_(req,resp,Name,NAME) \ + case RADIO_CONFIG_AIDL_RESP_##NAME: return #Name "Response"; + RADIO_CONFIG_AIDL_CALL_1(RADIO_CONFIG_AIDL_RESP_) +#undef RADIO_CONFIG_AIDL_RESP_ + case RADIO_CONFIG_AIDL_RESP_ANY: + break; + } } return NULL; } @@ -243,17 +306,29 @@ radio_config_known_resp_name( static const char* radio_config_known_ind_name( + RadioConfig* self, RADIO_CONFIG_IND ind) { - switch (ind) { + if (!G_LIKELY(self) || self->interface_type == RADIO_INTERFACE_TYPE_HIDL) { + switch (ind) { #define RADIO_CONFIG_IND_(code,Name,NAME) \ - case RADIO_CONFIG_IND_##NAME: return #Name; - RADIO_CONFIG_IND_1_0(RADIO_CONFIG_IND_) - /* 1.1 defines no new indications */ - RADIO_CONFIG_IND_1_2(RADIO_CONFIG_IND_) + case RADIO_CONFIG_IND_##NAME: return #Name; + RADIO_CONFIG_IND_1_0(RADIO_CONFIG_IND_) + /* 1.1 defines no new indications */ + RADIO_CONFIG_IND_1_2(RADIO_CONFIG_IND_) #undef RADIO_CONFIG_IND_ - case RADIO_CONFIG_IND_ANY: - break; + case RADIO_CONFIG_IND_ANY: + break; + } + } else if (self->interface_type == RADIO_INTERFACE_TYPE_AIDL) { + switch ((RADIO_CONFIG_AIDL_IND)ind) { +#define RADIO_CONFIG_AIDL_IND_(code,Name,NAME) \ + case RADIO_CONFIG_AIDL_IND_##NAME: return #Name; + RADIO_CONFIG_AIDL_IND_1(RADIO_CONFIG_AIDL_IND_) +#undef RADIO_CONFIG_AIDL_IND_ + case RADIO_CONFIG_AIDL_IND_ANY: + break; + } } return NULL; } @@ -271,7 +346,7 @@ radio_config_req_quark( q = GPOINTER_TO_UINT(g_hash_table_lookup(self->req_quarks, key)); if (!q) { - const char* known = radio_config_known_req_name(req); + const char* known = radio_config_known_req_name(self, req); if (known) { q = g_quark_from_static_string(known); @@ -297,7 +372,7 @@ radio_config_resp_quark( q = GPOINTER_TO_UINT(g_hash_table_lookup(self->resp_quarks, key)); if (!q) { - const char* known = radio_config_known_resp_name(resp); + const char* known = radio_config_known_resp_name(self, resp); if (known) { q = g_quark_from_static_string(known); @@ -323,7 +398,7 @@ radio_config_ind_quark( q = GPOINTER_TO_UINT(g_hash_table_lookup(self->ind_quarks, key)); if (!q) { - const char* known = radio_config_known_ind_name(ind); + const char* known = radio_config_known_ind_name(self, ind); if (known) { q = g_quark_from_static_string(known); @@ -393,53 +468,64 @@ radio_config_response( { RadioConfig* self = THIS(user_data); const char* iface = gbinder_remote_request_interface(req); + const RadioResponseInfo* info = NULL; + GBinderReader args; + + gbinder_remote_request_init_reader(req, &args); if (gutil_strv_contains((GStrV*)radio_config_response_ifaces, iface)) { - GBinderReader args; - const RadioResponseInfo* info; - /* All responses must be one-way and have RadioResponseInfo */ - gbinder_remote_request_init_reader(req, &args); info = gbinder_reader_read_hidl_struct(&args, RadioResponseInfo); - GASSERT(flags & GBINDER_TX_FLAG_ONEWAY); - if (info) { - int p = RADIO_OBSERVER_PRIORITY_HIGHEST; - const GQuark quark = radio_config_resp_quark(self, code); - const guint* signals = radio_config_signals + - SIGNAL_OBSERVE_RESPONSE_0; - - radio_config_ref(self); - - /* High-priority observers get notified first */ - for (; p > RADIO_OBSERVER_PRIORITY_DEFAULT; p--) { - const int i = RADIO_OBSERVER_PRIORITY_INDEX(p); - - if (signals[i]) { - g_signal_emit(self, signals[i], quark, code, info, &args); - } - } - - /* Then the response is actually processed */ - if (!radio_base_handle_resp(&self->base, code, info, &args)) { - const char* name = radio_config_known_resp_name(code); - - /* Most likely this is a response to a cancelled request */ - GDEBUG("Ignoring IRadioConfig response [%08x] %u %s", - info->serial, code, name ? name : ""); - } - - /* Followed by the remaining observers in their priority order */ - for (; p >= RADIO_OBSERVER_PRIORITY_LOWEST; p--) { - const int i = RADIO_OBSERVER_PRIORITY_INDEX(p); - - if (signals[i]) { - g_signal_emit(self, signals[i], quark, code, info, &args); - } - } - radio_config_unref(self); - *status = GBINDER_STATUS_OK; - } + } else if (gutil_strv_contains((GStrV*)radio_config_aidl_response_ifaces, iface)) { + /* RadioResponseInfo has the same fields/padding between HIDL and AIDL */ + gsize out_size; + info = gbinder_reader_read_parcelable(&args, &out_size); + GASSERT(out_size == sizeof(RadioResponseInfo)); + } else { + GDEBUG("radio_config_response called on unknown interface %s", iface); + return NULL; } + + GASSERT(flags & GBINDER_TX_FLAG_ONEWAY); + + if (info) { + int p = RADIO_OBSERVER_PRIORITY_HIGHEST; + const GQuark quark = radio_config_resp_quark(self, code); + const guint* signals = radio_config_signals + + SIGNAL_OBSERVE_RESPONSE_0; + + radio_config_ref(self); + + /* High-priority observers get notified first */ + for (; p > RADIO_OBSERVER_PRIORITY_DEFAULT; p--) { + const int i = RADIO_OBSERVER_PRIORITY_INDEX(p); + + if (signals[i]) { + g_signal_emit(self, signals[i], quark, code, info, &args); + } + } + + /* Then the response is actually processed */ + if (!radio_base_handle_resp(&self->base, code, info, &args)) { + const char* name = radio_config_known_resp_name(self, code); + + /* Most likely this is a response to a cancelled request */ + GDEBUG("Ignoring IRadioConfig response [%08x] %u %s", + info->serial, code, name ? name : ""); + } + + /* Followed by the remaining observers in their priority order */ + for (; p >= RADIO_OBSERVER_PRIORITY_LOWEST; p--) { + const int i = RADIO_OBSERVER_PRIORITY_INDEX(p); + + if (signals[i]) { + g_signal_emit(self, signals[i], quark, code, info, &args); + } + } + radio_config_unref(self); + *status = GBINDER_STATUS_OK; + } + return NULL; } @@ -509,12 +595,12 @@ radio_config_create( GBinderLocalRequest* req; GBinderWriter writer; int status; + guint req_code = RADIO_CONFIG_REQ_NONE; radio_base_initialize(&self->base); + self->interface_type = desc->interface_type; self->version = desc->version; self->remote = gbinder_remote_object_ref(remote); - self->client = gbinder_client_new2(remote, radio_config_iface_info, - G_N_ELEMENTS(radio_config_iface_info)); self->indication = gbinder_servicemanager_new_local_object2(sm, desc->ind_ifaces, radio_config_indication, self); self->response = gbinder_servicemanager_new_local_object2(sm, @@ -522,14 +608,28 @@ radio_config_create( self->death_id = gbinder_remote_object_add_death_handler(remote, radio_config_died, self); + if (self->interface_type == RADIO_INTERFACE_TYPE_HIDL) { + self->client = gbinder_client_new2(remote, radio_config_iface_info, + G_N_ELEMENTS(radio_config_iface_info)); + req_code = RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS; + } else if (self->interface_type == RADIO_INTERFACE_TYPE_AIDL) { + self->client = gbinder_client_new2(remote, radio_config_aidl_iface_info, + G_N_ELEMENTS(radio_config_aidl_iface_info)); + req_code = RADIO_CONFIG_AIDL_REQ_SET_RESPONSE_FUNCTIONS; + + gbinder_local_object_set_stability(self->indication, GBINDER_STABILITY_VINTF); + gbinder_local_object_set_stability(self->response, GBINDER_STABILITY_VINTF); + } + GASSERT(self->client); + /* IRadioConfig::setResponseFunctions */ req = gbinder_client_new_request2(self->client, - RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS); + req_code); gbinder_local_request_init_writer(req, &writer); gbinder_writer_append_local_object(&writer, self->response); gbinder_writer_append_local_object(&writer, self->indication); gbinder_remote_reply_unref(gbinder_client_transact_sync_reply(self->client, - RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS, req, &status)); + req_code, req, &status)); GVERBOSE_("IRadioConfig::setResponseFunctions status %d", status); gbinder_local_request_unref(req); return self; @@ -550,20 +650,51 @@ RadioConfig* radio_config_new_with_version( RADIO_CONFIG_INTERFACE max_version) { - /* Validate the requested version to avoid out-of-bounds access */ - if (max_version < RADIO_CONFIG_INTERFACE_1_0) { - max_version = RADIO_CONFIG_INTERFACE_1_0; - } else if (max_version > RADIO_CONFIG_INTERFACE_MAX) { - max_version = RADIO_CONFIG_INTERFACE_MAX; + return radio_config_new_with_version_and_interface_type(max_version, + RADIO_INTERFACE_TYPE_HIDL); +} + +RadioConfig* +radio_config_new_with_version_and_interface_type( + RADIO_CONFIG_INTERFACE max_version, + RADIO_INTERFACE_TYPE interface_type) +{ + static RadioConfig** instances = NULL; + static const RadioConfigInterfaceDesc* interfaces = NULL; + gsize num_interfaces = 0; + const char* binder_device = GBINDER_DEFAULT_HWBINDER; + + if (interface_type == RADIO_INTERFACE_TYPE_HIDL) { + /* Validate the requested version to avoid out-of-bounds access */ + if (max_version < RADIO_CONFIG_INTERFACE_1_0) { + max_version = RADIO_CONFIG_INTERFACE_1_0; + } else if (max_version > RADIO_CONFIG_INTERFACE_MAX) { + max_version = RADIO_CONFIG_INTERFACE_MAX; + } + + instances = radio_config_instance; + interfaces = radio_config_interfaces; + num_interfaces = G_N_ELEMENTS(radio_config_interfaces); + } else if (interface_type == RADIO_INTERFACE_TYPE_AIDL) { + /* Only RADIO_CONFIG_AIDL_INTERFACE_1 is supported for now */ + max_version = RADIO_CONFIG_AIDL_INTERFACE_1; + + binder_device = GBINDER_DEFAULT_BINDER; + instances = radio_config_aidl_instance; + interfaces = radio_config_aidl_interfaces; + num_interfaces = G_N_ELEMENTS(radio_config_aidl_interfaces); + } else { + GINFO("Wrong interface_type %d (neither HIDL nor AIDL)", interface_type); + return NULL; } - if (radio_config_instance[max_version]) { + if (instances[max_version]) { /* The requested instance already exists */ - return radio_config_ref(radio_config_instance[max_version]); + return radio_config_ref(instances[max_version]); } else { - /* Assume /dev/hwbinder */ + /* Assume /dev/hwbinder for HIDL, /dev/binder for AIDL */ GBinderServiceManager* sm = - gbinder_servicemanager_new(GBINDER_DEFAULT_HWBINDER); + gbinder_servicemanager_new(binder_device); if (sm) { guint i; @@ -572,8 +703,8 @@ radio_config_new_with_version( RadioConfig* config = NULL; /* Find maximum available version not exceeding the requested one */ - for (i=0; iversion <= max_version) { obj = gbinder_servicemanager_get_service_sync(sm, desc->fqname, NULL); @@ -582,9 +713,8 @@ radio_config_new_with_version( * desc->version isn't necessarily equal to * max_version */ - if (radio_config_instance[desc->version]) { - config = radio_config_ref(radio_config_instance - [desc->version]); + if (instances[desc->version]) { + config = radio_config_ref(instances[desc->version]); } else { GINFO("Connected to %s", desc->fqname); config = radio_config_create(sm, obj, desc); @@ -596,9 +726,9 @@ radio_config_new_with_version( gbinder_servicemanager_unref(sm); if (config) { - radio_config_instance[desc->version] = config; + instances[desc->version] = config; g_object_weak_ref(G_OBJECT(config), radio_config_gone, - radio_config_instance + desc->version); + instances + desc->version); return config; } } @@ -632,6 +762,13 @@ radio_config_dead( return G_UNLIKELY(!self) || self->dead; } +RADIO_INTERFACE_TYPE +radio_config_interface_type( + RadioConfig* self) +{ + return G_LIKELY(self) ? self->interface_type : RADIO_INTERFACE_TYPE_NONE; +} + RADIO_CONFIG_INTERFACE radio_config_interface( RadioConfig* self) @@ -659,7 +796,7 @@ radio_config_req_name( RadioConfig* self, RADIO_CONFIG_REQ req) { - const char* known = radio_config_known_req_name(req); + const char* known = radio_config_known_req_name(self, req); if (known) { return known; @@ -678,7 +815,7 @@ radio_config_resp_name( RadioConfig* self, RADIO_CONFIG_RESP resp) { - const char* known = radio_config_known_resp_name(resp); + const char* known = radio_config_known_resp_name(self, resp); if (known) { return known; @@ -697,7 +834,7 @@ radio_config_ind_name( RadioConfig* self, RADIO_CONFIG_IND ind) { - const char* known = radio_config_known_ind_name(ind); + const char* known = radio_config_known_ind_name(self, ind); if (known) { return known; diff --git a/unit/common/test_gbinder_local_object.c b/unit/common/test_gbinder_local_object.c index a5ed346..1d90a7a 100644 --- a/unit/common/test_gbinder_local_object.c +++ b/unit/common/test_gbinder_local_object.c @@ -43,6 +43,7 @@ struct gbinder_local_object { char** ifaces; GBinderLocalTransactFunc txproc; void* user_data; + GBINDER_STABILITY_LEVEL stability; }; static const char hidl_base_interface[] = "android.hidl.base@1.0::IBase"; @@ -144,6 +145,16 @@ gbinder_local_object_drop( } } +void +gbinder_local_object_set_stability( + GBinderLocalObject* self, + GBINDER_STABILITY_LEVEL stability) +{ + if (self) { + self->stability = stability; + } +} + /* * Local Variables: * mode: C diff --git a/unit/common/test_gbinder_reader_writer.c b/unit/common/test_gbinder_reader_writer.c index 1465505..c4bb361 100644 --- a/unit/common/test_gbinder_reader_writer.c +++ b/unit/common/test_gbinder_reader_writer.c @@ -373,6 +373,24 @@ gbinder_reader_read_hidl_struct1( return NULL; } +const void* +gbinder_reader_read_parcelable( + GBinderReader* reader, + gsize* size) +{ + TestGBinderReader* self = test_gbinder_reader_cast(reader); + TestGBinderDataItem* item = self->item; + + if (item && item->type == DATA_TYPE_BUFFER) { + if (size) { + *size = item->data.blob.size; + } + self->item = item->next; + return item->data.blob.buf; + } + return NULL; +} + GBinderRemoteObject* gbinder_reader_read_object( GBinderReader* reader)