[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:
1
Makefile
1
Makefile
@@ -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 \
|
||||
|
||||
115
src/binder_ims.c
115
src/binder_ims.c
@@ -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, ®istered) &&
|
||||
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
275
src/binder_ims_reg.c
Normal 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, ®istered) &&
|
||||
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
89
src/binder_ims_reg.h
Normal 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:
|
||||
*/
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user