--- /dev/null
+#include <dlog.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pkgmgr-info.h>
+#include <package-manager.h>
+
+#include "eventsystem_daemon.h"
+
+#define CION_METADATA_KEY "http://tizen.org/metadata/cion"
+
+static uid_t cur_uid;
+static pkgmgr_client *pkgmgr;
+static GList *service_list;
+
+struct cion_service {
+ char *pkgid;
+ char *appid;
+ char *service_name;
+ char *uuid;
+ int port;
+};
+
+static void __free_cion_service(gpointer data)
+{
+ struct cion_service *service = (struct cion_service *)data;
+
+ free(service->pkgid);
+ free(service->appid);
+ free(service->service_name);
+ free(service->uuid);
+ free(service);
+}
+
+static int __esd_cion_set_cur_uid(void)
+{
+ /* TODO(jeremy.jang): get current user from gumd or systemd */
+ cur_uid = 5001;
+ return 0;
+}
+
+static int __esd_cion_foreach_metadata_callback(const char *key,
+ const char *val, void *user_data)
+{
+ struct cion_service *service;
+ GList **service_list = (GList **)user_data;
+
+ if (strncmp(key, CION_METADATA_KEY, strlen(CION_METADATA_KEY)) != 0)
+ return 0;
+
+ if (val == NULL || strlen(val) == 0) {
+ _E("Service name is mandatory");
+ return 0;
+ }
+
+ service = calloc(1, sizeof(struct cion_service));
+ if (service == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ service->service_name = strdup(val);
+ if (service->service_name == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ *service_list = g_list_append(*service_list, (gpointer)service);
+
+ return 0;
+}
+
+static void __esd_cion_remove_cion_service_by_appid(const char *appid)
+{
+ GList *item;
+ GList *next;
+ struct cion_service *service;
+
+ item = service_list;
+ while (item != NULL) {
+ next = item->next;
+ service = (struct cion_service *)item->data;
+ if (strcmp(service->appid, appid) == 0) {
+ _D("Remove a cion service [%s:%s:%s:%d]",
+ service->appid, service->service_name,
+ service->uuid, service->port);
+ __free_cion_service(service);
+ service_list = g_list_delete_link(service_list, item);
+ }
+ item = next;
+ }
+}
+
+static void __esd_cion_remove_cion_service_by_pkgid(const char *pkgid)
+{
+ GList *item;
+ GList *next;
+ struct cion_service *service;
+
+ item = service_list;
+ while (item != NULL) {
+ next = item->next;
+ service = (struct cion_service *)item->data;
+ if (strcmp(service->pkgid, pkgid) == 0) {
+ _D("Remove a cion service [%s:%s:%s:%d]",
+ service->appid, service->service_name,
+ service->uuid, service->port);
+ __free_cion_service(service);
+ service_list = g_list_delete_link(service_list, item);
+ }
+ item = next;
+ }
+}
+
+static int __esd_cion_add_cion_service(struct cion_service *service,
+ const char *pkgid, const char *appid)
+{
+ /* service name already set by __esd_cion_foreach_metadata_callback() */
+ service->pkgid = strdup(pkgid);
+ if (service->pkgid == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ service->appid = strdup(appid);
+ if (service->appid == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ /* how to get uuid? */
+
+ service_list = g_list_append(service_list, service);
+ _D("Add a cion service [%s:%s:%s:%d]", service->appid,
+ service->service_name, service->uuid,
+ service->port);
+
+ return 0;
+}
+
+static int __esd_cion_foreach_app_callback(const pkgmgrinfo_appinfo_h appinfo,
+ void *user_data)
+{
+ int ret;
+ char *pkgid;
+ char *appid;
+ struct cion_service *service;
+ GList *item;
+ GList *list = NULL;
+
+ ret = pkgmgrinfo_appinfo_foreach_metadata(appinfo,
+ __esd_cion_foreach_metadata_callback, &list);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get metadata: %d", ret);
+ return -1;
+ }
+
+ ret = pkgmgrinfo_appinfo_get_pkgid(appinfo, &pkgid);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get pkgid: %d", ret);
+ return -1;
+ }
+
+ ret = pkgmgrinfo_appinfo_get_appid(appinfo, &appid);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get appid: %d", ret);
+ return -1;
+ }
+
+ /* remove first, the updated app may no longer provide cion service */
+ __esd_cion_remove_cion_service_by_appid(appid);
+ for (item = list; item; item = item->next) {
+ service = (struct cion_service *)item->data;
+ if (__esd_cion_add_cion_service(service, pkgid, appid)) {
+ _E("Failed to add a cion service");
+ __free_cion_service(service);
+ }
+ /* remove reference, the global 'service_list' takes reference
+ * of 'service'.
+ */
+ item->data = NULL;
+ }
+
+ g_list_free(list);
+
+ return 0;
+}
+
+static int __esd_cion_pkgmgr_event_callback(uid_t target_uid, int req_id,
+ const char *pkg_type, const char *pkgid, const char *key,
+ const char *val, const void *pmsg, void *data)
+{
+ int ret;
+ pkgmgrinfo_pkginfo_h pkginfo;
+
+ if (strncmp(key, "end", strlen("end")) ||
+ strncmp(val, "ok", strlen("ok")))
+ return 0;
+
+ ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, target_uid, &pkginfo);
+ if (ret == PMINFO_R_OK) {
+ /* install or update */
+ ret = pkgmgrinfo_appinfo_get_usr_list(pkginfo, PMINFO_ALL_APP,
+ __esd_cion_foreach_app_callback, NULL,
+ target_uid);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get appinfo of pkgid %s: %d", pkgid, ret);
+ pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
+ return 0;
+ }
+ pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
+ } else if (ret == PMINFO_R_ENOENT) {
+ /* uninstall */
+ __esd_cion_remove_cion_service_by_pkgid(pkgid);
+ } else {
+ _E("Failed to get pkginfo of %s: %d", pkgid, ret);
+ }
+
+ return 0;
+}
+
+static int __esd_cion_set_pkgmgr_callback(void)
+{
+ int ret;
+
+ pkgmgr = pkgmgr_client_new(PC_LISTENING);
+ if (pkgmgr == NULL) {
+ _E("Failed to create pkgmgr client");
+ return -1;
+ }
+
+ ret = pkgmgr_client_set_status_type(pkgmgr,
+ PKGMGR_CLIENT_STATUS_INSTALL |
+ PKGMGR_CLIENT_STATUS_UPGRADE |
+ PKGMGR_CLIENT_STATUS_UNINSTALL);
+ if (ret != PKGMGR_R_OK) {
+ _E("Failed to set pkgmgr event status type: %d", ret);
+ pkgmgr_client_free(pkgmgr);
+ pkgmgr = NULL;
+ return -1;
+ }
+
+ ret = pkgmgr_client_listen_status(pkgmgr,
+ __esd_cion_pkgmgr_event_callback, NULL);
+ if (ret < 0) {
+ _E("Failed to set event callback: %d", ret);
+ pkgmgr_client_free(pkgmgr);
+ pkgmgr = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __esd_cion_load_services(uid_t uid)
+{
+ int ret;
+ pkgmgrinfo_appinfo_metadata_filter_h filter;
+
+ ret = pkgmgrinfo_appinfo_metadata_filter_create(&filter);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to create metadata filter: %d", ret);
+ return -1;
+ }
+
+ ret = pkgmgrinfo_appinfo_metadata_filter_add(filter,
+ CION_METADATA_KEY, "");
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to add keyval to metadata filter: %d", ret);
+ pkgmgrinfo_appinfo_metadata_filter_destroy(filter);
+ return -1;
+ }
+
+ ret = pkgmgrinfo_appinfo_usr_metadata_filter_foreach(filter,
+ __esd_cion_foreach_app_callback, NULL, uid);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to metadata filter foreach: %d", ret);
+ pkgmgrinfo_appinfo_metadata_filter_destroy(filter);
+ return -1;
+ }
+
+ pkgmgrinfo_appinfo_metadata_filter_destroy(filter);
+
+ return 0;
+}
+
+int __esd_cion_init(void)
+{
+ if (__esd_cion_set_cur_uid()) {
+ _E("Failed to set current uid");
+ return -1;
+ }
+
+ /* how to handle when user switched? */
+ if (__esd_cion_load_services(cur_uid)) {
+ _E("Failed to load cion services");
+ return -1;
+ }
+
+ if (__esd_cion_set_pkgmgr_callback()) {
+ _E("Failed to set pkgmgr event callback");
+ return -1;
+ }
+
+ return 0;
+}
+
+void __esd_cion_finalize(void)
+{
+ if (pkgmgr) {
+ pkgmgr_client_remove_listen_status(pkgmgr);
+ pkgmgr_client_free(pkgmgr);
+ }
+
+ g_list_free_full(service_list, __free_cion_service);
+}