diff --git a/android/ipc.c b/android/ipc.c
index 3d6e2a3..a996935 100644
--- a/android/ipc.c
+++ b/android/ipc.c
GIOChannel *notif_io;
guint notif_watch;
+
+ ipc_disconnect_cb disconnect_cb;
+ void *disconnect_cb_data;
};
+static void ipc_disconnect(struct ipc *ipc, bool in_cleanup)
+{
+ if (ipc->cmd_watch) {
+ g_source_remove(ipc->cmd_watch);
+ ipc->cmd_watch = 0;
+ }
+
+ if (ipc->cmd_io) {
+ g_io_channel_shutdown(ipc->cmd_io, TRUE, NULL);
+ g_io_channel_unref(ipc->cmd_io);
+ ipc->cmd_io = NULL;
+ }
+
+ if (ipc->notif_watch) {
+ g_source_remove(ipc->notif_watch);
+ ipc->notif_watch = 0;
+ }
+
+ if (ipc->notif_io) {
+ g_io_channel_shutdown(ipc->notif_io, TRUE, NULL);
+ g_io_channel_unref(ipc->notif_io);
+ ipc->notif_io = NULL;
+ }
+
+ if (in_cleanup)
+ return;
+
+ if (ipc->disconnect_cb)
+ ipc->disconnect_cb(ipc->disconnect_cb_data);
+}
+
int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
const void *buf, ssize_t len)
{
int fd, err;
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
- info("IPC: command socket closed, terminating");
+ info("IPC: command socket closed");
+
+ ipc->cmd_watch = 0;
goto fail;
}
ret = read(fd, buf, sizeof(buf));
if (ret < 0) {
- error("IPC: command read failed, terminating (%s)",
- strerror(errno));
+ error("IPC: command read failed (%s)", strerror(errno));
goto fail;
}
err = ipc_handle_msg(ipc->services, ipc->service_max, buf, ret);
if (err < 0) {
- error("IPC: failed to handle message, terminating (%s)",
- strerror(-err));
+ error("IPC: failed to handle message (%s)", strerror(-err));
goto fail;
}
return TRUE;
fail:
- raise(SIGTERM);
+ ipc_disconnect(ipc, false);
+
return FALSE;
}
static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
- info("IPC: notification socket closed, terminating");
- raise(SIGTERM);
+ struct ipc *ipc = user_data;
+
+ info("IPC: notification socket closed");
+
+ ipc->notif_watch = 0;
+
+ ipc_disconnect(ipc, false);
return FALSE;
}
DBG("");
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
- error("IPC: notification socket connect failed, terminating");
- raise(SIGTERM);
+ error("IPC: notification socket connect failed");
+
+ ipc_disconnect(ipc, false);
+
return FALSE;
}
DBG("");
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
- error("IPC: command socket connect failed, terminating");
- raise(SIGTERM);
- return FALSE;
+ error("IPC: command socket connect failed");
+ goto failed;
}
ipc->notif_io = ipc_connect(ipc->path, ipc->size, notif_connect_cb,
ipc);
if (!ipc->notif_io)
- raise(SIGTERM);
+ goto failed;
+
+ return FALSE;
+
+failed:
+ ipc_disconnect(ipc, false);
return FALSE;
}
-struct ipc *ipc_init(const char *path, size_t size, int max_service_id)
+struct ipc *ipc_init(const char *path, size_t size, int max_service_id,
+ ipc_disconnect_cb cb, void *cb_data)
{
struct ipc *ipc;
return NULL;
}
+ ipc->disconnect_cb = cb;
+ ipc->disconnect_cb_data = cb_data;
+
return ipc;
}
void ipc_cleanup(struct ipc *ipc)
{
- if (ipc->cmd_watch) {
- g_source_remove(ipc->cmd_watch);
- ipc->cmd_watch = 0;
- }
-
- if (ipc->cmd_io) {
- g_io_channel_shutdown(ipc->cmd_io, TRUE, NULL);
- g_io_channel_unref(ipc->cmd_io);
- ipc->cmd_io = NULL;
- }
-
- if (ipc->notif_watch) {
- g_source_remove(ipc->notif_watch);
- ipc->notif_watch = 0;
- }
-
- if (ipc->notif_io) {
- g_io_channel_shutdown(ipc->notif_io, TRUE, NULL);
- g_io_channel_unref(ipc->notif_io);
- ipc->notif_io = NULL;
- }
+ ipc_disconnect(ipc, true);
g_free(ipc->services);
g_free(ipc);
}
if (sendmsg(sk, &msg, 0) < 0) {
- error("IPC send failed, terminating :%s", strerror(errno));
+ error("IPC send failed :%s", strerror(errno));
+
+ /* TODO disconnect IPC here when this function becomes static */
raise(SIGTERM);
}
}
diff --git a/android/ipc.h b/android/ipc.h
index 601301c..63b751d 100644
--- a/android/ipc.h
+++ b/android/ipc.h
struct ipc;
-struct ipc *ipc_init(const char *path, size_t size, int max_service_id);
+typedef void (*ipc_disconnect_cb) (void *data);
+
+struct ipc *ipc_init(const char *path, size_t size, int max_service_id,
+ ipc_disconnect_cb cb, void *cb_data);
void ipc_cleanup(struct ipc *ipc);
GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb,
diff --git a/android/main.c b/android/main.c
index 9f22486..01f0b92 100644
--- a/android/main.c
+++ b/android/main.c
g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS, quit_eventloop, NULL);
}
+static void ipc_disconnected(void *data)
+{
+ stop_bluetooth();
+}
+
static void adapter_ready(int err, const bdaddr_t *addr)
{
if (err < 0) {
info("Adapter initialized");
hal_ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
- HAL_SERVICE_ID_MAX);
+ HAL_SERVICE_ID_MAX, ipc_disconnected, NULL);
if (!hal_ipc) {
error("Failed to initialize IPC");
exit(EXIT_FAILURE);
diff --git a/android/test-ipc.c b/android/test-ipc.c
index 054af84..9b736a2 100644
--- a/android/test-ipc.c
+++ b/android/test-ipc.c
struct context *context = create_context(data);
ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
- HAL_SERVICE_ID_MAX);
+ HAL_SERVICE_ID_MAX, NULL, NULL);
g_assert(ipc);
struct context *context = create_context(data);
ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
- HAL_SERVICE_ID_MAX);
+ HAL_SERVICE_ID_MAX, NULL, NULL);
g_assert(ipc);
const struct test_data *test_data = context->data;
ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
- HAL_SERVICE_ID_MAX);
+ HAL_SERVICE_ID_MAX, NULL, NULL);
g_assert(ipc);
struct context *context = create_context(data);
ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
- HAL_SERVICE_ID_MAX);
+ HAL_SERVICE_ID_MAX, NULL, NULL);
g_assert(ipc);