Implement APIs for multi-signal 39/222839/5
authorJunghyun Yeon <jungh.yeon@samsung.com>
Mon, 20 Jan 2020 12:44:53 +0000 (21:44 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Fri, 31 Jan 2020 06:05:22 +0000 (06:05 +0000)
Currently dbus signal should be emitted for each pkg
even if process knows list of packages signal emittion has required.
Newly introduced API sets will provide methods to add
multiple package IDs to be submitted at once.

Change-Id: I62d5d3d9a9809b0d28f959b5d0d92018ffb22892
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
client/src/pkgmgr_client_connection.c
installer/pkgmgr_installer.c
installer/pkgmgr_installer.h
installer/pkgmgr_installer_signal_agent.c

index eab1228..17372fd 100644 (file)
@@ -106,21 +106,6 @@ struct signal_map map[] = {
        {NULL, -1}
 };
 
-static int __get_signal_type(const char *name)
-{
-       int i;
-
-       if (name == NULL)
-               return -1;
-
-       for (i = 0; map[i].signal_str != NULL; i++) {
-               if (strcmp(map[i].signal_str, name) == 0)
-                       return map[i].signal_type;
-       }
-
-       return -1;
-}
-
 static void __handle_size_info_callback(struct cb_info *cb_info,
                const char *pkgid, const char *val)
 {
@@ -187,47 +172,80 @@ static void __handle_size_info_callback(struct cb_info *cb_info,
        }
 }
 
+static void __convert_signal(char *event_type, char *event_status,
+               char *appid, int progress, char **key, char **val)
+{
+       *key = event_status;
+       if (strcmp(event_status, PKGMGR_INSTALLER_START_KEY_STR) == 0) {
+               *val = event_type;
+       } else if (strcmp(event_status, PKGMGR_INSTALLER_OK_EVENT_STR) == 0 ||
+                       strcmp(event_status, PKGMGR_INSTALLER_FAIL_EVENT_STR) == 0) {
+               *key = PKGMGR_INSTALLER_END_KEY_STR;
+               *val = event_status;
+       } else if (strcmp(event_status, PKGMGR_INSTALLER_APPID_KEY_STR) == 0) {
+               if (!appid) {
+                       ERR("appid is empty");
+                       return;
+               }
+               *val = appid;
+       } else if (strcmp(event_type, PKGMGR_INSTALLER_GET_SIZE_KEY_STR) == 0) {
+               *key = event_type;
+               *val = event_status;
+       }
+       // TODO: should handle cleardata / clearacache signal
+}
+
 static void __signal_handler(GDBusConnection *conn, const gchar *sender_name,
                const gchar *object_path, const gchar *interface_name,
                const gchar *signal_name, GVariant *parameters,
                gpointer user_data)
 {
+       int progress = 0;
        uid_t target_uid;
+       char buf[BUFMAX];
        char *req_id;
        char *pkg_type = NULL;
+       char *appid = NULL;
        char *pkgid = NULL;
+       char *event_type = NULL;
+       char *event_status = NULL;
        char *key = NULL;
        char *val = NULL;
-       char *appid = NULL;
-       int signal_type;
        struct cb_info *cb_info = (struct cb_info *)user_data;
+       GVariantIter *iter = NULL;
+
+       g_variant_get(parameters, "(u&sa(sss)&s&si)", &target_uid, &req_id, &iter,
+                       &event_type, &event_status, &progress);
+       while (g_variant_iter_loop(iter, "(&s&s&s)", &pkgid, &appid, &pkg_type)) {
+               if (cb_info->req_key) {
+                       if (strcmp(cb_info->req_key, req_id) != 0)
+                               continue;
+               }
 
-       g_variant_get(parameters, "(u&s&s&s&s&s&s)",
-                       &target_uid, &req_id, &pkg_type,
-                       &pkgid, &appid, &key, &val);
-
-       /* in case of request, check reqkey */
-       if (cb_info->req_key) {
-               if (strcmp(cb_info->req_key, req_id) != 0)
-                       return;
-       } else {
-               signal_type = __get_signal_type(signal_name);
-               if (signal_type < 0 || !(cb_info->status_type & signal_type))
-                       return;
+               /* convert event_type and event_status into key-val pair */
+               __convert_signal(event_type, event_status, appid,
+                               progress, &key, &val);
+               if (strcmp(event_status,
+                                       PKGMGR_INSTALLER_INSTALL_PERCENT_KEY_STR) == 0 ||
+                               strcmp(event_status, PKGMGR_INSTALLER_ERROR_KEY_STR) == 0) {
+                       snprintf(buf, BUFMAX - 1, "%d", progress);
+                       val = buf;
+               }
+               /* TODO: progress should be set properly when installation has
+                * completed or failed */
+
+               if (cb_info->event_cb) {
+                       cb_info->event_cb(target_uid, cb_info->req_id,
+                                       pkg_type, pkgid, key, val, NULL, cb_info->data);
+               } else if (cb_info->app_event_cb && strcmp(appid, "") != 0) {
+                       cb_info->app_event_cb(target_uid, cb_info->req_id,
+                                       pkg_type, pkgid, appid, key, val, NULL,
+                                       cb_info->data);
+               } else if (cb_info->size_info_cb)
+                       __handle_size_info_callback(cb_info, pkgid, val);
+
+               /* TODO: unsubscribe request callback */
        }
-
-       /* each cb_data can only has one callback */
-       if (cb_info->event_cb && strcmp(appid, "") == 0)
-               cb_info->event_cb(target_uid, cb_info->req_id,
-                               pkg_type, pkgid, key, val, NULL, cb_info->data);
-       else if (cb_info->app_event_cb && strcmp(appid, "") != 0)
-               cb_info->app_event_cb(target_uid, cb_info->req_id,
-                               pkg_type, pkgid, appid, key, val, NULL,
-                               cb_info->data);
-       else if (cb_info->size_info_cb)
-               __handle_size_info_callback(cb_info, pkgid, val);
-
-       /* TODO: unsubscribe request callback */
 }
 
 static void __set_signal_list(int event, GList **signal_list)
index 5183d37..7057696 100644 (file)
@@ -118,25 +118,21 @@ struct pkgmgr_installer {
        int skip_check_reference;
        int skip_optimization;
        GDBusConnection *conn;
+       GHashTable *pkg_list;
 };
 
+typedef struct pkg_signal_info {
+       char *pkgid;
+       char *pkg_type;
+} pkg_signal_info;
+
 static uid_t g_target_uid;
 static int g_debug_mode;
 static int g_skip_optimization;
 static pkgmgr_privilege_level g_privilege_level = PM_PRIVILEGE_UNKNOWN;
 
-static const char *__get_signal_name(pkgmgr_installer *pi, const char *key,
-               const char *pkg_type)
+static const char *__get_event_type(pkgmgr_installer *pi)
 {
-       if (strcmp(key, PKGMGR_INSTALLER_INSTALL_PERCENT_KEY_STR) == 0)
-               return key;
-       else if (strcmp(key, PKGMGR_INSTALLER_GET_SIZE_KEY_STR) == 0)
-               return key;
-       else if (strcmp(key, PKGMGR_INSTALLER_APPID_KEY_STR) == 0)
-               return PKGMGR_INSTALLER_UNINSTALL_EVENT_STR;
-       else if (strcmp(pkg_type, PKGMGR_INSTALLER_CLEAR_CACHE_KEY_STR) == 0)
-               return pkg_type;
-
        switch (pi->request_type) {
        case PKGMGR_REQ_INSTALL:
        case PKGMGR_REQ_MANIFEST_DIRECT_INSTALL:
@@ -171,12 +167,32 @@ static const char *__get_signal_name(pkgmgr_installer *pi, const char *key,
        return NULL;
 }
 
+static const char *__get_signal_name(pkgmgr_installer *pi, const char *key,
+               const char *pkg_type)
+{
+       if (strcmp(key, PKGMGR_INSTALLER_INSTALL_PERCENT_KEY_STR) == 0)
+               return key;
+       else if (strcmp(key, PKGMGR_INSTALLER_GET_SIZE_KEY_STR) == 0)
+               return key;
+       else if (strcmp(key, PKGMGR_INSTALLER_APPID_KEY_STR) == 0)
+               return PKGMGR_INSTALLER_UNINSTALL_EVENT_STR;
+       else if (strcmp(pkg_type, PKGMGR_INSTALLER_CLEAR_CACHE_KEY_STR) == 0)
+               return pkg_type;
+
+       return __get_event_type(pi);
+}
+
 static int __send_signal_for_event(pkgmgr_installer *pi, const char *pkg_type,
                const char *pkgid, const char *appid, const char *key,
                const char *val)
 {
+       int progress = 0;
        char *sid;
-       const char *name;
+       const char *tmp_appid = appid;
+       const char *event_type;
+       const char *event_status;
+       const char *signal_name;
+       GVariantBuilder *builder;
        GError *err = NULL;
 
        if (!pi || pi->conn == NULL)
@@ -186,24 +202,46 @@ static int __send_signal_for_event(pkgmgr_installer *pi, const char *pkg_type,
        if (!sid)
                sid = "";
 
-       name = __get_signal_name(pi, key, pkg_type);
-       if (name == NULL) {
-               ERR("unknown signal type");
+       signal_name = __get_signal_name(pi, key, val);
+       if (!signal_name) {
+               ERR("unknown signal name");
                return -1;
        }
 
+       event_type = __get_event_type(pi);
+       if (!event_type) {
+               ERR("unknown event type");
+               return -1;
+       }
+
+       if (strcmp(key, PKGMGR_INSTALLER_END_KEY_STR) == 0 ||
+                       strcmp(key, PKGMGR_INSTALLER_GET_SIZE_KEY_STR) == 0)
+               event_status = val;
+       else
+               event_status = key;
+
+       if (strcmp(key, PKGMGR_INSTALLER_INSTALL_PERCENT_KEY_STR) == 0 ||
+                       strcmp(key, PKGMGR_INSTALLER_ERROR_KEY_STR) == 0)
+               progress = atoi(val);
+       else if (strcmp(key, PKGMGR_INSTALLER_APPID_KEY_STR) == 0)
+               tmp_appid = val;
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("a(sss)"));
+       g_variant_builder_add(builder, "(sss)", pkgid,
+                       (tmp_appid ? tmp_appid : ""), pkg_type);
        if (g_dbus_connection_emit_signal(pi->conn, NULL,
                                PKGMGR_INSTALLER_DBUS_OBJECT_PATH,
-                               PKGMGR_INSTALLER_DBUS_INTERFACE, name,
-                               g_variant_new("(ussssss)", pi->target_uid, sid,
-                                       pkg_type, pkgid, appid ? appid : "",
-                                       key, val), &err)
-                       != TRUE) {
-               ERR("failed to send dbus signal: %s", err->message);
-               g_error_free(err);
+                               PKGMGR_INSTALLER_DBUS_INTERFACE, signal_name,
+                               g_variant_new("(usa(sss)ssi)", pi->target_uid, sid,
+                                               builder, event_type, event_status, progress),
+                               &err) != TRUE) {
+               ERR("failed to send dbus signal");
+               if (err) {
+                       ERR("err: %s", err->message);
+                       g_error_free(err);
+               }
                return -1;
        }
-
        return 0;
 }
 
@@ -245,9 +283,14 @@ static int __send_signal_for_event_for_uid(pkgmgr_installer *pi, uid_t uid,
                const char *pkg_type, const char *pkgid, const char *appid,
                const char *key, const char *val)
 {
+       int progress = 0;
        char *sid;
-       const char *name;
+       const char *signal_name;
+       const char *tmp_appid = appid;
+       const char *event_type;
+       const char *event_status;
        size_t name_size;
+       GVariantBuilder *builder;
        GVariant *gv;
        gsize gv_len;
        gpointer gv_data;
@@ -264,17 +307,40 @@ static int __send_signal_for_event_for_uid(pkgmgr_installer *pi, uid_t uid,
 
        data_len = sizeof(size_t) + sizeof(gsize);
 
-       name = __get_signal_name(pi, key, pkg_type);
-       if (name == NULL) {
-               ERR("unknown signal type");
+       signal_name = __get_signal_name(pi, key, pkg_type);
+       if (!signal_name) {
+               ERR("unknown signal name");
+               return -1;
+       }
+
+       event_type = __get_event_type(pi);
+       if (!event_type) {
+               ERR("unknown event type");
                return -1;
        }
+
+       if (strcmp(key, PKGMGR_INSTALLER_END_KEY_STR) == 0 ||
+                       strcmp(key, PKGMGR_INSTALLER_GET_SIZE_KEY_STR) == 0)
+               event_status = val;
+       else
+               event_status = key;
+
+       if (strcmp(key, PKGMGR_INSTALLER_INSTALL_PERCENT_KEY_STR) == 0 ||
+                       strcmp(key, PKGMGR_INSTALLER_ERROR_KEY_STR) == 0)
+               progress = atoi(val);
+       else if (strcmp(key, PKGMGR_INSTALLER_APPID_KEY_STR) == 0)
+               tmp_appid = val;
+
+
        /* including null byte */
-       name_size = strlen(name) + 1;
+       name_size = strlen(signal_name) + 1;
        data_len += name_size;
 
-       gv = g_variant_new("(ussssss)", pi->target_uid, sid,
-                       pkg_type, pkgid, appid ? appid : "", key, val);
+       builder = g_variant_builder_new(G_VARIANT_TYPE("a(sss)"));
+       g_variant_builder_add(builder, "(sss)", pkgid,
+                       (tmp_appid ? tmp_appid : ""), pkg_type);
+       gv = g_variant_new("(usa(sss)ssi)", pi->target_uid, sid,
+                       builder, event_type, event_status, progress);
        if (gv == NULL) {
                ERR("failed to create GVariant instance");
                return -1;
@@ -295,7 +361,7 @@ static int __send_signal_for_event_for_uid(pkgmgr_installer *pi, uid_t uid,
        ptr += sizeof(size_t);
        memcpy(ptr, &gv_len, sizeof(gsize));
        ptr += sizeof(gsize);
-       memcpy(ptr, name, name_size);
+       memcpy(ptr, signal_name, name_size);
        ptr += name_size;
        memcpy(ptr, gv_data, gv_len);
        g_free(gv_data);
@@ -311,6 +377,14 @@ static int __send_signal_for_event_for_uid(pkgmgr_installer *pi, uid_t uid,
        return 0;
 }
 
+static void __free_pkg_list(gpointer data)
+{
+       pkg_signal_info *info = (pkg_signal_info *)data;
+       free(info->pkgid);
+       free(info->pkg_type);
+       free(info);
+}
+
 API pkgmgr_installer *pkgmgr_installer_new(void)
 {
        pkgmgr_installer *pi;
@@ -331,7 +405,8 @@ API pkgmgr_installer *pkgmgr_installer_new(void)
        pi->tep_path = NULL;
        pi->tep_move = 0;
        pi->request_type = PKGMGR_REQ_INVALID;
-
+       pi->pkg_list = g_hash_table_new_full(
+                       g_str_hash, g_str_equal, NULL, __free_pkg_list);
        return pi;
 }
 
@@ -371,6 +446,9 @@ API int pkgmgr_installer_free(pkgmgr_installer *pi)
                g_object_unref(pi->conn);
        }
 
+       if (pi->pkg_list)
+               g_hash_table_destroy(pi->pkg_list);
+
        free(pi);
 
        return 0;
@@ -991,3 +1069,79 @@ API const char *pkgmgr_installer_error_to_string(int error_code)
                return PKGMGR_INSTALLER_ERRCODE_UNDEFINED_ERROR_STR;
        }
 }
+
+API int pkgmgr_installer_add_pkg(pkgmgr_installer *pi,
+               const char *pkgid, const char *pkg_type)
+{
+       pkg_signal_info *info;
+       if (!pi || !pkgid || !pkg_type) {
+               ERR("invalid argument");
+               return -1;
+       }
+
+       info = calloc(1, sizeof(pkg_signal_info));
+       if (!info) {
+               ERR("out of memory");
+               return -1;
+       }
+
+       info->pkgid = strdup(pkgid);
+       info->pkg_type = strdup(pkg_type);
+       if (!info->pkgid || info->pkg_type) {
+               ERR("out of memory");
+               free(info->pkgid);
+               free(info->pkg_type);
+               free(info);
+               return -1;
+       }
+       g_hash_table_insert(pi->pkg_list, (gpointer)pkgid, (gpointer)info);
+
+       return 0;
+}
+
+static void __build_multi_signal(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       GVariantBuilder *builder = (GVariantBuilder *)user_data;
+       char *pkgid = (char *)key;
+       pkg_signal_info *info = (pkg_signal_info *)value;
+
+       g_variant_builder_add(builder, "(sss)", pkgid, "", info->pkg_type);
+}
+
+API int pkgmgr_installer_send_signals(pkgmgr_installer *pi,
+               const char *event_type, const char *event_status, int progress)
+{
+       char *sid;
+       GError *err = NULL;
+       GVariantBuilder *builder;
+
+       if (!pi || !event_type || !event_status) {
+               ERR("invalid argument");
+               return -1;
+       }
+
+       sid = pi->session_id;
+       if (!sid)
+               sid = "";
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("a(sss)"));
+       g_hash_table_foreach(pi->pkg_list, __build_multi_signal, builder);
+       if (g_dbus_connection_emit_signal(pi->conn, NULL,
+                               PKGMGR_INSTALLER_DBUS_OBJECT_PATH,
+                               PKGMGR_INSTALLER_DBUS_INTERFACE, event_type,
+                               g_variant_new("(usa(sss)ssi)",
+                                               pi->target_uid, sid, builder, event_type,
+                                               event_status, progress), &err) != TRUE) {
+               ERR("failed to send dbus signal");
+               if (err) {
+                       ERR("err: %s", err->message);
+                       g_error_free(err);
+               }
+               g_variant_builder_unref(builder);
+               return -1;
+       }
+       g_variant_builder_unref(builder);
+
+       return 0;
+}
\ No newline at end of file
index b225e8d..a918e8f 100644 (file)
@@ -1066,6 +1066,33 @@ int pkgmgr_installer_set_privilege_level(pkgmgr_privilege_level level);
 */
 const char *pkgmgr_installer_error_to_string(int error_code);
 
+/**
+ * @brief      This API adds pkg to be send at once
+ *
+ *              This API is for installer backend.\n
+ *
+ * @param[in]  pi                              pointer to pkgmgr_installer
+ * @param[in]  pkgid                           package ID
+ * @param[in]  pkg_type                        type of package
+ * @return     0 if success, error code(<0) if fail\n
+*/
+int pkgmgr_installer_add_pkg(pkgmgr_installer *pi,
+               const char *pkgid, const char *pkg_type);
+
+/**
+ * @brief      This API sends signals with packages already added
+ *
+ *              This API is for installer backend.\n
+ *
+ * @param[in]  pi                                      pointer to pkgmgr_installer
+ * @param[in]  event_type                      package ID
+ * @param[in]  event_status            type of package
+ * @param[in]  progress                        progress of requested operation
+ * @return     0 if success, error code(<0) if fail\n
+*/
+int pkgmgr_installer_send_signals(pkgmgr_installer *pi,
+               const char *event_type, const char *event_status, int progress);
+
 #ifdef __cplusplus
 }
 #endif
index 0fb08b7..6ede96a 100644 (file)
@@ -257,7 +257,7 @@ static gboolean __handle_signal(gint fd, GIOCondition cond, gpointer user_data)
        memcpy(data, buf + type_len, data_len);
 
        /* floating type GVariant instance */
-       gv = g_variant_new_from_data(G_VARIANT_TYPE("(ussssss)"), data,
+       gv = g_variant_new_from_data(G_VARIANT_TYPE("(usa(sss)ssi)"), data,
                        data_len, TRUE, NULL, NULL);
        __emit_signal(type_name, gv);