Commit 6f6d4fc7 authored by spiiroin's avatar spiiroin

Merge branch 'mer1694_startup_and_exit' into 'master'

Fix issues related to usb-moded startup, exit and dbus usage



See merge request !20
parents 836d79fe f3a01678
......@@ -2,8 +2,11 @@
@file usb_moded-appsync.c
Copyright (C) 2010 Nokia Corporation. All rights reserved.
Copyright (C) 2013-2016 Jolla Ltd.
@author: Philippe De Swert <philippe.de-swert@nokia.com>
@author: Philippe De Swert <philippe.deswert@jollamobile.com>
@author: Simo Piiroinen <simo.piiroinen@jollamobile.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public License
......@@ -259,9 +262,8 @@ int activate_sync(const char *mode)
if(data->systemd)
{
if(!systemd_control_service(data->name, SYSTEMD_START))
mark_active(data->name, 0);
else
goto error;
mark_active(data->name, 0);
}
else if(data->launch)
{
......@@ -320,7 +322,7 @@ int activate_sync_post(const char *mode)
log_debug("launching post-enum-app %s\n", data->name);
if(data->systemd)
{
if(systemd_control_service(data->name, SYSTEMD_START))
if(!systemd_control_service(data->name, SYSTEMD_START))
goto error;
mark_active(data->name, 1);
}
......@@ -442,14 +444,14 @@ static void appsync_stop_apps(int post)
if(data->systemd && data->state == APP_STATE_ACTIVE && data->post == post)
{
log_debug("stopping %s-enum-app %s", post ? "post" : "pre", data->name);
if(systemd_control_service(data->name, SYSTEMD_STOP))
if(!systemd_control_service(data->name, SYSTEMD_STOP))
log_debug("Failed to stop %s\n", data->name);
data->state = APP_STATE_DONTCARE;
}
}
}
int appsync_stop(int force)
int appsync_stop(gboolean force)
{
/* If force arg is used, stop all applications that
* could have been started by usb-moded */
......
/*
Copyright (C) 2010 Nokia Corporation. All rights reserved.
Copyright (C) 2013-2016 Jolla Ltd.
author: Philippe De Swert <philippe.de-swert@nokia.com>
author: Philippe De Swert <philippe.deswert@jollamobile.com>
author: Simo Piiroinen <simo.piiroinen@jollamobile.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public License
......@@ -57,6 +60,6 @@ void readlist(int diag);
int activate_sync(const char *mode);
int activate_sync_post(const char *mode);
int mark_active(const gchar *name, int post);
int appsync_stop(int force);
int appsync_stop(gboolean force);
void free_appsync_list(void);
void usb_moded_appsync_cleanup(void);
/*
Copyright (C) 2010 Nokia Corporation. All rights reserved.
Copyright (C) 2013-2016 Jolla Ltd.
Author: Philippe De Swert <philippe.de-swert@nokia.com>
Author: Philippe De Swert <philippe.deswert@jollamobile.com>
Author: Vesa Halttunen <vesa.halttunen@jollamobile.com>
Author: Martin Jones <martin.jones@jollamobile.com>
Author: Simo Piiroinen <simo.piiroinen@jollamobile.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public License
......@@ -18,8 +23,20 @@
02110-1301 USA
*/
/* initialize dbus communication channels */
gboolean usb_moded_dbus_init(void);
/** Logical name for org.freedesktop.DBus.GetNameOwner method */
#define DBUS_GET_NAME_OWNER_REQ "GetNameOwner"
/** Logical name for org.freedesktop.DBus.NameOwnerChanged signal */
#define DBUS_NAME_OWNER_CHANGED_SIG "NameOwnerChanged"
/* Connect to D-Bus System Bus */
gboolean usb_moded_dbus_init_connection(void);
/* Claim D-Bus Service Name */
gboolean usb_moded_dbus_init_service(void);
/* Get current SystemBus connection */
DBusConnection *usb_moded_dbus_get_connection(void);
/* cleanup usb on exit */
void usb_moded_dbus_cleanup(void);
......@@ -35,3 +52,11 @@ int usb_moded_send_supported_modes_signal(const char *supported_modes);
/* send hidden modes signal system bus */
int usb_moded_send_hidden_modes_signal(const char *hidden_modes);
/* Callback function type used with usb_moded_get_name_owner_async() */
typedef void (*usb_moded_get_name_owner_fn)(const char *owner);
/* Asynchronous GetNameOwner query */
gboolean usb_moded_get_name_owner_async(const char *name,
usb_moded_get_name_owner_fn cb,
DBusPendingCall **ppc);
......@@ -2,10 +2,11 @@
@file usb_moded-dbus.c
Copyright (C) 2010 Nokia Corporation. All rights reserved.
Copyright (C) 2012-2015 Jolla. All rights reserved.
Copyright (C) 2012-2016 Jolla. All rights reserved.
@author: Philippe De Swert <philippe.de-swert@nokia.com>
@author: Philippe De Swert <philippe.deswert@jollamobile.com>
@author: Simo Piiroinen <simo.piiroinen@jollamobile.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public License
......@@ -44,6 +45,8 @@
#define INIT_DONE_MATCH "type='signal',interface='"INIT_DONE_INTERFACE"',member='"INIT_DONE_SIGNAL"'"
static DBusConnection *dbus_connection_sys = NULL;
static gboolean have_service_name = FALSE;
extern gboolean rescue_mode;
/**
......@@ -52,7 +55,12 @@ extern gboolean rescue_mode;
static void usb_moded_send_config_signal(const char *section, const char *key, const char *value)
{
log_debug(USB_MODE_CONFIG_SIGNAL_NAME ": %s %s %s\n", section, key, value);
if (dbus_connection_sys)
if( !have_service_name )
{
log_err("config notification without service: [%s] %s=%s",
section, key, value);
}
else if (dbus_connection_sys)
{
DBusMessage* msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, USB_MODE_CONFIG_SIGNAL_NAME);
if (msg) {
......@@ -451,7 +459,6 @@ error_reply:
}
}
EXIT:
if(reply)
......@@ -467,18 +474,25 @@ EXIT:
return status;
}
DBusConnection *usb_moded_dbus_get_connection(void)
{
DBusConnection *connection = 0;
if( dbus_connection_sys )
connection = dbus_connection_ref(dbus_connection_sys);
else
log_err("something asked for connection ref while unconnected");
return connection;
}
/**
* Init dbus for usb_moded
* Establish D-Bus SystemBus connection
*
* @return TRUE when everything went ok
*/
gboolean usb_moded_dbus_init(void)
gboolean usb_moded_dbus_init_connection(void)
{
gboolean status = FALSE;
DBusError error;
int ret;
dbus_error_init(&error);
DBusError error = DBUS_ERROR_INIT;
/* connect to system bus */
if ((dbus_connection_sys = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL)
......@@ -491,6 +505,35 @@ gboolean usb_moded_dbus_init(void)
if (!dbus_connection_add_filter(dbus_connection_sys, msg_handler, NULL, NULL))
goto EXIT;
/* Listen to init-done signals */
dbus_bus_add_match(dbus_connection_sys, INIT_DONE_MATCH, 0);
/* Connect D-Bus to the mainloop */
dbus_connection_setup_with_g_main(dbus_connection_sys, NULL);
/* everything went fine */
status = TRUE;
EXIT:
dbus_error_free(&error);
return status;
}
/**
* Reserve "com.meego.usb_moded" D-Bus Service Name
*
* @return TRUE when everything went ok
*/
gboolean usb_moded_dbus_init_service(void)
{
gboolean status = FALSE;
DBusError error = DBUS_ERROR_INIT;
int ret;
if( !dbus_connection_sys ) {
goto EXIT;
}
/* Acquire D-Bus service */
ret = dbus_bus_request_name(dbus_connection_sys, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
......@@ -500,19 +543,8 @@ gboolean usb_moded_dbus_init(void)
log_debug("DBUS ERROR: %s, %s \n", error.name, error.message);
goto EXIT;
}
/* only match on signals/methods we support (if needed)
dbus_bus_add_match(dbus_connection_sys, USB_MODE_INTERFACE, &error);
*/
/* Listen to init-done signals */
dbus_bus_add_match(dbus_connection_sys, INIT_DONE_MATCH, 0);
dbus_threads_init_default();
/* Connect D-Bus to the mainloop */
dbus_connection_setup_with_g_main(dbus_connection_sys, NULL);
log_debug("claimed name %s", USB_MODE_SERVICE);
have_service_name = TRUE;
/* everything went fine */
status = TRUE;
......@@ -521,20 +553,42 @@ EXIT:
return status;
}
/** Release "com.meego.usb_moded" D-Bus Service Name
*/
static void usb_moded_dbus_cleanup_service(void)
{
if( !have_service_name )
goto EXIT;
have_service_name = FALSE;
log_debug("release name %s", USB_MODE_SERVICE);
if( dbus_connection_sys &&
dbus_connection_get_is_connected(dbus_connection_sys) )
{
dbus_bus_release_name(dbus_connection_sys, USB_MODE_SERVICE, NULL);
}
EXIT:
return;
}
/**
* Clean up the dbus connections on exit
*
*/
void usb_moded_dbus_cleanup(void)
{
/* clean up system bus connection */
if (dbus_connection_sys != NULL)
{
dbus_bus_release_name(dbus_connection_sys, USB_MODE_SERVICE, NULL);
dbus_connection_remove_filter(dbus_connection_sys, msg_handler, NULL);
dbus_connection_unref(dbus_connection_sys);
dbus_connection_sys = NULL;
}
/* clean up system bus connection */
if (dbus_connection_sys != NULL)
{
usb_moded_dbus_cleanup_service();
dbus_connection_remove_filter(dbus_connection_sys, msg_handler, NULL);
dbus_connection_unref(dbus_connection_sys),
dbus_connection_sys = NULL;
}
}
/**
......@@ -549,6 +603,12 @@ static int usb_moded_dbus_signal(const char *signal_type, const char *content)
int result = 1;
DBusMessage* msg = 0;
if( !have_service_name )
{
log_err("sending signal without service: %s(%s)",
signal_type, content);
goto EXIT;
}
if(!dbus_connection_sys)
{
log_err("Dbus system connection broken!\n");
......@@ -632,3 +692,104 @@ int usb_moded_send_hidden_modes_signal(const char *hidden_modes)
{
return(usb_moded_dbus_signal(USB_MODE_HIDDEN_MODES_SIGNAL_NAME, hidden_modes));
}
/** Async reply handler for usb_moded_get_name_owner_async()
*
* @param pc Pending call object pointer
* @param aptr Notify function to call (as a void pointer)
*/
static void usb_moded_get_name_owner_cb(DBusPendingCall *pc, void *aptr)
{
usb_moded_get_name_owner_fn cb = aptr;
DBusMessage *rsp = 0;
const char *dta = 0;
DBusError err = DBUS_ERROR_INIT;
if( !(rsp = dbus_pending_call_steal_reply(pc)) ) {
log_err("did not get reply");
goto EXIT;
}
if( dbus_set_error_from_message(&err, rsp) )
{
if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) )
log_err("error reply: %s: %s", err.name, err.message);
goto EXIT;
}
if( !dbus_message_get_args(rsp, &err,
DBUS_TYPE_STRING, &dta,
DBUS_TYPE_INVALID) )
{
if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) )
log_err("parse error: %s: %s", err.name, err.message);
goto EXIT;
}
EXIT:
/* Allways call the notification function. Equate any error
* situations with "service does not have an owner". */
cb(dta ?: "");
if( rsp ) dbus_message_unref(rsp);
dbus_error_free(&err);
}
/** Helper function for making async dbus name owner queries
*
* @param name D-Bus name to query
* @param cb Function to call when async reply is received
* @param ppc Where to store pending call object, or NULL
*
* @return TRUE if method call was sent, FALSE otherwise
*/
gboolean usb_moded_get_name_owner_async(const char *name,
usb_moded_get_name_owner_fn cb,
DBusPendingCall **ppc)
{
gboolean ack = FALSE;
DBusMessage *req = 0;
DBusPendingCall *pc = 0;
if(!dbus_connection_sys)
goto EXIT;
req = dbus_message_new_method_call(DBUS_INTERFACE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
DBUS_GET_NAME_OWNER_REQ);
if( !req ) {
log_err("could not create method call message");
goto EXIT;
}
if( !dbus_message_append_args(req,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID) ) {
log_err("could not add method call parameters");
goto EXIT;
}
if( !dbus_connection_send_with_reply(dbus_connection_sys, req, &pc, -1) )
goto EXIT;
if( !pc )
goto EXIT;
if( !dbus_pending_call_set_notify(pc, usb_moded_get_name_owner_cb, cb, 0) )
goto EXIT;
ack = TRUE;
if( ppc )
*ppc = pc, pc = 0;
EXIT:
if( pc ) dbus_pending_call_unref(pc);
if( req ) dbus_message_unref(req);
return ack;
}
/**
@file: usb_moded-devicelock.c
Copyright (C) 2010 Nokia Corporation. All rights reserved.
Copyright (C) 2013-2016 Jolla Ltd.
@author: Philippe De Swert <philippe.de-swert@nokia.com>
@author: Philippe De Swert <philippe.deswert@jollamobile.com>
@author: Jonni Rainisto <jonni.rainisto@jollamobile.com>
@author: Vesa Halttunen <vesa.halttunen@jollamobile.com>
@author: Simo Piiroinen <simo.piiroinen@jollamobile.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public License
version 2 as published by the Free Software Foundation.
modify it under the terms of the Lesser 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.
You should have received a copy of the Lesser GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
* Interacts with the devicelock to know if we can expose the system contents or not
*/
* Interacts with the devicelock to know if we can expose the system contents or not
*/
/*============================================================================= */
......@@ -36,122 +42,389 @@
#include "usb_moded-log.h"
#include "usb_moded.h"
#include "usb_moded-modes.h"
#include "usb_moded-dbus-private.h"
/* ========================================================================= *
* devicelock state type
* ========================================================================= */
/** Devicelock states */
typedef enum
{
/** Devicelock is not active */
DEVICE_LOCK_UNLOCKED = 0,
/** Devicelock is active */
DEVICE_LOCK_LOCKED = 1,
/** Initial startup value; from usb-moded p.o.v. equals locked */
DEVICE_LOCK_UNDEFINED = 2,
} devicelock_state_t;
/** Return human readable representation of devicelock state enum
*/
static const char *
devicelock_state_repr(devicelock_state_t state)
{
const char *repr = "DEVICE_LOCK_<INVALID>";
static DBusHandlerResult devicelock_unlocked_cb(DBusConnection *conn, DBusMessage *msg, void *user_data);
switch( state )
{
case DEVICE_LOCK_UNLOCKED: repr = "DEVICE_LOCK_UNLOCKED"; break;
case DEVICE_LOCK_LOCKED: repr = "DEVICE_LOCK_LOCKED"; break;
case DEVICE_LOCK_UNDEFINED: repr = "DEVICE_LOCK_UNDEFINED"; break;
default: break;
}
return repr;
}
/* ========================================================================= *
* module state data
* ========================================================================= */
/* SystemBus connection ref used for devicelock ipc */
static DBusConnection *devicelock_con = NULL;
/* Cached devicelock state */
static devicelock_state_t device_lock_state = DEVICE_LOCK_UNDEFINED;
/* Flag for: devicelock is available on system bus */
static gboolean devicelock_is_available = FALSE;
/* ========================================================================= *
* functionality provided to the other modules
* ========================================================================= */
DBusConnection *dbus_conn_devicelock = NULL;
/** Checks if the device is locked.
*
*
* @return 0 for unlocked, 1 for locked
*
*/
int usb_moded_get_export_permission(void)
{
DBusConnection *dbus_conn_devicelock = NULL;
DBusMessage *msg = NULL, *reply = NULL;
DBusError error;
int ret = 2;
dbus_error_init(&error);
if( (dbus_conn_devicelock = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == 0 )
{
log_err("Could not connect to dbus for devicelock\n");
}
if ((msg = dbus_message_new_method_call(DEVICELOCK_SERVICE, DEVICELOCK_REQUEST_PATH, DEVICELOCK_REQUEST_IF, DEVICELOCK_STATE_REQ)) != NULL)
{
/* default dbus timeout is too long, timeout after 1,5 seconds */
if ((reply = dbus_connection_send_with_reply_and_block(dbus_conn_devicelock, msg, 1500, NULL)) != NULL)
{
dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32, &ret, DBUS_TYPE_INVALID);
dbus_message_unref(reply);
}
dbus_message_unref(msg);
}
dbus_connection_unref(dbus_conn_devicelock);
log_debug("devicelock state = %d\n", ret);
return(ret);
gboolean unlocked = (device_lock_state == DEVICE_LOCK_UNLOCKED);
// FIXME: this is reverse from what function name makes to expect
return unlocked ? 0 : 1;
}
int start_devicelock_listener(void)
/* ========================================================================= *
* devicelock state queries
* ========================================================================= */
static void devicelock_state_changed(devicelock_state_t state)
{
DBusError err = DBUS_ERROR_INIT;
if( device_lock_state != state ) {
log_debug("devicelock state: %s -> %s",
devicelock_state_repr(device_lock_state),
devicelock_state_repr(state));
device_lock_state = state;
if( (dbus_conn_devicelock = dbus_bus_get(DBUS_BUS_SYSTEM, &err)) == 0 )
{
log_err("Could not connect to dbus for devicelock\n");
goto cleanup;
}
if( device_lock_state == DEVICE_LOCK_UNLOCKED &&
get_usb_connection_state() == 1 )
{
const char *usb_mode = get_usb_mode();
log_debug("usb_mode %s\n", usb_mode);
dbus_bus_add_match(dbus_conn_devicelock, MATCH_DEVICELOCK_SIGNALS, &err);
if( dbus_error_is_set(&err) )
{
goto cleanup;
}
if( !dbus_connection_add_filter(dbus_conn_devicelock, devicelock_unlocked_cb , 0, 0) )
{
log_err("adding system dbus filter for devicelock failed");
goto cleanup;
}
//dbus_connection_setup_with_g_main(dbus_conn_devicelock, NULL);
/* if the mode is MODE_CHARGING_FALLBACK we know the user
* has not selected any mode, in case it things are still
* undefined it cannot hurt to try again to set a mode */
if(!strcmp(usb_mode, MODE_UNDEFINED) ||
!strcmp(usb_mode, MODE_CHARGING_FALLBACK))
{
log_debug("set_usb");
set_usb_connected_state();
}
}
}
}
cleanup:
dbus_error_free(&err);
return(1);
static DBusPendingCall *devicelock_state_query_pc = 0;
static void devicelock_state_cancel(void)
{
if( devicelock_state_query_pc ) {
dbus_pending_call_cancel(devicelock_state_query_pc);
dbus_pending_call_unref(devicelock_state_query_pc),
devicelock_state_query_pc = 0;
}
}
int stop_devicelock_listener(void)
static void devicelock_state_query_cb(DBusPendingCall *pending, void *aptr)
{
if(dbus_conn_devicelock)
{
dbus_connection_remove_filter(dbus_conn_devicelock, devicelock_unlocked_cb, NULL);
dbus_bus_remove_match(dbus_conn_devicelock, MATCH_DEVICELOCK_SIGNALS, NULL);
dbus_connection_unref(dbus_conn_devicelock);
}
DBusMessage *rsp = 0;
dbus_int32_t dta = DEVICE_LOCK_UNDEFINED;
DBusError err = DBUS_ERROR_INIT;
(void)aptr;
if( !(rsp = dbus_pending_call_steal_reply(pending)) )
{
log_err("%s.%s: no reply",
DEVICELOCK_INTERFACE, DEVICELOCK_GET_STATE_REQ);
goto EXIT;
}
if( dbus_set_error_from_message(&err, rsp) )
{
log_err("%s.%s: error reply: %s: %s",
DEVICELOCK_INTERFACE, DEVICELOCK_GET_STATE_REQ,
err.name, err.message);
goto EXIT;
}
return 0;
if( !dbus_message_get_args(rsp, &err, DBUS_TYPE_INT32, &dta,
DBUS_TYPE_INVALID) )
{
log_err("%s.%s: parse error: %s: %s",
DEVICELOCK_INTERFACE, DEVICELOCK_GET_STATE_REQ,
err.name, err.message);
goto EXIT;
}
EXIT:
devicelock_state_changed(dta);
if( rsp ) dbus_message_unref(rsp);
dbus_error_free(&err);
dbus_pending_call_unref(devicelock_state_query_pc),
devicelock_state_query_pc = 0;
}
static DBusHandlerResult devicelock_unlocked_cb(DBusConnection *conn, DBusMessage *msg, void *user_data)
{
/* regardless what happens, we want that other programs get a chance to process this */
DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
const char *interface = dbus_message_get_interface(msg);
const char *member = dbus_message_get_member(msg);
const char *object = dbus_message_get_path(msg);
int type = dbus_message_get_type(msg);
int ret=0;
(void) user_data;
// sanity checks
if( !interface || !member || !object ) goto cleanup;
if( type != DBUS_MESSAGE_TYPE_SIGNAL ) goto cleanup;
if( strcmp(interface, DEVICELOCK_REQUEST_IF) ) goto cleanup;
if( strcmp(object, DEVICELOCK_REQUEST_PATH) ) goto cleanup;
// handle known signals
else if( !strcmp(member, "stateChanged") )
{
dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &ret, DBUS_TYPE_INVALID);
log_debug("Devicelock state changed. New state = %d\n", ret);
if(ret == 0 && get_usb_connection_state() == 1 )
{
log_debug("usb_mode %s\n", get_usb_mode());
/* if the mode is MODE_CHARGING_FALLBACK we know the user has not selected any mode, in case it
things are still undefined it cannot hurt to try again to set a mode */
if(!strcmp(get_usb_mode(), MODE_UNDEFINED) || !strcmp(get_usb_mode(), MODE_CHARGING_FALLBACK))
{
log_debug("set_usb");
set_usb_connected_state();
}
}
}
static void devicelock_state_query(void)
{
DBusMessage *req = NULL;
DBusPendingCall *pc = 0;
devicelock_state_cancel();
log_debug("querying device lock state");
if( !devicelock_con ) {
log_err("not connected to system bus; skip device state query");
goto EXIT;
}
req = dbus_message_new_method_call(DEVICELOCK_SERVICE,
DEVICELOCK_OBJECT,
DEVICELOCK_INTERFACE,
DEVICELOCK_GET_STATE_REQ);
if( !req )
{
log_err("%s.%s: failed to construct request",
DEVICELOCK_INTERFACE, DEVICELOCK_GET_STATE_REQ);
goto EXIT;
}
if( !dbus_connection_send_with_reply(devicelock_con, req, &pc, -1) )
goto EXIT;
if( !pc )
goto EXIT;
if( !dbus_pending_call_set_notify(pc, devicelock_state_query_cb, 0, 0) )
goto EXIT;
devicelock_state_query_pc = pc, pc = 0;
EXIT:
if( pc ) dbus_pending_call_unref(pc);
if( req ) dbus_message_unref(req);
}