bt: track name-owner changes via NMModemManager and create D-Bus proxy asynchronously

Fix two issues of the previous code:

  - the D-Bus proxy for the modem manager should not get created
    synchronously.
  - NMModemManager is a singleton, let it track the name-owner
    change and the D-Bus proxy, instead of having one per NMDeviceBt.
This commit is contained in:
Thomas Haller 2017-04-22 11:05:31 +02:00
parent 7840dde47b
commit e84a52ea42
4 changed files with 198 additions and 38 deletions

View file

@ -64,7 +64,8 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
GDBusProxy *mm_proxy;
NMModemManager *modem_manager;
gboolean mm_running;
NMBluezDevice *bt_device;
@ -966,9 +967,12 @@ is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags)
}
static void
set_mm_running (NMDeviceBt *self, gboolean running)
set_mm_running (NMDeviceBt *self)
{
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
gboolean running;
running = (nm_modem_manager_name_owner_get (priv->modem_manager) != NULL);
if (priv->mm_running != running) {
_LOGD (LOGD_BT, "ModemManager now %s",
@ -981,22 +985,12 @@ set_mm_running (NMDeviceBt *self, gboolean running)
}
}
static void
mm_name_owner_changed (NMDeviceBt *self)
{
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
gs_free char *owner = NULL;
owner = g_dbus_proxy_get_name_owner (priv->mm_proxy);
set_mm_running (self, owner != NULL);
}
static void
mm_name_owner_changed_cb (GObject *object,
GParamSpec *pspec,
NMDeviceBt *self)
gpointer user_data)
{
mm_name_owner_changed (self);
set_mm_running (user_data);
}
/*****************************************************************************/
@ -1063,30 +1057,18 @@ constructed (GObject *object)
NMDeviceBt *self = NM_DEVICE_BT (object);
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
const char *my_hwaddr;
gs_free_error GError *error = NULL;
priv->mm_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
NM_MODEM_MANAGER_MM_DBUS_SERVICE,
NM_MODEM_MANAGER_MM_DBUS_PATH,
NM_MODEM_MANAGER_MM_DBUS_INTERFACE,
NULL, &error);
if (priv->mm_proxy) {
g_signal_connect (priv->mm_proxy, "notify::g-name-owner",
G_CALLBACK (mm_name_owner_changed_cb),
self);
mm_name_owner_changed (self);
} else {
_LOGW (LOGD_MB, "Could not create proxy for '%s': %s",
NM_MODEM_MANAGER_MM_DBUS_SERVICE, error->message);
g_clear_error (&error);
}
G_OBJECT_CLASS (nm_device_bt_parent_class)->constructed (object);
priv->modem_manager = g_object_ref (nm_modem_manager_get ());
nm_modem_manager_name_owner_ref (priv->modem_manager);
g_signal_connect (priv->modem_manager,
"notify::"NM_MODEM_MANAGER_NAME_OWNER,
G_CALLBACK (mm_name_owner_changed_cb),
self);
if (priv->bt_device) {
/* Watch for BT device property changes */
g_signal_connect (priv->bt_device, "notify::" NM_BLUEZ_DEVICE_CONNECTED,
@ -1100,6 +1082,8 @@ constructed (GObject *object)
priv->bdaddr = g_strdup (my_hwaddr);
else
g_warn_if_reached ();
set_mm_running (self);
}
NMDevice *
@ -1137,9 +1121,10 @@ dispose (GObject *object)
g_signal_handlers_disconnect_matched (priv->bt_device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object);
if (priv->mm_proxy) {
g_signal_handlers_disconnect_by_func (priv->mm_proxy, G_CALLBACK (mm_name_owner_changed_cb), object);
g_clear_object (&priv->mm_proxy);
if (priv->modem_manager) {
g_signal_handlers_disconnect_by_func (priv->modem_manager, G_CALLBACK (mm_name_owner_changed_cb), object);
nm_modem_manager_name_owner_unref (priv->modem_manager);
g_clear_object (&priv->modem_manager);
}
modem_cleanup (NM_DEVICE_BT (object));

View file

@ -20,7 +20,11 @@ global:
nm_modem_get_type;
nm_modem_get_uid;
nm_modem_ip4_pre_commit;
nm_modem_manager_get;
nm_modem_manager_get_type;
nm_modem_manager_name_owner_get;
nm_modem_manager_name_owner_ref;
nm_modem_manager_name_owner_unref;
nm_modem_owns_port;
nm_modem_set_mm_enabled;
nm_modem_stage3_ip4_config_start;

View file

@ -45,6 +45,10 @@
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE (NMModemManager,
PROP_NAME_OWNER,
);
enum {
MODEM_ADDED,
LAST_SIGNAL,
@ -65,6 +69,11 @@ typedef struct {
gulong handle_object_added_id;
gulong handle_object_removed_id;
guint relaunch_id;
GDBusProxy *proxy;
GCancellable *proxy_cancellable;
guint proxy_ref_count;
char *proxy_name_owner;
} modm;
#if WITH_OFONO
@ -435,6 +444,129 @@ modm_schedule_manager_relaunch (NMModemManager *self,
/*****************************************************************************/
static void
modm_proxy_name_owner_reset (NMModemManager *self)
{
NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
char *name = NULL;
if (priv->modm.proxy)
name = g_dbus_proxy_get_name_owner (priv->modm.proxy);
if (nm_streq0 (priv->modm.proxy_name_owner, name)) {
g_free (name);
return;
}
g_free (priv->modm.proxy_name_owner);
priv->modm.proxy_name_owner = name;
_notify (self, PROP_NAME_OWNER);
}
static void
modm_proxy_name_owner_changed_cb (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
modm_proxy_name_owner_reset (user_data);
}
static void
modm_proxy_new_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
NMModemManager *self;
NMModemManagerPrivate *priv;
GDBusProxy *proxy;
gs_free_error GError *error = NULL;
proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if ( !proxy
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = user_data;
priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
g_clear_object (&priv->modm.proxy_cancellable);
if (!proxy) {
_LOGW ("could not obtain D-Bus proxy for ModemManager: %s", error->message);
return;
}
priv->modm.proxy = proxy;
g_signal_connect (priv->modm.proxy, "notify::g-name-owner",
G_CALLBACK (modm_proxy_name_owner_changed_cb), self);
modm_proxy_name_owner_reset (self);
}
void
nm_modem_manager_name_owner_ref (NMModemManager *self)
{
NMModemManagerPrivate *priv;
g_return_if_fail (NM_IS_MODEM_MANAGER (self));
priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
if (priv->modm.proxy_ref_count++ > 0) {
/* only try once to create the proxy. If proxy creation
* for the first "ref" failed, it's unclear what to do.
* The proxy is hosed. */
return;
}
nm_assert (!priv->modm.proxy && !priv->modm.proxy_cancellable);
priv->modm.proxy_cancellable = g_cancellable_new ();
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
| G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
| G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
NM_MODEM_MANAGER_MM_DBUS_SERVICE,
NM_MODEM_MANAGER_MM_DBUS_PATH,
NM_MODEM_MANAGER_MM_DBUS_INTERFACE,
priv->modm.proxy_cancellable,
modm_proxy_new_cb,
self);
}
void
nm_modem_manager_name_owner_unref (NMModemManager *self)
{
NMModemManagerPrivate *priv;
g_return_if_fail (NM_IS_MODEM_MANAGER (self));
priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
g_return_if_fail (priv->modm.proxy_ref_count > 0);
if (--priv->modm.proxy_ref_count > 0)
return;
nm_clear_g_cancellable (&priv->modm.proxy_cancellable);
g_clear_object (&priv->modm.proxy);
modm_proxy_name_owner_reset (self);
}
const char *
nm_modem_manager_name_owner_get (NMModemManager *self)
{
g_return_val_if_fail (NM_IS_MODEM_MANAGER (self), NULL);
nm_assert (NM_MODEM_MANAGER_GET_PRIVATE (self)->modm.proxy_ref_count > 0);
return NM_MODEM_MANAGER_GET_PRIVATE (self)->modm.proxy_name_owner;
}
/*****************************************************************************/
#if WITH_OFONO
static void
@ -669,6 +801,25 @@ bus_get_ready (GObject *source,
/*****************************************************************************/
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMModemManager *self = NM_MODEM_MANAGER (object);
NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self);
switch (prop_id) {
case PROP_NAME_OWNER:
g_value_set_string (value, priv->modm.proxy_name_owner);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*****************************************************************************/
static void
nm_modem_manager_init (NMModemManager *self)
{
@ -695,6 +846,10 @@ dispose (GObject *object)
nm_clear_g_source (&priv->modm.relaunch_id);
nm_clear_g_cancellable (&priv->modm.proxy_cancellable);
g_clear_object (&priv->modm.proxy);
nm_clear_g_free (&priv->modm.proxy_name_owner);
modm_clear_manager (self);
#if WITH_OFONO
@ -723,6 +878,15 @@ nm_modem_manager_class_init (NMModemManagerClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = dispose;
object_class->get_property = get_property;
obj_properties[PROP_NAME_OWNER] =
g_param_spec_string (NM_MODEM_MANAGER_NAME_OWNER, "", "",
NULL,
G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
signals[MODEM_ADDED] =
g_signal_new (NM_MODEM_MANAGER_MODEM_ADDED,

View file

@ -34,6 +34,8 @@
#define NM_MODEM_MANAGER_MODEM_ADDED "modem-added"
#define NM_MODEM_MANAGER_NAME_OWNER "name-owner"
#define NM_MODEM_MANAGER_MM_DBUS_SERVICE "org.freedesktop.ModemManager1"
#define NM_MODEM_MANAGER_MM_DBUS_PATH "/org/freedesktop/ModemManager1"
#define NM_MODEM_MANAGER_MM_DBUS_INTERFACE "org.freedesktop.ModemManager1"
@ -45,4 +47,9 @@ GType nm_modem_manager_get_type (void);
NMModemManager *nm_modem_manager_get (void);
void nm_modem_manager_name_owner_ref (NMModemManager *self);
void nm_modem_manager_name_owner_unref (NMModemManager *self);
const char *nm_modem_manager_name_owner_get (NMModemManager *self);
#endif /* __NETWORKMANAGER_MODEM_MANAGER_H__ */