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 eab1228258fa49af6fbe60b4a5511936fea6b1ba..17372fd4c1ec653f0ec2468c40ea8e75493c275e 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 5183d37c6d96d7505e1fbd9211b7d6bdcb3d3ba3..7057696ab2d5884d4e9d9020bb95e5539cab3fed 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 b225e8d226a3dd3eb0091c4f7d66136ade5e2bd6..a918e8f07b97f9d2504de3ea13b9de00a7a65ae8 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 0fb08b7655bd9e78d78ad5a2b81358f7cfb6c8fd..6ede96a16703b33fa2f71310feb208c03f581f12 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);