iface-modem: disable unsolicited 3GPP events during quick suspend/resume

This introduces the "terse" mode during quick suspend/resume, right now
it is used by 3GPP interface to disable unsolicited events, but in
future it can be used by other interfaces as well.

This prevents device to wake-up from suspend for each unsolicited while
still allowing to wake up on calls or SMS messages.

Signed-off-by: biemster <biemster@gmail.com>
Signed-off-by: Bhushan Shah <bshah@kde.org>
This commit is contained in:
biemster
2025-07-28 09:45:10 -05:00
committed by Dan Williams
parent 3a1184785b
commit d22bc4d402
8 changed files with 388 additions and 15 deletions
+4 -3
View File
@@ -93,9 +93,10 @@ sleeping_quick_cb (MMSleepMonitor *sleep_monitor,
MM_BASE_MANAGER_CLEANUP_LOW_POWER,
ctx);
} else {
/* Don't need to wait for anything; just suspend */
mm_dbg ("leaving modem powered... (sleeping)");
mm_sleep_context_complete (ctx, NULL);
mm_dbg ("setting modem in terse mode... (only send important signals (call/text))");
mm_base_manager_cleanup (manager,
MM_BASE_MANAGER_CLEANUP_TERSE,
ctx);
}
}
+48 -5
View File
@@ -17,6 +17,8 @@
* Copyright (C) 2011 - 2016 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "gio/gio.h"
#include "glib.h"
#include <config.h>
#include <string.h>
@@ -874,6 +876,7 @@ typedef enum {
DEVICE_CLEANUP_STEP_DISABLE,
DEVICE_CLEANUP_STEP_LOW_POWER,
DEVICE_CLEANUP_STEP_REMOVE,
DEVICE_CLEANUP_STEP_TERSE,
DEVICE_CLEANUP_STEP_LAST,
} DeviceCleanupStep;
@@ -965,6 +968,25 @@ cleanup_disable_ready (MMBaseModem *modem,
device_cleanup_step (task);
}
#if defined WITH_SUSPEND_RESUME
static void
cleanup_terse_ready (MMBaseModem *modem,
GAsyncResult *res,
GTask *task)
{
DeviceCleanupContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
if (!mm_base_modem_terse_finish (modem, res, &error))
mm_obj_info (modem, "setting terse failed: %s", error->message);
ctx->step++;
device_cleanup_step (task);
}
#endif
static gboolean
has_cleanup_flag (MMBaseManagerCleanupFlags flags,
MMBaseManagerCleanupFlags expected)
@@ -1028,6 +1050,24 @@ device_cleanup_step (GTask *task)
ctx->step++;
/* fall through */
case DEVICE_CLEANUP_STEP_TERSE:
#if defined WITH_SUSPEND_RESUME
if (ctx->modem && has_cleanup_flag (ctx->flags, MM_BASE_MANAGER_CLEANUP_TERSE)) {
mm_obj_dbg(device,
"settting terse on modem%d",
mm_base_modem_get_dbus_id (ctx->modem));
mm_base_modem_terse (ctx->modem,
MM_BASE_MODEM_OPERATION_LOCK_REQUIRED,
(GAsyncReadyCallback)cleanup_terse_ready,
task);
return;
}
#endif
ctx->step++;
/* fall through */
case DEVICE_CLEANUP_STEP_LAST:
mm_obj_dbg (device, "device cleanup complete");
g_task_return_boolean (task, TRUE);
@@ -1126,7 +1166,7 @@ mm_base_manager_cleanup (MMBaseManager *self,
ManagerCleanupContext *ctx;
GHashTableIter iter;
MMDevice *device;
gboolean disable, remove, low_power;
gboolean disable, remove, low_power, terse;
g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_BASE_MANAGER (self));
@@ -1137,13 +1177,16 @@ mm_base_manager_cleanup (MMBaseManager *self,
disable = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_DISABLE);
low_power = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_LOW_POWER);
remove = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_REMOVE);
terse = has_cleanup_flag (flags, MM_BASE_MANAGER_CLEANUP_TERSE);
mm_obj_dbg (self,
"manager shutting down... (%s%s%s%s%s)",
"manager shutting down... (%s%s%s%s%s%s%s)",
disable ? "disable" : "",
disable && (low_power || remove) ? "," : "",
disable && (low_power || remove || terse) ? "," : "",
low_power ? "low-power" : "",
(low_power && remove) ? "," : "",
remove ? "remove" : "");
low_power && (remove || terse) ? "," : "",
remove ? "remove" : "",
(remove && terse) ? "," : "",
terse ? "terse" : "");
ctx = manager_cleanup_context_new (self, sleep_ctx);
+1
View File
@@ -77,6 +77,7 @@ typedef enum {
MM_BASE_MANAGER_CLEANUP_DISABLE = 0x1,
MM_BASE_MANAGER_CLEANUP_LOW_POWER = 0x2,
MM_BASE_MANAGER_CLEANUP_REMOVE = 0x4,
MM_BASE_MANAGER_CLEANUP_TERSE = 0x8,
} MMBaseManagerCleanupFlags;
void mm_base_manager_cleanup (MMBaseManager *manager,
+29
View File
@@ -730,6 +730,7 @@ typedef enum {
STATE_OPERATION_TYPE_DISABLE,
#if defined WITH_SUSPEND_RESUME
STATE_OPERATION_TYPE_SYNC,
STATE_OPERATION_TYPE_TERSE,
#endif
} StateOperationType;
@@ -855,6 +856,12 @@ state_operation (MMBaseModem *self,
ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->sync;
ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->sync_finish;
break;
case STATE_OPERATION_TYPE_TERSE:
operation_description = "terse";
optional = TRUE;
ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->terse;
ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->terse_finish;
break;
#endif
default:
g_assert_not_reached ();
@@ -909,6 +916,28 @@ mm_base_modem_sync (MMBaseModem *self,
user_data);
}
gboolean
mm_base_modem_terse_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error)
{
return state_operation_finish (self, res, error);
}
void
mm_base_modem_terse (MMBaseModem *self,
MMBaseModemOperationLock operation_lock,
GAsyncReadyCallback callback,
gpointer user_data)
{
state_operation (self,
STATE_OPERATION_TYPE_TERSE,
operation_lock,
MM_BASE_MODEM_OPERATION_PRIORITY_DEFAULT,
callback,
user_data);
}
#endif /* WITH_SUSPEND_RESUME */
/******************************************************************************/
+23 -7
View File
@@ -109,6 +109,15 @@ struct _MMBaseModemClass {
* this method triggers a synchronization of all modem interfaces */
StateOperation sync;
StateOperationFinish sync_finish;
/* Modem terse.
* When suspending in quick suspend/resume mode,
* this method disables unsolicited events on the 3GPP interface only.
* This is enough for phones to suspend properly, but it
* might be useful to extend it to all other interfaces
* that support it as well */
StateOperation terse;
StateOperationFinish terse_finish;
#endif
/* Allow plugins to subclass port object creation as needed */
@@ -298,13 +307,20 @@ gboolean mm_base_modem_disable_finish (MMBaseModem *self,
GError **error);
#if defined WITH_SUSPEND_RESUME
void mm_base_modem_sync (MMBaseModem *self,
MMBaseModemOperationLock operation_lock,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_base_modem_sync_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error);
void mm_base_modem_sync (MMBaseModem *self,
MMBaseModemOperationLock operation_lock,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_base_modem_sync_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error);
void mm_base_modem_terse (MMBaseModem *self,
MMBaseModemOperationLock operation_lock,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_base_modem_terse_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error);
#endif
void mm_base_modem_teardown_ports (MMBaseModem *self,
+99
View File
@@ -13158,6 +13158,103 @@ synchronize (MMBaseModem *self,
syncing_step (task);
}
typedef enum {
TERSE_STEP_FIRST,
TERSE_STEP_DISABLE_UNSOLICITED_EVENTS_3GPP,
TERSE_STEP_LAST,
} TerseStep;
typedef struct {
TerseStep step;
} TerseContext;
static void terse_step (GTask *task);
static gboolean
terse_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
iface_modem_3gpp_terse_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
GTask *task)
{
TerseContext *ctx;
g_autoptr(GError) error = NULL;
ctx = g_task_get_task_data (task);
if (!mm_iface_modem_3gpp_terse_finish (self, res, &error))
mm_obj_warn (self, "3GPP interface disable unsolicited events failed: %s", error->message);
/* Go on to next step */
ctx->step++;
terse_step (task);
}
static void
terse_step (GTask *task)
{
MMBroadbandModem *self;
TerseContext *ctx;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
switch (ctx->step) {
case TERSE_STEP_FIRST:
ctx->step++;
/* fall through */
case TERSE_STEP_DISABLE_UNSOLICITED_EVENTS_3GPP:
if (self->priv->modem_3gpp_dbus_skeleton &&
(self->priv->modem_state >= MM_MODEM_STATE_ENABLED)) {
mm_obj_msg (self, "terse state (%d/%d): 3GPP interface disable unsolicited events",
ctx->step, TERSE_STEP_LAST);
mm_iface_modem_3gpp_terse (MM_IFACE_MODEM_3GPP (self), (GAsyncReadyCallback)iface_modem_3gpp_terse_ready, task);
return;
}
ctx->step++;
/* fall through */
case TERSE_STEP_LAST:
mm_obj_msg (self, "setting terse state (%d/%d): all done",
ctx->step, TERSE_STEP_LAST);
/* We are done without errors! */
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
default:
break;
}
g_assert_not_reached ();
}
static void
terse (MMBaseModem *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
TerseContext *ctx;
GTask *task;
task = g_task_new (self, cancellable, callback, user_data);
/* Create TerseContext */
ctx = g_new0 (TerseContext, 1);
ctx->step = TERSE_STEP_FIRST;
g_task_set_task_data (task, ctx, (GDestroyNotify)g_free);
terse_step (task);
}
#endif
/*****************************************************************************/
@@ -14645,6 +14742,8 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass)
#if defined WITH_SUSPEND_RESUME
base_modem_class->sync = synchronize;
base_modem_class->sync_finish = synchronize_finish;
base_modem_class->terse = terse;
base_modem_class->terse_finish = terse_finish;
#endif
klass->setup_ports = setup_ports;
+177
View File
@@ -3232,6 +3232,8 @@ static void interface_syncing_step (GTask *task);
typedef enum {
SYNCING_STEP_FIRST,
SYNCING_STEP_ENABLE_UNSOLICITED_EVENTS,
SYNCING_STEP_ENABLE_UNSOLICITED_REGISTRATION_EVENTS,
SYNCING_STEP_REFRESH_3GPP_REGISTRATION,
SYNCING_STEP_REFRESH_EPS_BEARER,
SYNCING_STEP_LAST
@@ -3249,6 +3251,31 @@ mm_iface_modem_3gpp_sync_finish (MMIfaceModem3gpp *self,
return g_task_propagate_boolean (G_TASK (res), error);
}
#undef VOID_SYNC_REPLY_READY_FN
#define VOID_SYNC_REPLY_READY_FN(NAME,DISPLAY) \
static void \
sync_##NAME##_ready (MMIfaceModem3gpp *self, \
GAsyncResult *res, \
GTask *task) \
{ \
DisablingContext *ctx; \
g_autoptr(GError) error = NULL; \
\
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->NAME##_finish (self, res, &error); \
if (error) \
mm_obj_dbg (self, "couldn't %s: %s", DISPLAY, error->message); \
\
/* Go on to next step */ \
ctx = g_task_get_task_data (task); \
ctx->step++; \
interface_syncing_step (task); \
}
VOID_SYNC_REPLY_READY_FN (enable_unsolicited_events,
"enable unsolicited events")
VOID_SYNC_REPLY_READY_FN (enable_unsolicited_registration_events,
"enable unsolicited registration events")
static void
sync_eps_bearer_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
@@ -3327,6 +3354,33 @@ interface_syncing_step (GTask *task)
ctx->step++;
/* fall through */
case SYNCING_STEP_ENABLE_UNSOLICITED_EVENTS:
if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events &&
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events_finish) {
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_events (
self,
(GAsyncReadyCallback)sync_enable_unsolicited_events_ready,
task);
return;
}
ctx->step++;
/* fall through */
case SYNCING_STEP_ENABLE_UNSOLICITED_REGISTRATION_EVENTS:
if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events &&
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events_finish) {
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->enable_unsolicited_registration_events (
self,
get_cs_network_supported (self),
get_ps_network_supported (self),
get_eps_network_supported (self),
(GAsyncReadyCallback)sync_enable_unsolicited_registration_events_ready,
task);
return;
}
ctx->step++;
/* fall through */
case SYNCING_STEP_REFRESH_3GPP_REGISTRATION:
/*
* Refresh registration info to verify that the modem is still registered.
@@ -3381,6 +3435,129 @@ mm_iface_modem_3gpp_sync (MMIfaceModem3gpp *self,
interface_syncing_step (task);
}
typedef struct _TerseContext TerseContext;
static void interface_terse_step (GTask *task);
typedef enum {
TERSE_STEP_FIRST,
TERSE_STEP_DISABLE_UNSOLICITED_REGISTRATION_EVENTS,
TERSE_STEP_DISABLE_UNSOLICITED_EVENTS,
TERSE_STEP_LAST
} TerseStep;
struct _TerseContext {
TerseStep step;
};
gboolean
mm_iface_modem_3gpp_terse_finish (MMIfaceModem3gpp *self,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
#undef VOID_TERSE_REPLY_READY_FN
#define VOID_TERSE_REPLY_READY_FN(NAME,DISPLAY) \
static void \
terse_##NAME##_ready (MMIfaceModem3gpp *self, \
GAsyncResult *res, \
GTask *task) \
{ \
TerseContext *ctx; \
g_autoptr(GError) error = NULL; \
\
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->NAME##_finish (self, res, &error); \
if (error) \
mm_obj_dbg (self, "couldn't %s: %s", DISPLAY, error->message); \
\
/* Go on to next step */ \
ctx = g_task_get_task_data (task); \
ctx->step++; \
interface_terse_step (task); \
}
VOID_TERSE_REPLY_READY_FN (disable_unsolicited_events,
"disable unsolicited events")
VOID_TERSE_REPLY_READY_FN (disable_unsolicited_registration_events,
"disable unsolicited registration events")
static void
interface_terse_step (GTask *task)
{
MMIfaceModem3gpp *self;
TerseContext *ctx;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
switch (ctx->step) {
case TERSE_STEP_FIRST:
ctx->step++;
/* fall through */
case TERSE_STEP_DISABLE_UNSOLICITED_REGISTRATION_EVENTS:
if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events &&
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events_finish) {
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_registration_events (
self,
get_cs_network_supported (self),
get_ps_network_supported (self),
get_eps_network_supported (self),
(GAsyncReadyCallback)terse_disable_unsolicited_registration_events_ready,
task);
mm_obj_msg (self, "terse state 3GPP (%d/%d): disable unsolicited registration events done",
ctx->step, TERSE_STEP_LAST);
return;
}
ctx->step++;
/* fall through */
case TERSE_STEP_DISABLE_UNSOLICITED_EVENTS:
if (MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events &&
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events_finish) {
MM_IFACE_MODEM_3GPP_GET_IFACE (self)->disable_unsolicited_events (
self,
(GAsyncReadyCallback)terse_disable_unsolicited_events_ready,
task);
mm_obj_msg (self, "terse state 3GPP (%d/%d): disable unsolicited events done",
ctx->step, TERSE_STEP_LAST);
return;
}
ctx->step++;
/* fall through */
case TERSE_STEP_LAST:
/* We are done without errors! */
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
default:
g_assert_not_reached ();
}
g_assert_not_reached ();
}
void
mm_iface_modem_3gpp_terse (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
TerseContext *ctx;
GTask *task;
/* Create SyncingContext */
ctx = g_new0 (TerseContext, 1);
ctx->step = TERSE_STEP_FIRST;
/* Create sync steps task and execute it */
task = g_task_new (self, NULL, callback, user_data);
g_task_set_task_data (task, ctx, (GDestroyNotify)g_free);
interface_terse_step (task);
}
#endif
/*****************************************************************************/
+7
View File
@@ -318,6 +318,13 @@ gboolean mm_iface_modem_3gpp_sync_finish (MMIfaceModem3gpp *self,
GAsyncResult *res,
GError **error);
void mm_iface_modem_3gpp_terse (MMIfaceModem3gpp *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_iface_modem_3gpp_terse_finish (MMIfaceModem3gpp *self,
GAsyncResult *res,
GError **error);
#endif
/* Shutdown Modem 3GPP interface */