[ofono-binder] Added IMS state registration tracker object. JB#57425

IMS registration state will be needed in many places where we need
to make a decision based on the IMS registration state.
This commit is contained in:
Slava Monich
2022-02-17 19:34:13 +02:00
parent 760336b6b2
commit e7225edc21
7 changed files with 395 additions and 90 deletions

View File

@@ -52,6 +52,7 @@ SRC = \
binder_gprs.c \
binder_gprs_context.c \
binder_ims.c \
binder_ims_reg.c \
binder_logger.c \
binder_modem.c \
binder_netreg.c \

View File

@@ -14,30 +14,23 @@
*/
#include "binder_ims.h"
#include "binder_ims_reg.h"
#include "binder_log.h"
#include "binder_modem.h"
#include "binder_util.h"
#include <ofono/ims.h>
#include <radio_client.h>
#include <radio_request.h>
#include <radio_request_group.h>
#include <gbinder_reader.h>
enum binder_sms_events {
IMS_EVENT_IMS_NETWORK_STATE_CHANGED,
IMS_EVENT_COUNT
enum binder_ims_events {
EVENT_IMS_REGISTRATION_CHANGED,
EVENT_COUNT
};
typedef struct binder_ims {
struct ofono_ims* ims;
gboolean registered;
int flags;
char* log_prefix;
RadioRequestGroup* g;
gulong event_id[IMS_EVENT_COUNT];
BinderImsReg* reg;
gulong event_id[EVENT_COUNT];
guint start_id;
} BinderIms;
@@ -45,76 +38,23 @@ typedef struct binder_ims {
static inline BinderIms* binder_ims_get_data(struct ofono_ims* ims)
{ return ofono_ims_get_data(ims); }
static gboolean binder_ims_registered(BinderIms* self)
{ return self->reg && self->reg->registered; }
static int binder_ims_flags(BinderIms* self)
{ return binder_ims_registered(self) ? OFONO_IMS_SMS_CAPABLE : 0; }
static
void
binder_ims_query_registration_state_cb(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_RESP resp,
RADIO_ERROR error,
const GBinderReader* args,
gpointer user_data)
{
BinderIms* self = user_data;
if (status == RADIO_TX_STATUS_OK) {
if (resp == RADIO_RESP_GET_IMS_REGISTRATION_STATE) {
if (error == RADIO_ERROR_NONE) {
GBinderReader reader;
gboolean registered;
gint32 rat;
/*
* getImsRegistrationStateResponse(RadioResponseInfo info,
* bool isRegistered, RadioTechnologyFamily ratFamily)
*/
gbinder_reader_copy(&reader, args);
if (gbinder_reader_read_bool(&reader, &registered) &&
gbinder_reader_read_int32(&reader, &rat)) {
DBG_(self, "registered: %d, rat: 0x%08x", registered, rat);
if (self->registered != registered) {
self->registered = registered;
self->flags = registered ? OFONO_IMS_SMS_CAPABLE : 0;
ofono_ims_status_notify(self->ims, registered,
self->flags);
}
}
} else {
DBG_(self, "%s", binder_radio_error_string(error));
}
} else {
ofono_error("Unexpected getImsRegistrationState response %d",
resp);
}
}
}
static
void
binder_ims_query_registration_state(
BinderIms* self)
{
RadioRequest* req = radio_request_new2(self->g,
RADIO_REQ_GET_IMS_REGISTRATION_STATE, NULL,
binder_ims_query_registration_state_cb, NULL, self);
radio_request_submit(req);
radio_request_unref(req);
}
static
void
binder_ims_network_state_changed(
RadioClient* client,
RADIO_IND code,
const GBinderReader* args,
binder_ims_registration_changed(
BinderImsReg* reg,
BINDER_IMS_REG_PROPERTY property,
gpointer user_data)
{
BinderIms* self = user_data;
DBG_(self, "");
binder_ims_query_registration_state(self);
ofono_ims_status_notify(self->ims, binder_ims_registered(self),
binder_ims_flags(self));
}
static
@@ -127,7 +67,8 @@ binder_ims_registration_status(
BinderIms* self = binder_ims_get_data(ims);
struct ofono_error err;
cb(binder_error_ok(&err), self->registered, self->flags, data);
cb(binder_error_ok(&err), binder_ims_registered(self),
binder_ims_flags(self), data);
}
static
@@ -136,22 +77,17 @@ binder_ims_start(
gpointer user_data)
{
BinderIms* self = user_data;
RadioClient* client = self->g->client;
DBG_(self, "");
GASSERT(self->start_id);
self->start_id = 0;
self->event_id[EVENT_IMS_REGISTRATION_CHANGED] =
binder_ims_reg_add_property_handler(self->reg,
BINDER_IMS_REG_PROPERTY_REGISTERED,
binder_ims_registration_changed, self);
ofono_ims_register(self->ims);
/* Register event handlers */
self->event_id[IMS_EVENT_IMS_NETWORK_STATE_CHANGED] =
radio_client_add_indication_handler(client,
RADIO_IND_IMS_NETWORK_STATE_CHANGED,
binder_ims_network_state_changed, self);
/* Request the initial state */
binder_ims_query_registration_state(self);
return G_SOURCE_REMOVE;
}
@@ -167,7 +103,7 @@ binder_ims_probe(
self->log_prefix = binder_dup_prefix(modem->log_prefix);
DBG_(self, "");
self->g = radio_request_group_new(modem->client); /* Keeps ref to client */
self->reg = binder_ims_reg_ref(modem->ims);
self->ims = ims;
self->start_id = g_idle_add(binder_ims_start, self);
@@ -188,9 +124,8 @@ binder_ims_remove(
g_source_remove(self->start_id);
}
radio_client_remove_all_handlers(self->g->client, self->event_id);
radio_request_group_cancel(self->g);
radio_request_group_unref(self->g);
binder_ims_reg_remove_all_handlers(self->reg, self->event_id);
binder_ims_reg_unref(self->reg);
g_free(self->log_prefix);
g_free(self);

275
src/binder_ims_reg.c Normal file
View File

@@ -0,0 +1,275 @@
/*
* oFono - Open Source Telephony - binder based adaptation
*
* Copyright (C) 2022 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "binder_base.h"
#include "binder_ims_reg.h"
#include "binder_log.h"
#include "binder_util.h"
#include <radio_client.h>
#include <radio_request.h>
#include <radio_request_group.h>
#include <gbinder_reader.h>
#include <gutil_macros.h>
#include <gutil_misc.h>
enum binder_ims_events {
EVENT_IMS_NETWORK_STATE_CHANGED,
EVENT_COUNT
};
typedef struct binder_ims_reg_object {
BinderBase base;
BinderImsReg pub;
RadioRequestGroup* g;
char* log_prefix;
gulong event_id[EVENT_COUNT];
} BinderImsRegObject;
typedef BinderBaseClass BinderImsRegObjectClass;
GType binder_ims_reg_object_get_type() BINDER_INTERNAL;
G_DEFINE_TYPE(BinderImsRegObject, binder_ims_reg_object, BINDER_TYPE_BASE)
#define PARENT_CLASS binder_ims_reg_object_parent_class
#define THIS_TYPE binder_ims_reg_object_get_type()
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,THIS_TYPE,BinderImsRegObject)
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
/* Assumptions */
BINDER_BASE_ASSERT_COUNT(BINDER_IMS_REG_PROPERTY_COUNT);
static inline BinderImsRegObject* binder_ims_reg_cast(BinderImsReg* ims)
{ return ims ? THIS(G_CAST(ims, BinderImsRegObject, pub)) : NULL; }
static inline void binder_ims_reg_object_ref(BinderImsRegObject* self)
{ g_object_ref(self); }
static inline void binder_ims_reg_object_unref(BinderImsRegObject* self)
{ g_object_unref(self); }
static
void
binder_ims_reg_query_done(
RadioRequest* req,
RADIO_TX_STATUS status,
RADIO_RESP resp,
RADIO_ERROR error,
const GBinderReader* args,
gpointer user_data)
{
BinderImsRegObject* self = THIS(user_data);
BinderBase* base = &self->base;
BinderImsReg* ims = &self->pub;
gboolean registered = FALSE;
gint32 rat = RADIO_TECH_FAMILY_3GPP;
if (status != RADIO_TX_STATUS_OK) {
ofono_error("getImsRegistrationState failed");
} else if (resp != RADIO_RESP_GET_IMS_REGISTRATION_STATE) {
ofono_error("Unexpected getImsRegistrationState response %d", resp);
} else if (error != RADIO_ERROR_NONE) {
DBG_(self, "%s", binder_radio_error_string(error));
} else {
GBinderReader reader;
/*
* getImsRegistrationStateResponse(RadioResponseInfo info,
* bool isRegistered, RadioTechnologyFamily ratFamily)
*/
gbinder_reader_copy(&reader, args);
if (gbinder_reader_read_bool(&reader, &registered) &&
gbinder_reader_read_int32(&reader, &rat)) {
DBG_(self, "registered: %d, rat: %d", registered, rat);
} else {
ofono_error("Failed to parse getImsRegistrationState response");
}
}
/* Any error is treated as an unregistered state */
if (ims->registered != registered) {
ims->registered = registered;
binder_base_queue_property_change(base,
BINDER_IMS_REG_PROPERTY_REGISTERED);
}
if (ims->tech_family != rat) {
ims->tech_family = rat;
binder_base_queue_property_change(base,
BINDER_IMS_REG_PROPERTY_TECH_FAMILY);
}
binder_base_emit_queued_signals(base);
}
static
void
binder_ims_reg_query(
BinderImsRegObject* self)
{
RadioRequest* req = radio_request_new2(self->g,
RADIO_REQ_GET_IMS_REGISTRATION_STATE, NULL,
binder_ims_reg_query_done, NULL, self);
radio_request_submit(req);
radio_request_unref(req);
}
static
void
binder_ims_reg_state_changed(
RadioClient* client,
RADIO_IND code,
const GBinderReader* args,
gpointer user_data)
{
BinderImsRegObject* self = THIS(user_data);
DBG_(self, "");
binder_ims_reg_query(self);
}
/*==========================================================================*
* API
*==========================================================================*/
BinderImsReg*
binder_ims_reg_new(
RadioClient* client,
const char* log_prefix)
{
BinderImsReg* ims = NULL;
if (client) {
BinderImsRegObject* self = g_object_new(THIS_TYPE, NULL);
ims = &self->pub;
self->log_prefix = binder_dup_prefix(log_prefix);
self->g = radio_request_group_new(client); /* Keeps ref to client */
DBG_(self, "");
/* Register event handlers */
self->event_id[EVENT_IMS_NETWORK_STATE_CHANGED] =
radio_client_add_indication_handler(client,
RADIO_IND_IMS_NETWORK_STATE_CHANGED,
binder_ims_reg_state_changed, self);
/* Query the initial state */
binder_ims_reg_query(self);
}
return ims;
}
BinderImsReg*
binder_ims_reg_ref(
BinderImsReg* ims)
{
BinderImsRegObject* self = binder_ims_reg_cast(ims);
if (G_LIKELY(self)) {
binder_ims_reg_object_ref(self);
return ims;
} else {
return NULL;
}
}
void
binder_ims_reg_unref(
BinderImsReg* ims)
{
BinderImsRegObject* self = binder_ims_reg_cast(ims);
if (G_LIKELY(self)) {
binder_ims_reg_object_unref(self);
}
}
gulong
binder_ims_reg_add_property_handler(
BinderImsReg* ims,
BINDER_IMS_REG_PROPERTY property,
BinderImsRegPropertyFunc callback,
void* user_data)
{
BinderImsRegObject* self = binder_ims_reg_cast(ims);
return G_LIKELY(self) ? binder_base_add_property_handler(&self->base,
property, G_CALLBACK(callback), user_data) : 0;
}
void
binder_ims_reg_remove_handler(
BinderImsReg* ims,
gulong id)
{
if (G_LIKELY(id)) {
BinderImsRegObject* self = binder_ims_reg_cast(ims);
if (G_LIKELY(self)) {
g_signal_handler_disconnect(self, id);
}
}
}
void
binder_ims_reg_remove_handlers(
BinderImsReg* ims,
gulong* ids,
int count)
{
gutil_disconnect_handlers(binder_ims_reg_cast(ims), ids, count);
}
/*==========================================================================*
* Internals
*==========================================================================*/
static
void
binder_ims_reg_object_init(
BinderImsRegObject* self)
{
}
static
void
binder_ims_reg_object_finalize(
GObject* object)
{
BinderImsRegObject* self = THIS(object);
RadioRequestGroup* g = self->g;
radio_client_remove_all_handlers(g->client, self->event_id);
radio_request_group_cancel(g);
radio_request_group_unref(g);
g_free(self->log_prefix);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
binder_ims_reg_object_class_init(
BinderImsRegObjectClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = binder_ims_reg_object_finalize;
BINDER_BASE_CLASS(klass)->public_offset =
G_STRUCT_OFFSET(BinderImsRegObject, pub);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

89
src/binder_ims_reg.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* oFono - Open Source Telephony - binder based adaptation
*
* Copyright (C) 2022 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef BINDER_IMS_REG_H
#define BINDER_IMS_REG_H
#include "binder_types.h"
/* Object tracking IMS registration state */
typedef enum binder_ims_reg_property {
BINDER_IMS_REG_PROPERTY_ANY,
BINDER_IMS_REG_PROPERTY_REGISTERED,
BINDER_IMS_REG_PROPERTY_TECH_FAMILY,
BINDER_IMS_REG_PROPERTY_COUNT
} BINDER_IMS_REG_PROPERTY;
struct binder_ims_reg {
gboolean registered;
RADIO_TECH_FAMILY tech_family;
};
typedef
void
(*BinderImsRegPropertyFunc)(
BinderImsReg* ims,
BINDER_IMS_REG_PROPERTY property,
void* user_data);
BinderImsReg*
binder_ims_reg_new(
RadioClient* client,
const char* log_prefix);
BinderImsReg*
binder_ims_reg_ref(
BinderImsReg* ims)
BINDER_INTERNAL;
void
binder_ims_reg_unref(
BinderImsReg* ims)
BINDER_INTERNAL;
gulong
binder_ims_reg_add_property_handler(
BinderImsReg* ims,
BINDER_IMS_REG_PROPERTY property,
BinderImsRegPropertyFunc callback,
void* user_data)
BINDER_INTERNAL;
void
binder_ims_reg_remove_handler(
BinderImsReg* ims,
gulong id)
BINDER_INTERNAL;
void
binder_ims_reg_remove_handlers(
BinderImsReg* ims,
gulong* ids,
int count)
BINDER_INTERNAL;
#define binder_ims_reg_remove_all_handlers(ims, ids) \
binder_ims_reg_remove_handlers(ims, ids, G_N_ELEMENTS(ids))
#endif /* BINDER_IMS_REG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -19,6 +19,7 @@
#include "binder_sim_card.h"
#include "binder_sim_settings.h"
#include "binder_cell_info.h"
#include "binder_ims_reg.h"
#include "binder_data.h"
#include "binder_util.h"
#include "binder_log.h"
@@ -487,6 +488,7 @@ binder_modem_remove(
g_source_remove(self->set_offline.timeout_id);
}
binder_ims_reg_unref(modem->ims);
binder_network_unref(modem->network);
binder_sim_card_unref(modem->sim_card);
binder_data_unref(modem->data);
@@ -575,6 +577,7 @@ binder_modem_create(
modem->data = binder_data_ref(data);
modem->watch = ofono_watch_new(path);
modem->client = radio_client_ref(client);
modem->ims = binder_ims_reg_new(client, log_prefix);
self->g = radio_request_group_new(client);
self->last_known_iccid = g_strdup(modem->watch->iccid);

View File

@@ -30,6 +30,7 @@ struct binder_modem {
struct ofono_cell_info* cell_info;
struct ofono_watch* watch;
BinderData* data;
BinderImsReg* ims;
BinderNetwork* network;
BinderRadio* radio;
BinderSimCard* sim_card;

View File

@@ -23,6 +23,7 @@
typedef struct binder_data BinderData;
typedef struct binder_data_manager BinderDataManager;
typedef struct binder_devmon BinderDevmon;
typedef struct binder_ims_reg BinderImsReg;
typedef struct binder_logger BinderLogger;
typedef struct binder_modem BinderModem;
typedef struct binder_network BinderNetwork;