Support asynchronous plugin initializer
authorJiwan Kim <ji-wan.kim@samsung.com>
Mon, 3 Apr 2017 06:33:56 +0000 (15:33 +0900)
committersaerome.kim <saerome.kim@samsung.com>
Thu, 11 May 2017 09:10:26 +0000 (18:10 +0900)
- To support firmware update on plugin initialize time,
  asynchronous init function is required.
- Add support logic for async initializer.

Change-Id: Ie8631a62c0fdb97cef87383bf075e3e346880a97
Signed-off-by: Jiwan Kim <ji-wan.kim@samsung.com>
zigbee-daemon/src/main.c
zigbee-daemon/zigbee-interface/src/zigbee_service_dbus_interface.c
zigbee-daemon/zigbee-lib/include/zblib.h
zigbee-daemon/zigbee-lib/include/zblib_driver_manager.h [new file with mode: 0644]
zigbee-daemon/zigbee-lib/include/zblib_plugin.h
zigbee-daemon/zigbee-lib/include/zblib_service.h
zigbee-daemon/zigbee-lib/src/zblib_service.c
zigbee-daemon/zigbee-service/src/zigbee_service.c

index 05895ff..78639c3 100644 (file)
 /**< ZigBee Service */
 ZigBeeService *zigbee_service;
 
+static gboolean _request_terminate(gpointer user_data)
+{
+       NOTUSED(user_data);
+
+       zblib_service_exit(zigbee_service);
+
+       return G_SOURCE_REMOVE;
+}
+
 int main(int arg, char **argv)
 {
        ZigBeeService *service = NULL;
@@ -49,8 +58,6 @@ int main(int arg, char **argv)
        NOTUSED(arg);
        NOTUSED(argv);
 
-       Z_LOGI("service mainloop start");
-
        /* Create ZigBee service */
        zigbee_service = service = zblib_service_new();
 
@@ -65,10 +72,12 @@ int main(int arg, char **argv)
        ret = zigbee_service_init(service);
        if (G_UNLIKELY(FALSE == ret)) {
                Z_LOGE("zigbee_service_init failed!");
-               goto END;
+               /* Minimum mainloop time is required to notify the result */
+               g_timeout_add(100, _request_terminate, NULL);
        }
 
        /* Run ZigBee service */
+       Z_LOGI("service mainloop start");
        ret = zblib_service_run(service);
        if (G_UNLIKELY(FALSE == ret)) {
                Z_LOGE("Run service failed!");
index 3f729d5..97111d9 100644 (file)
@@ -26,6 +26,7 @@
 #include <zblib.h>
 #include <zblib_service.h>
 #include <zblib_service_interface.h>
+#include <zblib_driver_manager.h>
 
 #include "zigbee_service_interface.h"
 #include "zigbee_service_interface_common.h"
 /**< ZigBee D-BUS service interface name */
 #define ZIGBEE_DBUS_SERVICE_INTERFACE_NAME "zigbee-dbus"
 
+static void _notify_zigbee_state(ZigBeeServiceInterface *service_interface,
+               gboolean result)
+{
+       ZigbeeCustomData_t *custom_data = zblib_service_interface_ref_user_data(service_interface);
+       ZigBeeService *service = zblib_service_interface_ref_service(service_interface);
+
+       if (NULL == custom_data) {
+               Z_LOGE("Unexpected invalid parameter !");
+               return;
+       }
+
+       if (result) {
+               /* Notify zigbee service manually here (Enabled) */
+               zigbee_manager_emit_zigbee_state(custom_data->zigbee_mgr, result);
+       } else {
+               /* ZigBee state will be emitted on bus termination */
+               zblib_service_exit(service);
+       }
+}
+
 static gboolean on_manager_enable(ZigbeeManager *zigbee_mgr,
        GDBusMethodInvocation *invocation,
        gpointer user_data)
@@ -49,11 +70,6 @@ static gboolean on_manager_enable(ZigbeeManager *zigbee_mgr,
 
        zigbee_manager_complete_enable(zigbee_mgr, invocation);
 
-       if (TRUE == custom_data->sevice_interface_init_complete) {
-               /* Emit zigbee_state - enabled */
-               zigbee_manager_emit_zigbee_state(zigbee_mgr, TRUE);
-       }
-
        return TRUE;
 }
 
@@ -291,6 +307,18 @@ static void zigbee_service_dbus_interface_noti_cb(ZigBeeServiceInterface *servic
        }
        break;
 
+       case ZBLIB_DRIVER_TYPE_MANAGER: {
+               /* Handle 'enabled' notification here */
+               if (notification_id == ZBLIB_MANAGER_NOTI_ZIGBEE_ENABLED) {
+                       gboolean *rsp = (gboolean*)noti_data;
+
+                       Z_LOGD("Firmware update result : [%s]", ((*rsp) ? "Succeed" : "Failed"));
+                       _notify_zigbee_state(service_interface, *rsp);
+               } else
+                       Z_LOGE("Unhandled notification id: [%d]", notification_id);
+       }
+       break;
+
        case ZBLIB_DRIVER_TYPE_NONE: /* Fall through */
        default: {
                Z_LOGE("Unhandled driver type: [%d]", driver_type);
@@ -329,11 +357,6 @@ static void zigbee_on_name_acquired(GDBusConnection *connection,
 
        /* Bus name is 'acquired' */
        custom_data->name_acquired = TRUE;
-
-       if (TRUE == custom_data->sevice_interface_init_complete) {
-               /* Emit zigbee_state - enabled */
-               zigbee_manager_emit_zigbee_state(custom_data->zigbee_mgr, TRUE);
-       }
 }
 
 static void zigbee_on_bus_acquired(GDBusConnection *connection,
@@ -591,6 +614,10 @@ void zigbee_service_dbus_interface_deinit(ZigBeeService *service)
                goto EXIT;
        }
 
+       /* Emit zigbee_state - disabled */
+       Z_LOGD("Update zigbee_state ----");
+       zigbee_manager_emit_zigbee_state(interface_data->zigbee_mgr, FALSE);
+
        /*
         * Unown "org.tizen.zigbee.manager" named bus on D-BUS SYSTEM bus
         */
index d439aa5..2fc35ac 100644 (file)
@@ -61,6 +61,7 @@ typedef struct zblib_request_type ZigBeeRequest;
 /**< ZigBee driver types */
 typedef enum {
        ZBLIB_DRIVER_TYPE_NONE, /**< None */
+       ZBLIB_DRIVER_TYPE_MANAGER, /**< Manager */
        ZBLIB_DRIVER_TYPE_SERVICE, /**< Service */
        ZBLIB_DRIVER_TYPE_ZDO_DEV_CONTROL, /**< ZDO Dev control */
        ZBLIB_DRIVER_TYPE_ZDO_BIND, /**< ZDO bind */
diff --git a/zigbee-daemon/zigbee-lib/include/zblib_driver_manager.h b/zigbee-daemon/zigbee-lib/include/zblib_driver_manager.h
new file mode 100644 (file)
index 0000000..5b5bafa
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Suresh Kumar N (suresh.n@samsung.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ZIGBEE_LIB_DRIVER_MANAGER_H__
+#define __ZIGBEE_LIB_DRIVER_MANAGER_H__
+
+/**< ZigBee 'Manager' notification IDs */
+typedef enum {
+       ZBLIB_MANAGER_NOTI_ZIGBEE_ENABLED = 1, /**< Zigbee enabled */
+} ZblibManagerNoti_e;
+
+#endif /* __ZIGBEE_LIB_DRIVER_MANAGER_H__ */
index c901a96..cd77d97 100644 (file)
 #ifndef __ZIGBEE_LIB_PLUGIN_H__
 #define __ZIGBEE_LIB_PLUGIN_H__
 
+/**< ZigBee plug-in asynchronous initializer callback */
+typedef void (*zblib_plugin_init_finished_cb)(gboolean result, void *user_data);
+
 /**< ZigBee plug-in descriptor */
 typedef struct {
        const gchar *name;
        int version;
-       gboolean (*is_implemented)(); /**< Is plug-in implemented */
        gboolean (*load)(); /**< Load plugin */
        gboolean (*init)(ZigBeePlugin *); /**< Initialize plugin */
+       gboolean (*init_async)(ZigBeePlugin *, zblib_plugin_init_finished_cb, void *);
+                       /**< Initialize plugin asynchronously */
        void (*unload)(ZigBeePlugin *); /**< Unload plugin */
 } ZblibPluginDescriptor_t;
 
index 6034098..e0dc480 100644 (file)
@@ -30,6 +30,7 @@ gboolean zblib_service_remove_plugin(ZigBeeService *service, ZigBeePlugin *plugi
 
 gboolean zblib_service_load_plugins(ZigBeeService *service, const char *plugin_path);
 gboolean zblib_service_initialize_plugins(ZigBeeService *service);
+gboolean zblib_service_initialize_async_plugins(ZigBeeService *service);
 gboolean zblib_service_unload_plugins(ZigBeeService *service);
 
 GSList *zblib_service_ref_plugins(ZigBeeService *service);
index 681dc31..72e26e7 100644 (file)
 #include <zblib_plugin.h>
 #include <zblib_service_interface.h>
 #include <zblib_request.h>
+#include <zblib_driver.h>
+#include <zblib_driver_manager.h>
+
+struct _zblib_async_init_info {
+       gboolean is_initialized; /**< Does initialization succeeded? */
+       gboolean is_finished; /**< Does initialization finished? */
+
+       ZigBeePlugin *plugin; /**< ZigBee plugin */
+       void *user_data; /**< User data */
+};
 
 /**< ZigBee Service object */
 struct zblib_service_type {
@@ -34,8 +44,95 @@ struct zblib_service_type {
 
        GHashTable *request_table; /**< Request Hash table */
        guint request_id; /**< Request ID */
+
+       GSList *async_initializer; /**< Hash table for asynchronous initializer */
+       zblib_plugin_init_finished_cb callback; /**< Callback */
 };
 
+static GSList *__zblib_service_ref_async_initializer(ZigBeeService* service)
+{
+       zblib_check_null_ret_error("service", service, NULL);
+
+       return service->async_initializer;
+}
+
+static void __zblib_service_set_async_initializer(ZigBeeService* service, GSList* list)
+{
+       zblib_check_null_ret("service", service);
+
+       service->async_initializer = list;
+}
+
+static void __on_zblib_init_async_finished(gboolean result, void *user_data)
+{
+       GSList *list_async = NULL;
+       ZigBeeService *service = NULL;
+       ZigBeePlugin *plugin = NULL;
+       struct _zblib_async_init_info *info = (struct _zblib_async_init_info*)user_data;
+       char *plugin_name = NULL;
+
+       int i = 0;
+       int _finished_count = 0;
+       int _succeeded_count = 0;
+
+       zblib_check_null_ret("info", info);
+
+       plugin = info->plugin;
+       service = zblib_plugin_ref_service(plugin);
+       plugin_name = zblib_plugin_get_plugin_name(plugin);
+
+       zblib_check_null_ret("service", service);
+
+       info->is_finished = TRUE;
+       if (result) {
+               Z_LOGD("Plugin [%s] succeeded async init", plugin_name);
+               info->is_initialized = TRUE;
+       } else {
+               Z_LOGE("Plugin [%s] failed to init !", plugin_name);
+       }
+       g_free(plugin_name);
+
+       /* Check all async initializer list */
+       list_async = __zblib_service_ref_async_initializer(service);
+       while (list_async != NULL) {
+               /* Initialize each plug-in */
+               struct _zblib_async_init_info *in =
+                               (struct _zblib_async_init_info *)(list_async->data);
+               i++;
+               if (G_UNLIKELY(NULL == in)) {
+                       Z_LOGE("Invalid parameter !");
+                       list_async = g_slist_next(list_async);
+                       continue;
+               }
+
+               if (in->is_finished)
+                       _finished_count++;
+               if (in->is_initialized)
+                       _succeeded_count++;
+
+               list_async = g_slist_next(list_async);
+       }
+
+       if (i == _finished_count) {
+               gboolean ret = TRUE;
+               guint driver_noti_id = (ZBLIB_DRIVER_TYPE_MANAGER << 24)
+                               | ZBLIB_MANAGER_NOTI_ZIGBEE_ENABLED;
+
+               if (_finished_count == _succeeded_count) {
+                       /* All initializer finished successfully */
+                       Z_LOGD("All async init finished !");
+                       ret = TRUE;
+               } else {
+                       /* Some initializers are failed */
+                       Z_LOGE("There are some failed plugin initializer !");
+                       ret = FALSE;
+               }
+               /* Notify whether zigbee service is enabled or not */
+               zblib_plugin_send_notification(plugin,
+                       driver_noti_id, &ret, sizeof(ret));
+       }
+}
+
 static void *__zblib_service_load_plugin(gchar *filename,
        ZblibPluginDescriptor_t **descriptor_out)
 {
@@ -97,7 +194,10 @@ static gboolean __zblib_service_init_plugin(ZigBeePlugin *plugin)
        const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin);
 
        zblib_check_null_ret_error("descriptor", descriptor, FALSE);
-       zblib_check_null_ret_error("descriptor->init", descriptor->init, FALSE);
+       if (NULL == descriptor->init) {
+               Z_LOGD("descriptor->init is NULL, trying async init");
+               return FALSE;
+       }
 
        if (G_UNLIKELY(FALSE == descriptor->init(plugin))) {
                char *plugin_name = zblib_plugin_get_plugin_name(plugin);
@@ -111,6 +211,28 @@ static gboolean __zblib_service_init_plugin(ZigBeePlugin *plugin)
        return TRUE;
 }
 
+static gboolean __zblib_service_init_async_plugin(ZigBeePlugin *plugin,
+               zblib_plugin_init_finished_cb callback, void *user_data)
+{
+       const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin);
+       char *plugin_name = zblib_plugin_get_plugin_name(plugin);
+
+       zblib_check_null_ret_error("descriptor", descriptor, FALSE);
+       zblib_check_null_ret_error("descriptor->init_async", descriptor->init_async, FALSE);
+
+       if (G_UNLIKELY(NULL != plugin_name))
+               plugin_name = g_strdup("NONAME");
+
+       if (G_UNLIKELY(FALSE == descriptor->init_async(plugin, callback, user_data))) {
+               Z_LOGE("plugin(%s) init failed!", plugin_name);
+               g_free(plugin_name);
+               return FALSE;
+       }
+
+       g_free(plugin_name);
+       return TRUE;
+}
+
 static gboolean __zblib_service_unload_plugin(ZigBeePlugin *plugin)
 {
        const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin);
@@ -193,6 +315,12 @@ void zblib_service_free(ZigBeeService *service)
                }
        }
 
+       /* Free async initializer */
+       if (service->async_initializer) {
+               g_slist_free(service->async_initializer);
+               service->async_initializer = NULL;
+       }
+
        /* Free plug-ins */
        if (service->plugins) {
                g_slist_free(service->plugins);
@@ -315,20 +443,74 @@ gboolean zblib_service_load_plugins(ZigBeeService *service, const char *plugin_p
 gboolean zblib_service_initialize_plugins(ZigBeeService *service)
 {
        GSList *list;
+       GSList *list_async;
 
        zblib_check_null_ret_error("service", service, FALSE);
 
        /* Refer plug-in list */
        list = zblib_service_ref_plugins(service);
+       list_async = __zblib_service_ref_async_initializer(service);
        while (list != NULL) {
                /* Initialize each plug-in */
-               if (G_UNLIKELY(FALSE == __zblib_service_init_plugin((ZigBeePlugin *)(list->data)))) {
-                       list = g_slist_next(list);
-                       continue;
+               ZigBeePlugin *plugin = (ZigBeePlugin *)(list->data);
+               if (FALSE == __zblib_service_init_plugin(plugin)) {
+                       /* If there is no initializer, it should have asynchronous one */
+                       const ZblibPluginDescriptor_t *descriptor =
+                                       zblib_plugin_get_descriptor(plugin);
+                       if (NULL != descriptor->init_async) {
+                               /* Register async initializer */
+                               struct _zblib_async_init_info *info =
+                                       g_try_new0(struct _zblib_async_init_info, 1);
+                               if(NULL == info) {
+                                       Z_LOGE("Fatal : Failed to allocate memory");
+                                       return FALSE;
+                               }
+                               info->is_finished = FALSE;
+                               info->is_initialized = FALSE;
+                               info->plugin = plugin;
+                               info->user_data = NULL;
+
+                               list_async = g_slist_append(list_async, info);
+                       } else {
+                               Z_LOGE("Fatal : Failed to initialize plugin");
+                               return FALSE;
+                       }
                }
                list = g_slist_next(list);
        }
 
+       __zblib_service_set_async_initializer(service, list_async);
+
+       return TRUE;
+}
+
+gboolean zblib_service_initialize_async_plugins(ZigBeeService *service)
+{
+       GSList *list_async;
+
+       zblib_check_null_ret_error("service", service, FALSE);
+
+       /* Refer async initializer list */
+       list_async = __zblib_service_ref_async_initializer(service);
+       while (list_async != NULL) {
+               /* Initialize each plug-in */
+               struct _zblib_async_init_info *info =
+                               (struct _zblib_async_init_info *)(list_async->data);
+
+               if (G_UNLIKELY(NULL == info)) {
+                       Z_LOGE("Invalid parameter !");
+                       list_async = g_slist_next(list_async);
+                       continue;
+               }
+
+               if (G_UNLIKELY(FALSE == __zblib_service_init_async_plugin(
+                                       info->plugin, __on_zblib_init_async_finished, info))) {
+                       Z_LOGE("Fatal : Failed to initialize mandatory plugin");
+                       return FALSE;
+               }
+               list_async = g_slist_next(list_async);
+       }
+
        return TRUE;
 }
 
index d80dbf7..b2a7284 100644 (file)
@@ -56,7 +56,15 @@ gboolean zigbee_service_init(ZigBeeService *service)
                return FALSE;
        }
 
-       Z_TIME_CHECK("Initializing Plugins Complete. Starting Daemon");
+       Z_TIME_CHECK("Initializing Plugins Complete.");
+
+       /* Initialize ZigBee plug-ins */
+       if (G_UNLIKELY(TRUE != zblib_service_initialize_async_plugins(service))) {
+               Z_LOGE("Asynchronously initialize plug-ins failed!");
+               return FALSE;
+       }
+
+       Z_TIME_CHECK("Asynchronous initializer launched successfully. Starting Daemon");
 
        return TRUE;
 }