Skip to content

Commit

Permalink
[systemd] Use cached SystemBus connection. Fixes MER#1694
Browse files Browse the repository at this point in the history
Usb-moded opens and closes a private peer-to-peer dbus connection for each
systemd unit start/stop it needs to perform. This is relatively heavy
operation and seems to cause problems with systemd v225 during bootup.

Since usb-moded no longer has any reason to communicate with systemd
before it can connect to SystemBus, we can drop the private connections
and use cached SystemBus connection instead.

Signed-off-by: Simo Piiroinen <simo.piiroinen@jollamobile.com>
  • Loading branch information
spiiroin committed Nov 7, 2016
1 parent 40463c7 commit bae8743
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 59 deletions.
178 changes: 119 additions & 59 deletions src/usb_moded-systemd.c
Expand Up @@ -35,69 +35,129 @@
#include "usb_moded-log.h"
#include "usb_moded-systemd.h"

static DBusConnection * get_systemd_dbus_connection(void)
{
DBusError error;
DBusConnection *conn = 0;

dbus_error_init(&error);

conn = dbus_connection_open_private("unix:path=/run/systemd/private", &error);
if (!conn)
{
if (dbus_error_is_set(&error))
log_err("Cannot connect to systemd: %s", error.message);
else
log_err("Cannot connect to systemd");
dbus_error_free(&error);
return 0;
}

return conn;
}
#define SYSTEMD_DBUS_SERVICE "org.freedesktop.systemd1"
#define SYSTEMD_DBUS_PATH "/org/freedesktop/systemd1"
#define SYSTEMD_DBUS_INTERFACE "org.freedesktop.systemd1.Manager"


/* SystemBus connection ref used for systemd control ipc */
static DBusConnection *systemd_con = NULL;

// QDBusObjectPath org.freedesktop.systemd1.Manager.StartUnit(QString name, QString mode)
// QDBusObjectPath org.freedesktop.systemd1.Manager.StopUnit(QString name, QString mode)


// mode = replace
// method = StartUnit or StopUnit
gboolean systemd_control_service(const char *name, const char *method)
{
DBusMessage *req = NULL;
DBusMessage *rsp = NULL;
DBusError err = DBUS_ERROR_INIT;
const char *arg = "replace";
const char *res = 0;


log_debug("%s(%s) ...", method, name);

if( !systemd_con ) {
log_err("not connected to system bus; skip systemd unit control");
goto EXIT;
}

req = dbus_message_new_method_call(SYSTEMD_DBUS_SERVICE,
SYSTEMD_DBUS_PATH,
SYSTEMD_DBUS_INTERFACE,
method);
if( !req ) {
log_err("failed to construct %s.%s request",
SYSTEMD_DBUS_INTERFACE,
method);
goto EXIT;
}

if( !dbus_message_append_args(req,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &arg,
DBUS_TYPE_INVALID))
{
log_debug("error appending arguments");
goto EXIT;
}


rsp = dbus_connection_send_with_reply_and_block(systemd_con, req, -1, &err);
if( !rsp ) {
log_err("no reply to %s.%s request: %s: %s",
SYSTEMD_DBUS_INTERFACE,
method,
err.name, err.message);
goto EXIT;
}

if( dbus_set_error_from_message(&err, rsp) ) {
log_err("got error reply to %s.%s request: %s: %s",
SYSTEMD_DBUS_INTERFACE,
method,
err.name, err.message);
goto EXIT;
}

if( !dbus_message_get_args(rsp, &err,
DBUS_TYPE_OBJECT_PATH, &res,
DBUS_TYPE_INVALID) ) {
log_err("failed to parse reply to %s.%s request: %s: %s",
SYSTEMD_DBUS_INTERFACE,
method,
err.name, err.message);
goto EXIT;
}

EXIT:

dbus_error_free(&err);

if( rsp ) dbus_message_unref(rsp);
if( req ) dbus_message_unref(req);

log_debug("%s(%s) -> %s", method, name, res ?: "N/A");

return res != 0;
}

/* ========================================================================= *
* start/stop systemd control availability
* ========================================================================= */

gboolean
systemd_control_start(void)
{
gboolean ack = FALSE;

log_debug("starting systemd control");

/* Get connection ref */
if( (systemd_con = usb_moded_dbus_get_connection()) == 0 )
{
log_err("Could not connect to dbus for systemd control\n");
goto cleanup;
}
ack = TRUE;

DBusConnection *bus;
DBusError error;
DBusMessage *msg = NULL, *reply = NULL;
gboolean ret = FALSE;
const char * replace = "replace";

dbus_error_init(&error);

log_debug("Handling %s, with systemd, method %s\n", name, method);

bus = get_systemd_dbus_connection();
if(!bus)
return(ret);

msg = dbus_message_new_method_call("org.freedesktop.systemd1",
"/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", method);
if(msg)
{
if(!dbus_message_append_args (msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &replace, DBUS_TYPE_INVALID))
{
log_debug("error appending arguments\n");
dbus_message_unref(msg);
goto quit;
}
reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &error);
if(reply)
{
dbus_message_unref(reply);
ret = TRUE;
}
dbus_message_unref(msg);
}

quit:
dbus_connection_close(bus);
dbus_connection_unref(bus);
dbus_error_free(&error);

return(ret);
cleanup:

return ack;
}

void
systemd_control_stop(void)
{
log_debug("stopping systemd control");

if(systemd_con)
{
/* Let go of connection ref */
dbus_connection_unref(systemd_con),
systemd_con = 0;
}
}
2 changes: 2 additions & 0 deletions src/usb_moded-systemd.h
Expand Up @@ -24,3 +24,5 @@
#define SYSTEMD_START "StartUnit"

gboolean systemd_control_service(const char *name, const char *method);
gboolean systemd_control_start(void);
void systemd_control_stop(void);
7 changes: 7 additions & 0 deletions src/usb_moded.c
Expand Up @@ -54,6 +54,7 @@
#include "usb_moded-network.h"
#include "usb_moded-mac.h"
#include "usb_moded-android.h"
#include "usb_moded-systemd.h"
#ifdef MEEGOLOCK
#include "usb_moded-dsme.h"
#endif
Expand Down Expand Up @@ -1197,6 +1198,11 @@ int main(int argc, char* argv[])
goto EXIT;
}

if( !systemd_control_start() ) {
log_crit("systemd control could not be started");
goto EXIT;
}

/* init daemon into a clean state first, then dbus and hw_abstraction last */
usb_moded_init();

Expand Down Expand Up @@ -1252,6 +1258,7 @@ int main(int argc, char* argv[])
EXIT:
dsme_listener_stop();
handle_exit();
systemd_control_stop();

allow_suspend();
return result;
Expand Down

0 comments on commit bae8743

Please sign in to comment.