All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error
@ 2014-08-19 19:51 Szymon Janc
  2014-08-19 19:51 ` [PATCH 02/11] android/hal-ipc: Use IPC constants for return codes Szymon Janc
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

Move all error handling to notification thread. This makes single
point of error (ie exit()) and is a preparation for custom
disconnect callback.
---
 android/hal-ipc.c | 134 +++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 93 insertions(+), 41 deletions(-)

diff --git a/android/hal-ipc.c b/android/hal-ipc.c
index 363072c..1f5cc52 100644
--- a/android/hal-ipc.c
+++ b/android/hal-ipc.c
@@ -39,7 +39,7 @@ static int listen_sk = -1;
 static int cmd_sk = -1;
 static int notif_sk = -1;
 
-static pthread_mutex_t cmd_sk_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static pthread_t notif_th = 0;
 
@@ -133,6 +133,7 @@ static void *notification_handler(void *data)
 	struct iovec iv;
 	struct cmsghdr *cmsg;
 	char cmsgbuf[CMSG_SPACE(sizeof(int))];
+	bool failed = false;
 	char buf[IPC_MTU];
 	ssize_t ret;
 	int fd;
@@ -157,20 +158,22 @@ static void *notification_handler(void *data)
 		if (ret < 0) {
 			error("Receiving notifications failed: %s",
 							strerror(errno));
-			goto failed;
+			failed = true;
+			break;
 		}
 
 		/* socket was shutdown */
 		if (ret == 0) {
-			pthread_mutex_lock(&cmd_sk_mutex);
+			pthread_mutex_lock(&ipc_mutex);
 			if (cmd_sk == -1) {
-				pthread_mutex_unlock(&cmd_sk_mutex);
+				pthread_mutex_unlock(&ipc_mutex);
 				break;
 			}
-			pthread_mutex_unlock(&cmd_sk_mutex);
+			pthread_mutex_unlock(&ipc_mutex);
 
-			error("Notification socket closed");
-			goto failed;
+			error("Notification socket closed unexpectedly");
+			failed = true;
+			break;
 		}
 
 		fd = -1;
@@ -185,21 +188,25 @@ static void *notification_handler(void *data)
 			}
 		}
 
-		if (!handle_msg(buf, ret, fd))
-			goto failed;
+		if (!handle_msg(buf, ret, fd)) {
+			failed = true;
+			break;
+		}
 	}
 
+	pthread_mutex_lock(&ipc_mutex);
 	close(notif_sk);
 	notif_sk = -1;
+	pthread_mutex_unlock(&ipc_mutex);
 
 	bt_thread_disassociate();
 
 	DBG("exit");
 
-	return NULL;
+	if (failed)
+		exit(EXIT_FAILURE);
 
-failed:
-	exit(EXIT_FAILURE);
+	return NULL;
 }
 
 static int accept_connection(int sk)
@@ -238,32 +245,67 @@ bool hal_ipc_accept(void)
 {
 	int err;
 
+	pthread_mutex_lock(&ipc_mutex);
+	if (cmd_sk >= 0) {
+		close(cmd_sk);
+		cmd_sk = -1;
+	}
+
+	if (notif_sk >= 0) {
+		close(notif_sk);
+		notif_sk = -1;
+	}
+
+	/*
+	 * If notification thread is running this means accept was called
+	 * from notification thread context . We need to detach thread to not
+	 * leak resources.
+	 *
+	 * TODO should we verify if context is really notification thread?
+	 * calling accept from other thread when IPC is running is an illegal
+	 * usage anyway..
+	 */
+	if (notif_th) {
+		pthread_detach(notif_th);
+		notif_th = 0;
+	}
+
 	cmd_sk = accept_connection(listen_sk);
 	if (cmd_sk < 0)
-		return false;
+		goto failed;
 
 	notif_sk = accept_connection(listen_sk);
-	if (notif_sk < 0) {
-		close(cmd_sk);
-		cmd_sk = -1;
-		return false;
-	}
+	if (notif_sk < 0)
+		goto failed;
 
 	err = pthread_create(&notif_th, NULL, notification_handler, NULL);
 	if (err) {
 		notif_th = 0;
 		error("Failed to start notification thread: %d (%s)", err,
 							strerror(err));
+		goto failed;
+	}
+
+	pthread_mutex_unlock(&ipc_mutex);
+
+	info("IPC connected");
+
+	return true;
+
+failed:
+	if (cmd_sk >= 0) {
 		close(cmd_sk);
 		cmd_sk = -1;
+	}
+
+	if (notif_sk >= 0) {
 		close(notif_sk);
 		notif_sk = -1;
-		return false;
 	}
 
-	info("IPC connected");
+	pthread_mutex_unlock(&ipc_mutex);
 
-	return true;
+	return false;
 }
 
 bool hal_ipc_init(const char *path, size_t size)
@@ -307,23 +349,28 @@ bool hal_ipc_init(const char *path, size_t size)
 
 void hal_ipc_cleanup(void)
 {
+	pthread_t th;
+
+	pthread_mutex_lock(&ipc_mutex);
+
 	close(listen_sk);
 	listen_sk = -1;
 
-	pthread_mutex_lock(&cmd_sk_mutex);
 	if (cmd_sk >= 0) {
 		close(cmd_sk);
 		cmd_sk = -1;
 	}
-	pthread_mutex_unlock(&cmd_sk_mutex);
-
-	if (notif_sk < 0)
-		return;
 
-	shutdown(notif_sk, SHUT_RD);
+	if (notif_sk >= 0)
+		shutdown(notif_sk, SHUT_RD);
 
-	pthread_join(notif_th, NULL);
+	th = notif_th;
 	notif_th = 0;
+
+	pthread_mutex_unlock(&ipc_mutex);
+
+	if (th)
+		pthread_join(th, NULL);
 }
 
 int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
@@ -337,11 +384,6 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
 	struct ipc_status s;
 	size_t s_len = sizeof(s);
 
-	if (cmd_sk < 0) {
-		error("Invalid cmd socket passed to hal_ipc_cmd");
-		goto failed;
-	}
-
 	if (!rsp || !rsp_len) {
 		memset(&s, 0, s_len);
 		rsp_len = &s_len;
@@ -358,26 +400,29 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
 	iv[0].iov_base = &cmd;
 	iv[0].iov_len = sizeof(cmd);
 
-	iv[1].iov_base = param;
+	iv[1].iov_base = (void *) param;
 	iv[1].iov_len = len;
 
 	msg.msg_iov = iv;
 	msg.msg_iovlen = 2;
 
-	pthread_mutex_lock(&cmd_sk_mutex);
+	pthread_mutex_lock(&ipc_mutex);
+
+	if (cmd_sk < 0) {
+		error("Invalid cmd socket passed to hal_ipc_cmd");
+		goto failed_locked;
+	}
 
 	ret = sendmsg(cmd_sk, &msg, 0);
 	if (ret < 0) {
 		error("Sending command failed:%s", strerror(errno));
-		pthread_mutex_unlock(&cmd_sk_mutex);
-		goto failed;
+		goto failed_locked;
 	}
 
 	/* socket was shutdown */
 	if (ret == 0) {
 		error("Command socket closed");
-		pthread_mutex_unlock(&cmd_sk_mutex);
-		goto failed;
+		goto failed_locked;
 	}
 
 	memset(&msg, 0, sizeof(msg));
@@ -400,7 +445,7 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
 
 	ret = recvmsg(cmd_sk, &msg, 0);
 
-	pthread_mutex_unlock(&cmd_sk_mutex);
+	pthread_mutex_unlock(&ipc_mutex);
 
 	if (ret < 0) {
 		error("Receiving command response failed: %s", strerror(errno));
@@ -467,5 +512,12 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
 	return BT_STATUS_SUCCESS;
 
 failed:
-	exit(EXIT_FAILURE);
+	pthread_mutex_lock(&ipc_mutex);
+
+failed_locked:
+	if (notif_sk >= 0)
+		shutdown(notif_sk, SHUT_RD);
+	pthread_mutex_unlock(&ipc_mutex);
+
+	return BT_STATUS_FAIL;
 }
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 02/11] android/hal-ipc: Use IPC constants for return codes
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 03/11] android/hal-ipc: Allow to set custom thread and disconnect callbacks Szymon Janc
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/hal-ipc.c    | 4 ++--
 android/ipc-common.h | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/android/hal-ipc.c b/android/hal-ipc.c
index 1f5cc52..4f51c36 100644
--- a/android/hal-ipc.c
+++ b/android/hal-ipc.c
@@ -509,7 +509,7 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
 
 	*rsp_len = cmd.len;
 
-	return BT_STATUS_SUCCESS;
+	return IPC_STATUS_SUCCESS;
 
 failed:
 	pthread_mutex_lock(&ipc_mutex);
@@ -519,5 +519,5 @@ failed_locked:
 		shutdown(notif_sk, SHUT_RD);
 	pthread_mutex_unlock(&ipc_mutex);
 
-	return BT_STATUS_FAIL;
+	return IPC_STATUS_FAIL;
 }
diff --git a/android/ipc-common.h b/android/ipc-common.h
index 27736e4..958ef9e 100644
--- a/android/ipc-common.h
+++ b/android/ipc-common.h
@@ -24,6 +24,7 @@
 #define IPC_MTU 1024
 
 #define IPC_STATUS_SUCCESS	0x00
+#define IPC_STATUS_FAIL		0x01
 
 struct ipc_hdr {
 	uint8_t  service_id;
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 03/11] android/hal-ipc: Allow to set custom thread and disconnect callbacks
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
  2014-08-19 19:51 ` [PATCH 02/11] android/hal-ipc: Use IPC constants for return codes Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 04/11] android/hal-ipc: Constify param parameter Szymon Janc
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/hal-bluetooth.c | 23 ++++++++++++++++-------
 android/hal-ipc.c       | 37 ++++++++++++++++++++++++++++++-------
 android/hal-ipc.h       |  7 +++++++
 android/hal.h           |  3 ---
 4 files changed, 53 insertions(+), 17 deletions(-)

diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c
index 44eddbd..34d115d 100644
--- a/android/hal-bluetooth.c
+++ b/android/hal-bluetooth.c
@@ -253,15 +253,14 @@ static void handle_ssp_request(void *buf, uint16_t len, int fd)
 							ev->passkey);
 }
 
-void bt_thread_associate(void)
+static void thread_cb(bool associate)
 {
-	if (bt_hal_cbacks->thread_evt_cb)
-		bt_hal_cbacks->thread_evt_cb(ASSOCIATE_JVM);
-}
+	if (!bt_hal_cbacks->thread_evt_cb)
+		return;
 
-void bt_thread_disassociate(void)
-{
-	if (bt_hal_cbacks->thread_evt_cb)
+	if (associate)
+		bt_hal_cbacks->thread_evt_cb(ASSOCIATE_JVM);
+	else
 		bt_hal_cbacks->thread_evt_cb(DISASSOCIATE_JVM);
 }
 
@@ -405,6 +404,13 @@ static uint8_t get_mode(void)
 	return HAL_MODE_DEFAULT;
 }
 
+static void disconnect_cb(void *data)
+{
+	/* TODO */
+
+	exit(EXIT_FAILURE);
+}
+
 static int init(bt_callbacks_t *callbacks)
 {
 	struct hal_cmd_register_module cmd;
@@ -421,6 +427,9 @@ static int init(bt_callbacks_t *callbacks)
 	if (!hal_ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH)))
 		return BT_STATUS_FAIL;
 
+	hal_ipc_set_thread_cb(thread_cb);
+	hal_ipc_set_disconnect_cb(disconnect_cb, NULL);
+
 	bt_hal_cbacks = callbacks;
 
 	/* Start Android Bluetooth daemon service */
diff --git a/android/hal-ipc.c b/android/hal-ipc.c
index 4f51c36..7aef971 100644
--- a/android/hal-ipc.c
+++ b/android/hal-ipc.c
@@ -25,9 +25,6 @@
 #include <stdint.h>
 #include <stdlib.h>
 
-#include <cutils/properties.h>
-
-#include "hal.h"
 #include "hal-msg.h"
 #include "hal-log.h"
 #include "ipc-common.h"
@@ -43,6 +40,11 @@ static pthread_mutex_t ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static pthread_t notif_th = 0;
 
+static hal_ipc_disconnect_t disconnect_cb = NULL;
+static void *disconnect_cb_data = NULL;
+
+static hal_ipc_thread_t thread_cb = NULL;
+
 struct service_handler {
 	const struct hal_ipc_handler *handler;
 	uint8_t size;
@@ -138,7 +140,8 @@ static void *notification_handler(void *data)
 	ssize_t ret;
 	int fd;
 
-	bt_thread_associate();
+	if (thread_cb)
+		thread_cb(true);
 
 	while (true) {
 		memset(&msg, 0, sizeof(msg));
@@ -199,12 +202,17 @@ static void *notification_handler(void *data)
 	notif_sk = -1;
 	pthread_mutex_unlock(&ipc_mutex);
 
-	bt_thread_disassociate();
+	if (thread_cb)
+		thread_cb(false);
 
 	DBG("exit");
 
-	if (failed)
-		exit(EXIT_FAILURE);
+	if (failed) {
+		if (disconnect_cb)
+			disconnect_cb(disconnect_cb_data);
+		else
+			exit(EXIT_FAILURE);
+	}
 
 	return NULL;
 }
@@ -347,6 +355,17 @@ bool hal_ipc_init(const char *path, size_t size)
 	return true;
 }
 
+void hal_ipc_set_disconnect_cb(hal_ipc_disconnect_t cb, void *data)
+{
+	disconnect_cb = cb;
+	disconnect_cb_data = data;
+}
+
+void hal_ipc_set_thread_cb(hal_ipc_thread_t cb)
+{
+	thread_cb = cb;
+}
+
 void hal_ipc_cleanup(void)
 {
 	pthread_t th;
@@ -371,6 +390,10 @@ void hal_ipc_cleanup(void)
 
 	if (th)
 		pthread_join(th, NULL);
+
+	thread_cb = NULL;
+	disconnect_cb = NULL;
+	disconnect_cb_data = NULL;
 }
 
 int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
diff --git a/android/hal-ipc.h b/android/hal-ipc.h
index 08ed7cc..ddfcbd4 100644
--- a/android/hal-ipc.h
+++ b/android/hal-ipc.h
@@ -22,6 +22,13 @@ struct hal_ipc_handler {
 };
 
 bool hal_ipc_init(const char *path, size_t size);
+
+typedef void (*hal_ipc_disconnect_t)(void *data);
+void hal_ipc_set_disconnect_cb(hal_ipc_disconnect_t cb, void *data);
+
+typedef void (*hal_ipc_thread_t)(bool enable);
+void hal_ipc_set_thread_cb(hal_ipc_thread_t cb);
+
 bool hal_ipc_accept(void);
 void hal_ipc_cleanup(void);
 
diff --git a/android/hal.h b/android/hal.h
index 6998e9a..767939e 100644
--- a/android/hal.h
+++ b/android/hal.h
@@ -35,6 +35,3 @@ btrc_interface_t *bt_get_avrcp_interface(void);
 bthf_interface_t *bt_get_handsfree_interface(void);
 btgatt_interface_t *bt_get_gatt_interface(void);
 bthl_interface_t *bt_get_health_interface(void);
-
-void bt_thread_associate(void);
-void bt_thread_disassociate(void);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 04/11] android/hal-ipc: Constify param parameter
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
  2014-08-19 19:51 ` [PATCH 02/11] android/hal-ipc: Use IPC constants for return codes Szymon Janc
  2014-08-19 19:51 ` [PATCH 03/11] android/hal-ipc: Allow to set custom thread and disconnect callbacks Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 05/11] android/test: Add initial HAL IPC unit tests Szymon Janc
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

param buffer is not modified by function and should be const.
Due to non-const iov_base in struct iovec this needs to be later
casted to (void *).
---
 android/hal-ipc.c | 4 ++--
 android/hal-ipc.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/android/hal-ipc.c b/android/hal-ipc.c
index 7aef971..8f02e97 100644
--- a/android/hal-ipc.c
+++ b/android/hal-ipc.c
@@ -396,8 +396,8 @@ void hal_ipc_cleanup(void)
 	disconnect_cb_data = NULL;
 }
 
-int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
-					size_t *rsp_len, void *rsp, int *fd)
+int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
+			const void *param, size_t *rsp_len, void *rsp, int *fd)
 {
 	ssize_t ret;
 	struct msghdr msg;
diff --git a/android/hal-ipc.h b/android/hal-ipc.h
index ddfcbd4..8b7b35f 100644
--- a/android/hal-ipc.h
+++ b/android/hal-ipc.h
@@ -32,8 +32,8 @@ void hal_ipc_set_thread_cb(hal_ipc_thread_t cb);
 bool hal_ipc_accept(void);
 void hal_ipc_cleanup(void);
 
-int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
-					size_t *rsp_len, void *rsp, int *fd);
+int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
+			const void *param, size_t *rsp_len, void *rsp, int *fd);
 
 void hal_ipc_register(uint8_t service, const struct hal_ipc_handler *handlers,
 								uint8_t size);
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 05/11] android/test: Add initial HAL IPC unit tests
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
                   ` (2 preceding siblings ...)
  2014-08-19 19:51 ` [PATCH 04/11] android/hal-ipc: Constify param parameter Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 06/11] android/test: Add HAL IPC accept test Szymon Janc
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 .gitignore             |  1 +
 android/Makefile.am    |  9 ++++++++
 android/test-hal-ipc.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+)
 create mode 100644 android/test-hal-ipc.c

diff --git a/.gitignore b/.gitignore
index 1ee35e2..35e96ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -131,6 +131,7 @@ android/android-tester
 android/ipc-tester
 android/bluetoothd-snoop
 android/test-ipc
+android/test-hal-ipc
 android/test-*.log
 android/test-*.trs
 
diff --git a/android/Makefile.am b/android/Makefile.am
index 4b93c5b..bc9efe3 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -231,6 +231,15 @@ android_test_ipc_SOURCES = android/test-ipc.c \
 				android/ipc.c android/ipc.h
 android_test_ipc_LDADD = @GLIB_LIBS@
 
+unit_tests += android/test-hal-ipc
+
+android_test_hal_ipc_SOURCES = android/test-hal-ipc.c \
+				src/shared/util.h src/shared/util.c \
+				android/ipc-common.h \
+				android/hal-ipc.c android/hal-ipc.h
+android_test_hal_ipc_LDADD = @GLIB_LIBS@
+android_test_hal_ipc_LDFLAGS = $(AM_LDFLAGS) -pthread
+
 plugin_LTLIBRARIES += android/audio.a2dp.default.la
 
 android_audio_a2dp_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
diff --git a/android/test-hal-ipc.c b/android/test-hal-ipc.c
new file mode 100644
index 0000000..22b6072
--- /dev/null
+++ b/android/test-hal-ipc.c
@@ -0,0 +1,63 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib.h>
+#include "android/ipc-common.h"
+#include "android/hal-ipc.h"
+
+static const char HAL_SK_PATH[] = "\0test_hal_ipc_socket";
+
+static void test_init(void)
+{
+	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
+
+	hal_ipc_cleanup();
+
+	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
+
+	hal_ipc_cleanup();
+}
+
+int main(int argc, char *argv[])
+{
+	g_test_init(&argc, &argv, NULL);
+
+	if (!g_test_verbose())
+		fclose(stderr);
+
+	g_test_add_func("/android_hal_ipc/init", test_init);
+
+	return g_test_run();
+}
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 06/11] android/test: Add HAL IPC accept test
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
                   ` (3 preceding siblings ...)
  2014-08-19 19:51 ` [PATCH 05/11] android/test: Add initial HAL IPC unit tests Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 07/11] android/test: Add HAL IPC thread callback test Szymon Janc
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/test-hal-ipc.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/android/test-hal-ipc.c b/android/test-hal-ipc.c
index 22b6072..3321367 100644
--- a/android/test-hal-ipc.c
+++ b/android/test-hal-ipc.c
@@ -32,6 +32,8 @@
 #include <inttypes.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <sys/wait.h>
+#include <errno.h>
 
 #include <glib.h>
 #include "android/ipc-common.h"
@@ -50,6 +52,46 @@ static void test_init(void)
 	hal_ipc_cleanup();
 }
 
+static void connect_hal(void)
+{
+	struct sockaddr_un addr;
+	int sk;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+
+	memcpy(addr.sun_path, HAL_SK_PATH, sizeof(HAL_SK_PATH));
+
+	sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+
+	connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+
+	sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+	connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+}
+
+static void test_accept(void)
+{
+	pid_t pid;
+
+	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
+
+	pid = fork();
+	if (pid == 0) {
+		connect_hal();
+
+		exit(0);
+	}
+
+	g_assert(pid > 0);
+
+	g_assert(hal_ipc_accept());
+
+	hal_ipc_cleanup();
+
+	wait(NULL);
+}
+
 int main(int argc, char *argv[])
 {
 	g_test_init(&argc, &argv, NULL);
@@ -58,6 +100,7 @@ int main(int argc, char *argv[])
 		fclose(stderr);
 
 	g_test_add_func("/android_hal_ipc/init", test_init);
+	g_test_add_func("/android_hal_ipc/accept", test_accept);
 
 	return g_test_run();
 }
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 07/11] android/test: Add HAL IPC thread callback test
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
                   ` (4 preceding siblings ...)
  2014-08-19 19:51 ` [PATCH 06/11] android/test: Add HAL IPC accept test Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 08/11] android/test: Add HAL IPC disconnect tests Szymon Janc
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/test-hal-ipc.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/android/test-hal-ipc.c b/android/test-hal-ipc.c
index 3321367..b4cf071 100644
--- a/android/test-hal-ipc.c
+++ b/android/test-hal-ipc.c
@@ -92,6 +92,41 @@ static void test_accept(void)
 	wait(NULL);
 }
 
+static int thread_cb_cnt = 0;
+
+static void thread_cb(bool enable)
+{
+	g_assert((enable && !thread_cb_cnt) || (!enable && thread_cb_cnt));
+	thread_cb_cnt++;
+}
+
+static void test_thread_cb(void)
+{
+	pid_t pid;
+
+	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
+
+	pid = fork();
+	if (pid == 0) {
+		connect_hal();
+
+		exit(0);
+	}
+
+	g_assert(pid > 0);
+
+	hal_ipc_set_thread_cb(thread_cb);
+
+	g_assert(hal_ipc_accept());
+
+	hal_ipc_cleanup();
+
+	wait(NULL);
+
+	g_assert(thread_cb_cnt == 2);
+	thread_cb_cnt = 0;
+}
+
 int main(int argc, char *argv[])
 {
 	g_test_init(&argc, &argv, NULL);
@@ -101,6 +136,7 @@ int main(int argc, char *argv[])
 
 	g_test_add_func("/android_hal_ipc/init", test_init);
 	g_test_add_func("/android_hal_ipc/accept", test_accept);
+	g_test_add_func("/android_hal_ipc/thread_cb", test_thread_cb);
 
 	return g_test_run();
 }
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 08/11] android/test: Add HAL IPC disconnect tests
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
                   ` (5 preceding siblings ...)
  2014-08-19 19:51 ` [PATCH 07/11] android/test: Add HAL IPC thread callback test Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 09/11] android/test: Add HAL IPC reconnect tests Szymon Janc
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/test-hal-ipc.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 117 insertions(+), 5 deletions(-)

diff --git a/android/test-hal-ipc.c b/android/test-hal-ipc.c
index b4cf071..bc86a3e 100644
--- a/android/test-hal-ipc.c
+++ b/android/test-hal-ipc.c
@@ -34,15 +34,51 @@
 #include <sys/un.h>
 #include <sys/wait.h>
 #include <errno.h>
+#include <pthread.h>
 
 #include <glib.h>
 #include "android/ipc-common.h"
 #include "android/hal-ipc.h"
 
 static const char HAL_SK_PATH[] = "\0test_hal_ipc_socket";
+static int cmd_sk = -1;
+static int notif_sk = -1;
+
+static void disconnect_hal(bool cmd_first)
+{
+	int sk1, sk2;
+
+	if (cmd_first) {
+		sk1 = cmd_sk;
+		sk2 = notif_sk;
+	} else {
+		sk1 = notif_sk;
+		sk2 = cmd_sk;
+	}
+
+	if (sk1 >= 0) {
+		shutdown(sk1, SHUT_RDWR);
+		close(sk1);
+	}
+
+	if (sk2 >= 0) {
+		shutdown(sk2, SHUT_RDWR);
+		close(sk2);
+	}
+
+	cmd_sk = -1;
+	notif_sk = -1;
+}
+
+static void cleanup_hal(void)
+{
+	disconnect_hal(true);
+}
 
 static void test_init(void)
 {
+	cleanup_hal();
+
 	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
 
 	hal_ipc_cleanup();
@@ -55,25 +91,26 @@ static void test_init(void)
 static void connect_hal(void)
 {
 	struct sockaddr_un addr;
-	int sk;
 
 	memset(&addr, 0, sizeof(addr));
 	addr.sun_family = AF_UNIX;
 
 	memcpy(addr.sun_path, HAL_SK_PATH, sizeof(HAL_SK_PATH));
 
-	sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+	cmd_sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
 
-	connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+	connect(cmd_sk, (struct sockaddr *) &addr, sizeof(addr));
 
-	sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
-	connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+	notif_sk = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+	connect(notif_sk, (struct sockaddr *) &addr, sizeof(addr));
 }
 
 static void test_accept(void)
 {
 	pid_t pid;
 
+	cleanup_hal();
+
 	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
 
 	pid = fork();
@@ -127,6 +164,73 @@ static void test_thread_cb(void)
 	thread_cb_cnt = 0;
 }
 
+static pthread_mutex_t cv_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+static bool disconnected = false;
+
+static void disconnect_cb(void *data)
+{
+	disconnected = true;
+
+	pthread_mutex_lock(&cv_mutex);
+	pthread_cond_signal(&cv);
+	pthread_mutex_unlock(&cv_mutex);
+}
+
+static void test_disconnect(const void *data)
+{
+	pid_t pid;
+	bool cmd_first = (bool) data;
+	struct timespec ts;
+
+	cleanup_hal();
+
+	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
+
+	pid = fork();
+	if (pid == 0) {
+		connect_hal();
+		disconnect_hal(cmd_first);
+		exit(0);
+	}
+
+	g_assert(pid > 0);
+
+	hal_ipc_set_disconnect_cb(disconnect_cb, NULL);
+
+	pthread_mutex_lock(&cv_mutex);
+
+	g_assert(hal_ipc_accept());
+
+	wait(NULL);
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+	ts.tv_sec += 15;
+
+	/*
+	 * This is not needed in real usecase but here we want to test if
+	 * disconnect callback was properly called on socket shutdown so
+	 * we need to wait until it happen before calling cleanup (otherwise
+	 * we might have a race where cleanup is called before notif thread is
+	 * scheduled resulting in clean shutdown
+	 */
+	g_assert(pthread_cond_timedwait(&cv, &cv_mutex, &ts) == 0);
+	pthread_mutex_unlock(&cv_mutex);
+
+	hal_ipc_cleanup();
+
+	g_assert(disconnected);
+	disconnected = false;
+}
+
+static void test_disconnect_stress(const void *data)
+{
+	int i;
+
+	for (i = 0; i < 9999; i++)
+		test_disconnect(data);
+}
+
 int main(int argc, char *argv[])
 {
 	g_test_init(&argc, &argv, NULL);
@@ -137,6 +241,14 @@ int main(int argc, char *argv[])
 	g_test_add_func("/android_hal_ipc/init", test_init);
 	g_test_add_func("/android_hal_ipc/accept", test_accept);
 	g_test_add_func("/android_hal_ipc/thread_cb", test_thread_cb);
+	g_test_add_data_func("/android_hal_ipc/disconnect1", (void *) true,
+							test_disconnect);
+	g_test_add_data_func("/android_hal_ipc/disconnect1_stress",
+					(void *) true, test_disconnect_stress);
+	g_test_add_data_func("/android_hal_ipc/disconnect2", (void *) false,
+							test_disconnect);
+	g_test_add_data_func("/android_hal_ipc/disconnect2_stress",
+					(void *) false, test_disconnect_stress);
 
 	return g_test_run();
 }
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 09/11] android/test: Add HAL IPC reconnect tests
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
                   ` (6 preceding siblings ...)
  2014-08-19 19:51 ` [PATCH 08/11] android/test: Add HAL IPC disconnect tests Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 10/11] android/test: Add HAL IPC command tests Szymon Janc
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/test-hal-ipc.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/android/test-hal-ipc.c b/android/test-hal-ipc.c
index bc86a3e..44485c4 100644
--- a/android/test-hal-ipc.c
+++ b/android/test-hal-ipc.c
@@ -231,6 +231,82 @@ static void test_disconnect_stress(const void *data)
 		test_disconnect(data);
 }
 
+static bool reconnected = false;
+
+static void reconnect_cb(void *data)
+{
+	disconnected = true;
+
+	if (!reconnected) {
+		reconnected = true;
+		g_assert(hal_ipc_accept());
+		return;
+	}
+
+	pthread_mutex_lock(&cv_mutex);
+	pthread_cond_signal(&cv);
+	pthread_mutex_unlock(&cv_mutex);
+}
+
+static void test_reconnect(const void *data)
+{
+	pid_t pid;
+	bool cmd_first = (bool) data;
+	struct timespec ts;
+
+	cleanup_hal();
+
+	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
+
+	pid = fork();
+	if (pid == 0) {
+		connect_hal();
+		disconnect_hal(cmd_first);
+		connect_hal();
+		disconnect_hal(cmd_first);
+		exit(0);
+	}
+
+	g_assert(pid > 0);
+
+	hal_ipc_set_disconnect_cb(reconnect_cb, NULL);
+
+	pthread_mutex_lock(&cv_mutex);
+
+	g_assert(hal_ipc_accept());
+
+	wait(NULL);
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+	ts.tv_sec += 15;
+
+	/*
+	 * This is not needed in real usecase but here we want to test if
+	 * disconnect callback was properly called on socket shutdown so
+	 * we need to wait until it happen before calling cleanup (otherwise
+	 * we might have a race where cleanup is called before notif thread is
+	 * scheduled resulting in clean shutdown
+	 */
+	g_assert(pthread_cond_timedwait(&cv, &cv_mutex, &ts) == 0);
+	pthread_mutex_unlock(&cv_mutex);
+
+	hal_ipc_cleanup();
+
+	g_assert(disconnected);
+	disconnected = false;
+
+	g_assert(reconnected);
+	reconnected = false;
+}
+
+static void test_reconnect_stress(const void *data)
+{
+	int i;
+
+	for (i = 0; i < 9999; i++)
+		test_reconnect(data);
+}
+
 int main(int argc, char *argv[])
 {
 	g_test_init(&argc, &argv, NULL);
@@ -249,6 +325,14 @@ int main(int argc, char *argv[])
 							test_disconnect);
 	g_test_add_data_func("/android_hal_ipc/disconnect2_stress",
 					(void *) false, test_disconnect_stress);
+	g_test_add_data_func("/android_hal_ipc/reconnect1", (void *) true,
+							test_reconnect);
+	g_test_add_data_func("/android_hal_ipc/reconnect_stress",
+					(void *) true, test_reconnect_stress);
+	g_test_add_data_func("/android_hal_ipc/reconnect2", (void *) false,
+							test_reconnect);
+	g_test_add_data_func("/android_hal_ipc/reconnect2_stress",
+					(void *) false, test_reconnect_stress);
 
 	return g_test_run();
 }
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 10/11] android/test: Add HAL IPC command tests
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
                   ` (7 preceding siblings ...)
  2014-08-19 19:51 ` [PATCH 09/11] android/test: Add HAL IPC reconnect tests Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-19 19:51 ` [PATCH 11/11] doc: Add Android test-hal-ipc test numbers to coverage list Szymon Janc
  2014-08-20 10:38 ` [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Luiz Augusto von Dentz
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/test-hal-ipc.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)

diff --git a/android/test-hal-ipc.c b/android/test-hal-ipc.c
index 44485c4..0a858ee 100644
--- a/android/test-hal-ipc.c
+++ b/android/test-hal-ipc.c
@@ -307,6 +307,161 @@ static void test_reconnect_stress(const void *data)
 		test_reconnect(data);
 }
 
+struct test_cmd_data {
+	uint8_t service_id;
+	uint8_t opcode;
+
+	uint16_t len;
+	const void *param;
+
+	size_t rsp_len;
+	const void *rsp;
+};
+
+static void signal_action(int sig)
+{
+}
+
+static void wait_for_signal(void)
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = signal_action;
+	sigaction(SIGUSR1, &sa, NULL);
+	sigaction(SIGALRM, &sa, NULL);
+
+	alarm(5);
+
+	pause();
+}
+
+static int handle_cmd(const void *data)
+{
+	const struct test_cmd_data *cdata = data;
+	char buf[100];
+	struct ipc_hdr *hdr = (void *) buf;
+	int ret;
+	int result = 0;
+
+	ret = read(cmd_sk, buf, sizeof(buf));
+	if (ret != cdata->len + (int) sizeof(*hdr))
+		result = 1;
+
+	if (hdr->opcode != cdata->opcode)
+		result = 2;
+
+	if (hdr->service_id != cdata->service_id)
+		result = 3;
+
+	if (memcmp(hdr->payload, cdata->param, hdr->len))
+		result = 4;
+
+	memcpy(hdr->payload, cdata->rsp, cdata->rsp_len);
+	hdr->len = cdata->rsp_len;
+
+	write(cmd_sk, hdr, sizeof(*hdr) + hdr->len);
+
+	return result;
+}
+
+static void send_cmd(const void *data)
+{
+	const struct test_cmd_data *cdata = data;
+	char buf[100];
+	char *rsp;
+	size_t rsp_len;
+
+	rsp = cdata->rsp_len ? buf : NULL;
+	rsp_len = cdata->rsp_len;
+
+	g_assert(hal_ipc_cmd(cdata->service_id, cdata->opcode, cdata->len,
+				cdata->param, &rsp_len, rsp,
+				NULL) == IPC_STATUS_SUCCESS);
+
+	g_assert(cdata->rsp_len == rsp_len);
+	if (cdata->rsp_len)
+		g_assert(memcmp(cdata->rsp, rsp, cdata->rsp_len) == 0);
+}
+
+static void cmd_cb(void *data)
+{
+	g_assert(FALSE);
+}
+
+static void test_command(const void *data)
+{
+	pid_t pid;
+	int status;
+
+	cleanup_hal();
+
+	g_assert(hal_ipc_init(HAL_SK_PATH, sizeof(HAL_SK_PATH)));
+	hal_ipc_set_disconnect_cb(cmd_cb, NULL);
+
+	pid = fork();
+	if (pid == 0) {
+		int ret;
+
+		connect_hal();
+		ret = handle_cmd(data);
+		wait_for_signal();
+		exit(ret);
+	}
+
+	g_assert(pid > 0);
+
+	g_assert(hal_ipc_accept());
+
+	send_cmd(data);
+
+	hal_ipc_cleanup();
+
+	kill(pid, SIGUSR1);
+	wait(&status);
+
+	g_assert(status == 0);
+}
+
+static const char cmd_data[] = { 0x01, 0x02, 0x03, 0x04 };
+static const char rsp_data[] = { 0x06, 0x07 };
+
+static const struct test_cmd_data cmd1 = {
+	.service_id = 1,
+	.opcode = 2,
+	.len = 0,
+	.param = NULL,
+	.rsp_len = 0,
+	.rsp = NULL,
+};
+
+static const struct test_cmd_data cmd2 = {
+	.service_id = 1,
+	.opcode = 2,
+	.len = sizeof(cmd_data),
+	.param = cmd_data,
+	.rsp_len = 0,
+	.rsp = NULL,
+};
+
+static const struct test_cmd_data cmd3 = {
+	.service_id = 1,
+	.opcode = 2,
+	.len = sizeof(cmd_data),
+	.param = cmd_data,
+	.rsp_len = sizeof(rsp_data),
+	.rsp = rsp_data,
+};
+
+static const struct test_cmd_data cmd4 = {
+	.service_id = 1,
+	.opcode = 2,
+	.len = 0,
+	.param = NULL,
+	.rsp_len = sizeof(rsp_data),
+	.rsp = rsp_data,
+};
+
 int main(int argc, char *argv[])
 {
 	g_test_init(&argc, &argv, NULL);
@@ -333,6 +488,10 @@ int main(int argc, char *argv[])
 							test_reconnect);
 	g_test_add_data_func("/android_hal_ipc/reconnect2_stress",
 					(void *) false, test_reconnect_stress);
+	g_test_add_data_func("/android_hal_ipc/command1", &cmd1, test_command);
+	g_test_add_data_func("/android_hal_ipc/command2", &cmd2, test_command);
+	g_test_add_data_func("/android_hal_ipc/command3", &cmd3, test_command);
+	g_test_add_data_func("/android_hal_ipc/command4", &cmd4, test_command);
 
 	return g_test_run();
 }
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 11/11] doc: Add Android test-hal-ipc test numbers to coverage list
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
                   ` (8 preceding siblings ...)
  2014-08-19 19:51 ` [PATCH 10/11] android/test: Add HAL IPC command tests Szymon Janc
@ 2014-08-19 19:51 ` Szymon Janc
  2014-08-20 10:38 ` [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Luiz Augusto von Dentz
  10 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-19 19:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 doc/test-coverage.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index c460d35..e08d8b8 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -65,5 +65,6 @@ Android automated unit testing
 Application		Count	Description
 -------------------------------------------
 test-ipc		  14	Android IPC library functions
+test-hal-ipc		  15	Android IPC HAL library functions
 			-----
-			  14
+			  29
-- 
1.9.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error
  2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
                   ` (9 preceding siblings ...)
  2014-08-19 19:51 ` [PATCH 11/11] doc: Add Android test-hal-ipc test numbers to coverage list Szymon Janc
@ 2014-08-20 10:38 ` Luiz Augusto von Dentz
  2014-08-20 11:22   ` Szymon Janc
  10 siblings, 1 reply; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2014-08-20 10:38 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth

Hi Szymon,

On Tue, Aug 19, 2014 at 10:51 PM, Szymon Janc <szymon.janc@tieto.com> wrote:
> Move all error handling to notification thread. This makes single
> point of error (ie exit()) and is a preparation for custom
> disconnect callback.

Does this imply every ipc must have a notification thread? iirc this
was not the case for audio.

> ---
>  android/hal-ipc.c | 134 +++++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 93 insertions(+), 41 deletions(-)
>
> diff --git a/android/hal-ipc.c b/android/hal-ipc.c
> index 363072c..1f5cc52 100644
> --- a/android/hal-ipc.c
> +++ b/android/hal-ipc.c
> @@ -39,7 +39,7 @@ static int listen_sk = -1;
>  static int cmd_sk = -1;
>  static int notif_sk = -1;
>
> -static pthread_mutex_t cmd_sk_mutex = PTHREAD_MUTEX_INITIALIZER;
> +static pthread_mutex_t ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
>
>  static pthread_t notif_th = 0;
>
> @@ -133,6 +133,7 @@ static void *notification_handler(void *data)
>         struct iovec iv;
>         struct cmsghdr *cmsg;
>         char cmsgbuf[CMSG_SPACE(sizeof(int))];
> +       bool failed = false;
>         char buf[IPC_MTU];
>         ssize_t ret;
>         int fd;
> @@ -157,20 +158,22 @@ static void *notification_handler(void *data)
>                 if (ret < 0) {
>                         error("Receiving notifications failed: %s",
>                                                         strerror(errno));
> -                       goto failed;
> +                       failed = true;
> +                       break;
>                 }
>
>                 /* socket was shutdown */
>                 if (ret == 0) {
> -                       pthread_mutex_lock(&cmd_sk_mutex);
> +                       pthread_mutex_lock(&ipc_mutex);
>                         if (cmd_sk == -1) {
> -                               pthread_mutex_unlock(&cmd_sk_mutex);
> +                               pthread_mutex_unlock(&ipc_mutex);
>                                 break;
>                         }
> -                       pthread_mutex_unlock(&cmd_sk_mutex);
> +                       pthread_mutex_unlock(&ipc_mutex);
>
> -                       error("Notification socket closed");
> -                       goto failed;
> +                       error("Notification socket closed unexpectedly");
> +                       failed = true;
> +                       break;
>                 }
>
>                 fd = -1;
> @@ -185,21 +188,25 @@ static void *notification_handler(void *data)
>                         }
>                 }
>
> -               if (!handle_msg(buf, ret, fd))
> -                       goto failed;
> +               if (!handle_msg(buf, ret, fd)) {
> +                       failed = true;
> +                       break;
> +               }
>         }
>
> +       pthread_mutex_lock(&ipc_mutex);
>         close(notif_sk);
>         notif_sk = -1;
> +       pthread_mutex_unlock(&ipc_mutex);
>
>         bt_thread_disassociate();
>
>         DBG("exit");
>
> -       return NULL;
> +       if (failed)
> +               exit(EXIT_FAILURE);
>
> -failed:
> -       exit(EXIT_FAILURE);
> +       return NULL;
>  }
>
>  static int accept_connection(int sk)
> @@ -238,32 +245,67 @@ bool hal_ipc_accept(void)
>  {
>         int err;
>
> +       pthread_mutex_lock(&ipc_mutex);
> +       if (cmd_sk >= 0) {
> +               close(cmd_sk);
> +               cmd_sk = -1;
> +       }
> +
> +       if (notif_sk >= 0) {
> +               close(notif_sk);
> +               notif_sk = -1;
> +       }
> +
> +       /*
> +        * If notification thread is running this means accept was called
> +        * from notification thread context . We need to detach thread to not
> +        * leak resources.
> +        *
> +        * TODO should we verify if context is really notification thread?
> +        * calling accept from other thread when IPC is running is an illegal
> +        * usage anyway..
> +        */
> +       if (notif_th) {
> +               pthread_detach(notif_th);
> +               notif_th = 0;
> +       }
> +
>         cmd_sk = accept_connection(listen_sk);
>         if (cmd_sk < 0)
> -               return false;
> +               goto failed;
>
>         notif_sk = accept_connection(listen_sk);
> -       if (notif_sk < 0) {
> -               close(cmd_sk);
> -               cmd_sk = -1;
> -               return false;
> -       }
> +       if (notif_sk < 0)
> +               goto failed;
>
>         err = pthread_create(&notif_th, NULL, notification_handler, NULL);
>         if (err) {
>                 notif_th = 0;
>                 error("Failed to start notification thread: %d (%s)", err,
>                                                         strerror(err));
> +               goto failed;
> +       }
> +
> +       pthread_mutex_unlock(&ipc_mutex);
> +
> +       info("IPC connected");
> +
> +       return true;
> +
> +failed:
> +       if (cmd_sk >= 0) {
>                 close(cmd_sk);
>                 cmd_sk = -1;
> +       }
> +
> +       if (notif_sk >= 0) {
>                 close(notif_sk);
>                 notif_sk = -1;
> -               return false;
>         }
>
> -       info("IPC connected");
> +       pthread_mutex_unlock(&ipc_mutex);
>
> -       return true;
> +       return false;
>  }
>
>  bool hal_ipc_init(const char *path, size_t size)
> @@ -307,23 +349,28 @@ bool hal_ipc_init(const char *path, size_t size)
>
>  void hal_ipc_cleanup(void)
>  {
> +       pthread_t th;
> +
> +       pthread_mutex_lock(&ipc_mutex);
> +
>         close(listen_sk);
>         listen_sk = -1;
>
> -       pthread_mutex_lock(&cmd_sk_mutex);
>         if (cmd_sk >= 0) {
>                 close(cmd_sk);
>                 cmd_sk = -1;
>         }
> -       pthread_mutex_unlock(&cmd_sk_mutex);
> -
> -       if (notif_sk < 0)
> -               return;
>
> -       shutdown(notif_sk, SHUT_RD);
> +       if (notif_sk >= 0)
> +               shutdown(notif_sk, SHUT_RD);
>
> -       pthread_join(notif_th, NULL);
> +       th = notif_th;
>         notif_th = 0;
> +
> +       pthread_mutex_unlock(&ipc_mutex);
> +
> +       if (th)
> +               pthread_join(th, NULL);
>  }
>
>  int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
> @@ -337,11 +384,6 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
>         struct ipc_status s;
>         size_t s_len = sizeof(s);
>
> -       if (cmd_sk < 0) {
> -               error("Invalid cmd socket passed to hal_ipc_cmd");
> -               goto failed;
> -       }
> -
>         if (!rsp || !rsp_len) {
>                 memset(&s, 0, s_len);
>                 rsp_len = &s_len;
> @@ -358,26 +400,29 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
>         iv[0].iov_base = &cmd;
>         iv[0].iov_len = sizeof(cmd);
>
> -       iv[1].iov_base = param;
> +       iv[1].iov_base = (void *) param;

Does this change is really necessary?

>         iv[1].iov_len = len;
>
>         msg.msg_iov = iv;
>         msg.msg_iovlen = 2;
>
> -       pthread_mutex_lock(&cmd_sk_mutex);
> +       pthread_mutex_lock(&ipc_mutex);
> +
> +       if (cmd_sk < 0) {
> +               error("Invalid cmd socket passed to hal_ipc_cmd");
> +               goto failed_locked;
> +       }
>
>         ret = sendmsg(cmd_sk, &msg, 0);
>         if (ret < 0) {
>                 error("Sending command failed:%s", strerror(errno));
> -               pthread_mutex_unlock(&cmd_sk_mutex);
> -               goto failed;
> +               goto failed_locked;
>         }
>
>         /* socket was shutdown */
>         if (ret == 0) {
>                 error("Command socket closed");
> -               pthread_mutex_unlock(&cmd_sk_mutex);
> -               goto failed;
> +               goto failed_locked;
>         }
>
>         memset(&msg, 0, sizeof(msg));
> @@ -400,7 +445,7 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
>
>         ret = recvmsg(cmd_sk, &msg, 0);
>
> -       pthread_mutex_unlock(&cmd_sk_mutex);
> +       pthread_mutex_unlock(&ipc_mutex);
>
>         if (ret < 0) {
>                 error("Receiving command response failed: %s", strerror(errno));
> @@ -467,5 +512,12 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
>         return BT_STATUS_SUCCESS;
>
>  failed:
> -       exit(EXIT_FAILURE);
> +       pthread_mutex_lock(&ipc_mutex);
> +
> +failed_locked:
> +       if (notif_sk >= 0)
> +               shutdown(notif_sk, SHUT_RD);
> +       pthread_mutex_unlock(&ipc_mutex);

Perhaps having ipc_shutdown would be a good idea here, it should
probably only be called with the lock being held, also if notif_sk is
not set perhaps it should shutdown the cmd_sk otherwise it can have no
effect.

> +
> +       return BT_STATUS_FAIL;
>  }
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error
  2014-08-20 10:38 ` [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Luiz Augusto von Dentz
@ 2014-08-20 11:22   ` Szymon Janc
  0 siblings, 0 replies; 13+ messages in thread
From: Szymon Janc @ 2014-08-20 11:22 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hi Luiz,

On Wednesday 20 of August 2014 13:38:28 Luiz Augusto von Dentz wrote:
> Hi Szymon,
> 
> On Tue, Aug 19, 2014 at 10:51 PM, Szymon Janc <szymon.janc@tieto.com> wrote:
> > Move all error handling to notification thread. This makes single
> > point of error (ie exit()) and is a preparation for custom
> > disconnect callback.
> 
> Does this imply every ipc must have a notification thread? iirc this
> was not the case for audio.

The idea is to use notification thread for detecting IPC shutdown.
But you are right that on audio we don't connect second socket. Both sockets
could be always connected (even when notifications are not used) or hal-ipc
could have flag for notification support (similar to daemon ipc part) and
use correct socket for watching.

I'll see which one fits better.

> 
> > ---
> > 
> >  android/hal-ipc.c | 134
> >  +++++++++++++++++++++++++++++++++++++----------------- 1 file changed,
> >  93 insertions(+), 41 deletions(-)
> > 
> > diff --git a/android/hal-ipc.c b/android/hal-ipc.c
> > index 363072c..1f5cc52 100644
> > --- a/android/hal-ipc.c
> > +++ b/android/hal-ipc.c
> > @@ -39,7 +39,7 @@ static int listen_sk = -1;
> > 
> >  static int cmd_sk = -1;
> >  static int notif_sk = -1;
> > 
> > -static pthread_mutex_t cmd_sk_mutex = PTHREAD_MUTEX_INITIALIZER;
> > +static pthread_mutex_t ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
> > 
> >  static pthread_t notif_th = 0;
> > 
> > @@ -133,6 +133,7 @@ static void *notification_handler(void *data)
> > 
> >         struct iovec iv;
> >         struct cmsghdr *cmsg;
> >         char cmsgbuf[CMSG_SPACE(sizeof(int))];
> > 
> > +       bool failed = false;
> > 
> >         char buf[IPC_MTU];
> >         ssize_t ret;
> >         int fd;
> > 
> > @@ -157,20 +158,22 @@ static void *notification_handler(void *data)
> > 
> >                 if (ret < 0) {
> >                 
> >                         error("Receiving notifications failed: %s",
> >                         
> >                                                         strerror(errno));
> > 
> > -                       goto failed;
> > +                       failed = true;
> > +                       break;
> > 
> >                 }
> >                 
> >                 /* socket was shutdown */
> >                 if (ret == 0) {
> > 
> > -                       pthread_mutex_lock(&cmd_sk_mutex);
> > +                       pthread_mutex_lock(&ipc_mutex);
> > 
> >                         if (cmd_sk == -1) {
> > 
> > -                               pthread_mutex_unlock(&cmd_sk_mutex);
> > +                               pthread_mutex_unlock(&ipc_mutex);
> > 
> >                                 break;
> >                         
> >                         }
> > 
> > -                       pthread_mutex_unlock(&cmd_sk_mutex);
> > +                       pthread_mutex_unlock(&ipc_mutex);
> > 
> > -                       error("Notification socket closed");
> > -                       goto failed;
> > +                       error("Notification socket closed unexpectedly");
> > +                       failed = true;
> > +                       break;
> > 
> >                 }
> >                 
> >                 fd = -1;
> > 
> > @@ -185,21 +188,25 @@ static void *notification_handler(void *data)
> > 
> >                         }
> >                 
> >                 }
> > 
> > -               if (!handle_msg(buf, ret, fd))
> > -                       goto failed;
> > +               if (!handle_msg(buf, ret, fd)) {
> > +                       failed = true;
> > +                       break;
> > +               }
> > 
> >         }
> > 
> > +       pthread_mutex_lock(&ipc_mutex);
> > 
> >         close(notif_sk);
> >         notif_sk = -1;
> > 
> > +       pthread_mutex_unlock(&ipc_mutex);
> > 
> >         bt_thread_disassociate();
> >         
> >         DBG("exit");
> > 
> > -       return NULL;
> > +       if (failed)
> > +               exit(EXIT_FAILURE);
> > 
> > -failed:
> > -       exit(EXIT_FAILURE);
> > +       return NULL;
> > 
> >  }
> >  
> >  static int accept_connection(int sk)
> > 
> > @@ -238,32 +245,67 @@ bool hal_ipc_accept(void)
> > 
> >  {
> >  
> >         int err;
> > 
> > +       pthread_mutex_lock(&ipc_mutex);
> > +       if (cmd_sk >= 0) {
> > +               close(cmd_sk);
> > +               cmd_sk = -1;
> > +       }
> > +
> > +       if (notif_sk >= 0) {
> > +               close(notif_sk);
> > +               notif_sk = -1;
> > +       }
> > +
> > +       /*
> > +        * If notification thread is running this means accept was called
> > +        * from notification thread context . We need to detach thread to
> > not +        * leak resources.
> > +        *
> > +        * TODO should we verify if context is really notification thread?
> > +        * calling accept from other thread when IPC is running is an
> > illegal +        * usage anyway..
> > +        */
> > +       if (notif_th) {
> > +               pthread_detach(notif_th);
> > +               notif_th = 0;
> > +       }
> > +
> > 
> >         cmd_sk = accept_connection(listen_sk);
> >         if (cmd_sk < 0)
> > 
> > -               return false;
> > +               goto failed;
> > 
> >         notif_sk = accept_connection(listen_sk);
> > 
> > -       if (notif_sk < 0) {
> > -               close(cmd_sk);
> > -               cmd_sk = -1;
> > -               return false;
> > -       }
> > +       if (notif_sk < 0)
> > +               goto failed;
> > 
> >         err = pthread_create(&notif_th, NULL, notification_handler, NULL);
> >         if (err) {
> >         
> >                 notif_th = 0;
> >                 error("Failed to start notification thread: %d (%s)", err,
> >                 
> >                                                         strerror(err));
> > 
> > +               goto failed;
> > +       }
> > +
> > +       pthread_mutex_unlock(&ipc_mutex);
> > +
> > +       info("IPC connected");
> > +
> > +       return true;
> > +
> > +failed:
> > +       if (cmd_sk >= 0) {
> > 
> >                 close(cmd_sk);
> >                 cmd_sk = -1;
> > 
> > +       }
> > +
> > +       if (notif_sk >= 0) {
> > 
> >                 close(notif_sk);
> >                 notif_sk = -1;
> > 
> > -               return false;
> > 
> >         }
> > 
> > -       info("IPC connected");
> > +       pthread_mutex_unlock(&ipc_mutex);
> > 
> > -       return true;
> > +       return false;
> > 
> >  }
> >  
> >  bool hal_ipc_init(const char *path, size_t size)
> > 
> > @@ -307,23 +349,28 @@ bool hal_ipc_init(const char *path, size_t size)
> > 
> >  void hal_ipc_cleanup(void)
> >  {
> > 
> > +       pthread_t th;
> > +
> > +       pthread_mutex_lock(&ipc_mutex);
> > +
> > 
> >         close(listen_sk);
> >         listen_sk = -1;
> > 
> > -       pthread_mutex_lock(&cmd_sk_mutex);
> > 
> >         if (cmd_sk >= 0) {
> >         
> >                 close(cmd_sk);
> >                 cmd_sk = -1;
> >         
> >         }
> > 
> > -       pthread_mutex_unlock(&cmd_sk_mutex);
> > -
> > -       if (notif_sk < 0)
> > -               return;
> > 
> > -       shutdown(notif_sk, SHUT_RD);
> > +       if (notif_sk >= 0)
> > +               shutdown(notif_sk, SHUT_RD);
> > 
> > -       pthread_join(notif_th, NULL);
> > +       th = notif_th;
> > 
> >         notif_th = 0;
> > 
> > +
> > +       pthread_mutex_unlock(&ipc_mutex);
> > +
> > +       if (th)
> > +               pthread_join(th, NULL);
> > 
> >  }
> >  
> >  int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void
> >  *param,> 
> > @@ -337,11 +384,6 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode,
> > uint16_t len, void *param,> 
> >         struct ipc_status s;
> >         size_t s_len = sizeof(s);
> > 
> > -       if (cmd_sk < 0) {
> > -               error("Invalid cmd socket passed to hal_ipc_cmd");
> > -               goto failed;
> > -       }
> > -
> > 
> >         if (!rsp || !rsp_len) {
> >         
> >                 memset(&s, 0, s_len);
> >                 rsp_len = &s_len;
> > 
> > @@ -358,26 +400,29 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode,
> > uint16_t len, void *param,> 
> >         iv[0].iov_base = &cmd;
> >         iv[0].iov_len = sizeof(cmd);
> > 
> > -       iv[1].iov_base = param;
> > +       iv[1].iov_base = (void *) param;
> 
> Does this change is really necessary?
> 
> >         iv[1].iov_len = len;
> >         
> >         msg.msg_iov = iv;
> >         msg.msg_iovlen = 2;
> > 
> > -       pthread_mutex_lock(&cmd_sk_mutex);
> > +       pthread_mutex_lock(&ipc_mutex);
> > +
> > +       if (cmd_sk < 0) {
> > +               error("Invalid cmd socket passed to hal_ipc_cmd");
> > +               goto failed_locked;
> > +       }
> > 
> >         ret = sendmsg(cmd_sk, &msg, 0);
> >         if (ret < 0) {
> >         
> >                 error("Sending command failed:%s", strerror(errno));
> > 
> > -               pthread_mutex_unlock(&cmd_sk_mutex);
> > -               goto failed;
> > +               goto failed_locked;
> > 
> >         }
> >         
> >         /* socket was shutdown */
> >         if (ret == 0) {
> >         
> >                 error("Command socket closed");
> > 
> > -               pthread_mutex_unlock(&cmd_sk_mutex);
> > -               goto failed;
> > +               goto failed_locked;
> > 
> >         }
> >         
> >         memset(&msg, 0, sizeof(msg));
> > 
> > @@ -400,7 +445,7 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode,
> > uint16_t len, void *param,> 
> >         ret = recvmsg(cmd_sk, &msg, 0);
> > 
> > -       pthread_mutex_unlock(&cmd_sk_mutex);
> > +       pthread_mutex_unlock(&ipc_mutex);
> > 
> >         if (ret < 0) {
> >         
> >                 error("Receiving command response failed: %s",
> >                 strerror(errno));
> > 
> > @@ -467,5 +512,12 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode,
> > uint16_t len, void *param,> 
> >         return BT_STATUS_SUCCESS;
> >  
> >  failed:
> > -       exit(EXIT_FAILURE);
> > +       pthread_mutex_lock(&ipc_mutex);
> > +
> > +failed_locked:
> > +       if (notif_sk >= 0)
> > +               shutdown(notif_sk, SHUT_RD);
> > +       pthread_mutex_unlock(&ipc_mutex);
> 
> Perhaps having ipc_shutdown would be a good idea here, it should
> probably only be called with the lock being held, also if notif_sk is
> not set perhaps it should shutdown the cmd_sk otherwise it can have no
> effect.
> 
> > +
> > +       return BT_STATUS_FAIL;
> > 
> >  }
> > 
> > --
> > 1.9.3
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth"
> > in the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
BR
Szymon Janc

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2014-08-20 11:22 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-19 19:51 [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Szymon Janc
2014-08-19 19:51 ` [PATCH 02/11] android/hal-ipc: Use IPC constants for return codes Szymon Janc
2014-08-19 19:51 ` [PATCH 03/11] android/hal-ipc: Allow to set custom thread and disconnect callbacks Szymon Janc
2014-08-19 19:51 ` [PATCH 04/11] android/hal-ipc: Constify param parameter Szymon Janc
2014-08-19 19:51 ` [PATCH 05/11] android/test: Add initial HAL IPC unit tests Szymon Janc
2014-08-19 19:51 ` [PATCH 06/11] android/test: Add HAL IPC accept test Szymon Janc
2014-08-19 19:51 ` [PATCH 07/11] android/test: Add HAL IPC thread callback test Szymon Janc
2014-08-19 19:51 ` [PATCH 08/11] android/test: Add HAL IPC disconnect tests Szymon Janc
2014-08-19 19:51 ` [PATCH 09/11] android/test: Add HAL IPC reconnect tests Szymon Janc
2014-08-19 19:51 ` [PATCH 10/11] android/test: Add HAL IPC command tests Szymon Janc
2014-08-19 19:51 ` [PATCH 11/11] doc: Add Android test-hal-ipc test numbers to coverage list Szymon Janc
2014-08-20 10:38 ` [PATCH 01/11] android/hal-ipc: Refactor handling of IPC error Luiz Augusto von Dentz
2014-08-20 11:22   ` Szymon Janc

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.