iface-modem: consolidate new unlock required check with retries
The new internal_load_unlock_required() method will take care of running the subclassed load_unlock_required(), if available, and also retry the check up to 6 times. This method will be used both by the standard unlock required check and by the check within the current capabilities loading for multimode devices.
This commit is contained in:

committed by
Dan Williams

parent
43d1c904e6
commit
13c7319bff
@@ -205,6 +205,146 @@ mm_iface_modem_wait_for_final_state (MMIfaceModem *self,
|
|||||||
ctx);
|
ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Helper method to load unlock required, considering retries */
|
||||||
|
|
||||||
|
#define MAX_RETRIES 6
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMIfaceModem *self;
|
||||||
|
GSimpleAsyncResult *result;
|
||||||
|
guint retries;
|
||||||
|
guint pin_check_timeout_id;
|
||||||
|
} InternalLoadUnlockRequiredContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
internal_load_unlock_required_context_complete_and_free (InternalLoadUnlockRequiredContext *ctx)
|
||||||
|
{
|
||||||
|
g_simple_async_result_complete_in_idle (ctx->result);
|
||||||
|
g_object_unref (ctx->result);
|
||||||
|
g_object_unref (ctx->self);
|
||||||
|
g_slice_free (InternalLoadUnlockRequiredContext, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MMModemLock
|
||||||
|
internal_load_unlock_required_finish (MMIfaceModem *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
|
||||||
|
return MM_MODEM_LOCK_UNKNOWN;
|
||||||
|
|
||||||
|
return (MMModemLock) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void internal_load_unlock_required_context_step (InternalLoadUnlockRequiredContext *ctx);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
load_unlock_required_again (InternalLoadUnlockRequiredContext *ctx)
|
||||||
|
{
|
||||||
|
ctx->pin_check_timeout_id = 0;
|
||||||
|
/* Retry the step */
|
||||||
|
internal_load_unlock_required_context_step (ctx);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_unlock_required_ready (MMIfaceModem *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
InternalLoadUnlockRequiredContext *ctx)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
MMModemLock lock;
|
||||||
|
|
||||||
|
lock = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error);
|
||||||
|
if (error) {
|
||||||
|
mm_dbg ("Couldn't check if unlock required: '%s'", error->message);
|
||||||
|
|
||||||
|
/* For several kinds of errors, just return them directly */
|
||||||
|
if (error->domain == MM_SERIAL_ERROR ||
|
||||||
|
g_error_matches (error,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_CANCELLED) ||
|
||||||
|
g_error_matches (error,
|
||||||
|
MM_MOBILE_EQUIPMENT_ERROR,
|
||||||
|
MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
|
||||||
|
g_error_matches (error,
|
||||||
|
MM_MOBILE_EQUIPMENT_ERROR,
|
||||||
|
MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) ||
|
||||||
|
g_error_matches (error,
|
||||||
|
MM_MOBILE_EQUIPMENT_ERROR,
|
||||||
|
MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
|
||||||
|
g_simple_async_result_take_error (ctx->result, error);
|
||||||
|
internal_load_unlock_required_context_complete_and_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the remaining ones, retry if possible */
|
||||||
|
if (ctx->retries < MAX_RETRIES) {
|
||||||
|
ctx->retries++;
|
||||||
|
mm_dbg ("Retrying (%u) unlock required check", ctx->retries);
|
||||||
|
|
||||||
|
g_assert (ctx->pin_check_timeout_id == 0);
|
||||||
|
ctx->pin_check_timeout_id = g_timeout_add_seconds (2,
|
||||||
|
(GSourceFunc)load_unlock_required_again,
|
||||||
|
ctx);
|
||||||
|
g_error_free (error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If reached max retries and still reporting error... default to SIM error */
|
||||||
|
g_error_free (error);
|
||||||
|
g_simple_async_result_set_error (ctx->result,
|
||||||
|
MM_MOBILE_EQUIPMENT_ERROR,
|
||||||
|
MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE,
|
||||||
|
"Couldn't get SIM lock status after %u retries",
|
||||||
|
MAX_RETRIES);
|
||||||
|
internal_load_unlock_required_context_complete_and_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Got the lock value, return it */
|
||||||
|
g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (ctx->result),
|
||||||
|
GUINT_TO_POINTER (lock),
|
||||||
|
NULL);
|
||||||
|
internal_load_unlock_required_context_complete_and_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
internal_load_unlock_required_context_step (InternalLoadUnlockRequiredContext *ctx)
|
||||||
|
{
|
||||||
|
g_assert (ctx->pin_check_timeout_id == 0);
|
||||||
|
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required (
|
||||||
|
ctx->self,
|
||||||
|
(GAsyncReadyCallback)load_unlock_required_ready,
|
||||||
|
ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
internal_load_unlock_required (MMIfaceModem *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
InternalLoadUnlockRequiredContext *ctx;
|
||||||
|
|
||||||
|
ctx = g_slice_new0 (InternalLoadUnlockRequiredContext);
|
||||||
|
ctx->self = g_object_ref (self);
|
||||||
|
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||||
|
callback,
|
||||||
|
user_data,
|
||||||
|
internal_load_unlock_required);
|
||||||
|
|
||||||
|
if (!MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required ||
|
||||||
|
!MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required_finish) {
|
||||||
|
/* Just assume that no lock is required */
|
||||||
|
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||||
|
internal_load_unlock_required_context_complete_and_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_load_unlock_required_context_step (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static MMModemState get_current_consolidated_state (MMIfaceModem *self, MMModemState modem_state);
|
static MMModemState get_current_consolidated_state (MMIfaceModem *self, MMModemState modem_state);
|
||||||
@@ -2670,8 +2810,6 @@ typedef enum {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
MMIfaceModem *self;
|
MMIfaceModem *self;
|
||||||
UpdateLockInfoContextStep step;
|
UpdateLockInfoContextStep step;
|
||||||
guint pin_check_tries;
|
|
||||||
guint pin_check_timeout_id;
|
|
||||||
GSimpleAsyncResult *result;
|
GSimpleAsyncResult *result;
|
||||||
MmGdbusModem *skeleton;
|
MmGdbusModem *skeleton;
|
||||||
MMModemLock lock;
|
MMModemLock lock;
|
||||||
@@ -2744,23 +2882,14 @@ modem_after_sim_unlock_ready (MMIfaceModem *self,
|
|||||||
update_lock_info_context_step (ctx);
|
update_lock_info_context_step (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
load_unlock_required_again (UpdateLockInfoContext *ctx)
|
|
||||||
{
|
|
||||||
ctx->pin_check_timeout_id = 0;
|
|
||||||
/* Retry the step */
|
|
||||||
update_lock_info_context_step (ctx);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
load_unlock_required_ready (MMIfaceModem *self,
|
internal_load_unlock_required_ready (MMIfaceModem *self,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
UpdateLockInfoContext *ctx)
|
UpdateLockInfoContext *ctx)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
ctx->lock = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error);
|
ctx->lock = internal_load_unlock_required_finish (self, res, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
/* Treat several SIM related, serial and other core errors as critical
|
/* Treat several SIM related, serial and other core errors as critical
|
||||||
* and abort the checks. These will end up moving the modem to a FAILED
|
* and abort the checks. These will end up moving the modem to a FAILED
|
||||||
@@ -2773,44 +2902,32 @@ load_unlock_required_ready (MMIfaceModem *self,
|
|||||||
ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
|
ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
|
||||||
update_lock_info_context_step (ctx);
|
update_lock_info_context_step (ctx);
|
||||||
return;
|
return;
|
||||||
} else if (g_error_matches (error,
|
}
|
||||||
MM_MOBILE_EQUIPMENT_ERROR,
|
|
||||||
MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
|
if (g_error_matches (error,
|
||||||
g_error_matches (error,
|
MM_MOBILE_EQUIPMENT_ERROR,
|
||||||
MM_MOBILE_EQUIPMENT_ERROR,
|
MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
|
||||||
MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) ||
|
g_error_matches (error,
|
||||||
g_error_matches (error,
|
MM_MOBILE_EQUIPMENT_ERROR,
|
||||||
MM_MOBILE_EQUIPMENT_ERROR,
|
MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) ||
|
||||||
MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
|
g_error_matches (error,
|
||||||
if (mm_iface_modem_is_cdma (self)) {
|
MM_MOBILE_EQUIPMENT_ERROR,
|
||||||
/* For mixed 3GPP+3GPP2 devices, skip SIM errors */
|
MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
|
||||||
mm_dbg ("Skipping SIM error in 3GPP2-capable device, assuming no lock is needed");
|
/* SIM errors are only critical in 3GPP-only devices */
|
||||||
g_error_free (error);
|
if (!mm_iface_modem_is_cdma (self)) {
|
||||||
ctx->lock = MM_MODEM_LOCK_NONE;
|
|
||||||
} else {
|
|
||||||
/* SIM errors are only critical in 3GPP-only devices */
|
|
||||||
ctx->saved_error = error;
|
ctx->saved_error = error;
|
||||||
ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
|
ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
|
||||||
update_lock_info_context_step (ctx);
|
update_lock_info_context_step (ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For mixed 3GPP+3GPP2 devices, skip SIM errors */
|
||||||
|
mm_dbg ("Skipping SIM error in 3GPP2-capable device, assuming no lock is needed");
|
||||||
|
g_error_free (error);
|
||||||
|
ctx->lock = MM_MODEM_LOCK_NONE;
|
||||||
} else {
|
} else {
|
||||||
mm_dbg ("Couldn't check if unlock required: '%s'", error->message);
|
mm_dbg ("Couldn't check if unlock required: '%s'", error->message);
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
|
|
||||||
/* Retry up to 6 times */
|
|
||||||
if (mm_gdbus_modem_get_unlock_required (ctx->skeleton) != MM_MODEM_LOCK_NONE &&
|
|
||||||
++ctx->pin_check_tries < 6) {
|
|
||||||
mm_dbg ("Retrying (%u) unlock required check", ctx->pin_check_tries);
|
|
||||||
if (ctx->pin_check_timeout_id)
|
|
||||||
g_source_remove (ctx->pin_check_timeout_id);
|
|
||||||
ctx->pin_check_timeout_id = g_timeout_add_seconds (2,
|
|
||||||
(GSourceFunc)load_unlock_required_again,
|
|
||||||
ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If reached max retries and still reporting error, set UNKNOWN */
|
|
||||||
ctx->lock = MM_MODEM_LOCK_UNKNOWN;
|
ctx->lock = MM_MODEM_LOCK_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2842,12 +2959,10 @@ update_lock_info_context_step (UpdateLockInfoContext *ctx)
|
|||||||
/* Don't re-ask if already known */
|
/* Don't re-ask if already known */
|
||||||
if (ctx->lock == MM_MODEM_LOCK_UNKNOWN) {
|
if (ctx->lock == MM_MODEM_LOCK_UNKNOWN) {
|
||||||
/* If we're already unlocked, we're done */
|
/* If we're already unlocked, we're done */
|
||||||
if (mm_gdbus_modem_get_unlock_required (ctx->skeleton) != MM_MODEM_LOCK_NONE &&
|
if (mm_gdbus_modem_get_unlock_required (ctx->skeleton) != MM_MODEM_LOCK_NONE) {
|
||||||
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required &&
|
internal_load_unlock_required (
|
||||||
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required_finish) {
|
|
||||||
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required (
|
|
||||||
ctx->self,
|
ctx->self,
|
||||||
(GAsyncReadyCallback)load_unlock_required_ready,
|
(GAsyncReadyCallback)internal_load_unlock_required_ready,
|
||||||
ctx);
|
ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3592,13 +3707,13 @@ initialization_context_complete_and_free_if_cancelled (InitializationContext *ct
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
current_capabilities_load_unlock_required_ready (MMIfaceModem *self,
|
current_capabilities_internal_load_unlock_required_ready (MMIfaceModem *self,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
InitializationContext *ctx)
|
InitializationContext *ctx)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error);
|
internal_load_unlock_required_finish (self, res, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
/* These SIM errors indicate that there is NO valid SIM available. So,
|
/* These SIM errors indicate that there is NO valid SIM available. So,
|
||||||
* remove all 3GPP caps from the current capabilities */
|
* remove all 3GPP caps from the current capabilities */
|
||||||
@@ -3657,13 +3772,11 @@ load_current_capabilities_ready (MMIfaceModem *self,
|
|||||||
/* If the device is a multimode device (3GPP+3GPP2) check whether we have a
|
/* If the device is a multimode device (3GPP+3GPP2) check whether we have a
|
||||||
* SIM or not. */
|
* SIM or not. */
|
||||||
if (caps & MM_MODEM_CAPABILITY_CDMA_EVDO &&
|
if (caps & MM_MODEM_CAPABILITY_CDMA_EVDO &&
|
||||||
(caps & MM_MODEM_CAPABILITY_GSM_UMTS || caps & MM_MODEM_CAPABILITY_LTE) &&
|
(caps & MM_MODEM_CAPABILITY_GSM_UMTS || caps & MM_MODEM_CAPABILITY_LTE)) {
|
||||||
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required &&
|
|
||||||
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required_finish) {
|
|
||||||
mm_dbg ("Checking if multimode device has a SIM...");
|
mm_dbg ("Checking if multimode device has a SIM...");
|
||||||
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required (
|
internal_load_unlock_required (
|
||||||
ctx->self,
|
ctx->self,
|
||||||
(GAsyncReadyCallback)current_capabilities_load_unlock_required_ready,
|
(GAsyncReadyCallback)current_capabilities_internal_load_unlock_required_ready,
|
||||||
ctx);
|
ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user