From: sooyeon.kim Date: Tue, 26 Jun 2018 13:08:16 +0000 (+0900) Subject: Add engine-parser X-Git-Tag: submit/tizen/20180724.084832~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=73095f23a811518ad8cb5be8cfe3fe6572cb8acb;p=platform%2Fcore%2Fuifw%2Fvoice-control.git Add engine-parser Change-Id: Ib3789585acd459938a507fc2a102089e8130e460 Signed-off-by: sooyeon.kim --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 51c98b0..8819be3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,12 +43,12 @@ INCLUDE(FindPkgConfig) IF("${_TV_PRODUCT}" STREQUAL "TRUE") pkg_check_modules(pkgs REQUIRED aul capi-appfw-app-control capi-appfw-app-manager capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wayland - capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libtzplatform-config libxml-2.0 sqlite3 vconf msfapi + capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf msfapi ) ELSE() pkg_check_modules(pkgs REQUIRED aul capi-appfw-app-control capi-appfw-app-manager capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wayland - capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libtzplatform-config libxml-2.0 sqlite3 vconf + capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf ) ENDIF() @@ -62,6 +62,9 @@ ADD_SUBDIRECTORY(client) ## Server daemon ## ADD_SUBDIRECTORY(server) +## Engine Parser ## +ADD_SUBDIRECTORY(engine-parser) + ## config ## INSTALL(FILES ${CMAKE_SOURCE_DIR}/vc-config.xml DESTINATION ${TZ_SYS_RO_SHARE}/voice/vc/1.0) diff --git a/common/vc_config_mgr.c b/common/vc_config_mgr.c index 296e88a..5c33189 100755 --- a/common/vc_config_mgr.c +++ b/common/vc_config_mgr.c @@ -41,6 +41,12 @@ typedef struct { vc_config_enabled_cb enabled_cb; } vc_config_client_s; +/* for engine directory monitoring */ +typedef struct { + Ecore_Fd_Handler* dir_fd_handler; + int dir_fd; + int dir_wd; +} vc_engine_inotify_s; const char* vc_config_tag() { @@ -58,10 +64,14 @@ static Ecore_Fd_Handler* g_fd_handler_lang = NULL; static int g_fd_lang; static int g_wd_lang; +static GList* g_ino_list = NULL; + static pthread_mutex_t vc_config_mgr_mutex = PTHREAD_MUTEX_INITIALIZER; -int __vc_config_mgr_print_engine_info(); +static int __vc_config_mgr_register_engine_config_updated_event(const char* path); +static int __vc_config_mgr_unregister_engine_config_updated_event(); +int __vc_config_mgr_print_engine_info(); int __vc_config_mgr_print_client_info(); int vc_config_convert_error_code(vc_config_error_e code) @@ -260,6 +270,295 @@ int __vc_config_mgr_select_lang(const char* engine_id, char** language) return VC_ERROR_OPERATION_FAILED; } +int __vc_config_release_client(int uid) +{ + GSList *iter = NULL; + vc_config_client_s* temp_client = NULL; + + if (0 < g_slist_length(g_config_client_list)) { + /* Check uid */ + iter = g_slist_nth(g_config_client_list, 0); + + while (NULL != iter) { + temp_client = iter->data; + + if (NULL != temp_client) { + if (uid == temp_client->uid) { + g_config_client_list = g_slist_remove(g_config_client_list, temp_client); + free(temp_client); + break; + } + } + + iter = g_slist_next(iter); + } + } + + SLOG(LOG_DEBUG, vc_config_tag(), "Client count (%d)", g_slist_length(g_config_client_list)); + + return g_slist_length(g_config_client_list); +} + +void __vc_config_release_engine() +{ + GSList *iter = NULL; + vc_engine_info_s *engine_info = NULL; + + if (0 < g_slist_length(g_engine_list)) { + + /* Get a first item */ + iter = g_slist_nth(g_engine_list, 0); + + while (NULL != iter) { + engine_info = iter->data; + + if (NULL != engine_info) { + g_engine_list = g_slist_remove(g_engine_list, engine_info); + + vc_parser_free_engine_info(engine_info); + } + + iter = g_slist_nth(g_engine_list, 0); + } + } + + return; +} + +int __vc_config_mgr_get_engine_info() +{ + DIR *dp = NULL; + struct dirent *dirp = NULL; + + char filepath[512] = {'\0',}; + int filesize; + vc_engine_info_s* info = NULL; + + __vc_config_release_engine(); + g_engine_list = NULL; + __vc_config_mgr_unregister_engine_config_updated_event(); + + /* Copy default info directory to download directory */ + dp = opendir(VC_DEFAULT_ENGINE_INFO); + if (NULL == dp) { + SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] No default directory : %s", VC_DEFAULT_ENGINE_INFO); + } else { + do { + dirp = readdir(dp); + + if (NULL != dirp) { + if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name)) + continue; + + filesize = strlen(VC_DEFAULT_ENGINE_INFO) + strlen(dirp->d_name) + 2; + if (filesize >= 512) { + SECURE_SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] File path is too long : %s", dirp->d_name); + closedir(dp); + return -1; + } + + memset(filepath, '\0', 512); + snprintf(filepath, 512, "%s/%s", VC_DEFAULT_ENGINE_INFO, dirp->d_name); + + SECURE_SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] Filepath(%s)", filepath); + + char dest[512] = {'\0',}; + snprintf(dest, 512, "%s/%s", VC_DOWNLOAD_ENGINE_INFO, dirp->d_name); + + if (0 != access(dest, F_OK)) { + if (0 != vc_parser_copy_xml(filepath, dest)) { + SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] Fail to copy engine info"); + } + } + } + } while (NULL != dirp); + + closedir(dp); + } + + /* Get engine info from default engine directory */ + dp = opendir(VC_DOWNLOAD_ENGINE_INFO); + if (NULL == dp) { + SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] No downloadable directory : %s", VC_DOWNLOAD_ENGINE_INFO); + } else { + do { + dirp = readdir(dp); + + if (NULL != dirp) { + if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name)) + continue; + + filesize = strlen(VC_DOWNLOAD_ENGINE_INFO) + strlen(dirp->d_name) + 2; + if (filesize >= 512) { + SECURE_SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] File path is too long : %s", dirp->d_name); + closedir(dp); + return -1; + } + + memset(filepath, '\0', 512); + snprintf(filepath, 512, "%s/%s", VC_DOWNLOAD_ENGINE_INFO, dirp->d_name); + + SECURE_SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] Filepath(%s)", filepath); + + if (0 == vc_parser_get_engine_info(filepath, &info)) { + g_engine_list = g_slist_append(g_engine_list, info); + if (0 != __vc_config_mgr_register_engine_config_updated_event(filepath)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to register engine config updated event"); + } + } + } + } while (NULL != dirp); + + closedir(dp); + } + + if (0 >= g_slist_length(g_engine_list)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] No engine"); + return -1; + } + + return 0; +} + +static Eina_Bool __vc_config_mgr_engine_config_inotify_event_callback(void* data, Ecore_Fd_Handler *fd_handler) +{ + SLOG(LOG_DEBUG, vc_config_tag(), "@@@ Engine config updated callback event"); + + vc_engine_inotify_s *ino = (vc_engine_inotify_s *)data; + int dir_fd = ino->dir_fd; + + int length; + struct inotify_event event; + memset(&event, '\0', sizeof(struct inotify_event)); + + length = read(dir_fd, &event, sizeof(struct inotify_event)); + if (0 > length) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Empty Inotify event"); + SLOG(LOG_DEBUG, vc_config_tag(), "@@@"); + return ECORE_CALLBACK_DONE; + } + + if (IN_CLOSE_WRITE == event.mask) { + int ret = __vc_config_mgr_get_engine_info(); + if (0 != ret) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get engine info when config updated"); + } + __vc_config_mgr_print_engine_info(); + bool support = vc_config_check_default_language_is_valid(g_config_info->language); + if (false == support) { + SLOG(LOG_DEBUG, vc_config_tag(), "[ERROR] Default language is valid"); + char* temp_lang = NULL; + ret = __vc_config_mgr_select_lang(g_config_info->engine_id, &temp_lang); + if (0 != ret) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get language"); + } + + ret = vc_config_mgr_set_default_language(temp_lang); + if (0 != ret) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to set language"); + } else { + SLOG(LOG_DEBUG, vc_config_tag(), "[DEBUG] Saved default language : lang(%s)", g_config_info->language); + } + if (NULL != temp_lang) { + free(temp_lang); + temp_lang = NULL; + } + } + } else { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Undefined event"); + } + + SLOG(LOG_DEBUG, vc_config_tag(), "@@@"); + + return ECORE_CALLBACK_PASS_ON; +} + +static int __vc_config_mgr_register_engine_config_updated_event(const char* path) +{ + if (NULL == path) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Path is NULL"); + return -1; + } + + /* For engine directory monitoring */ + vc_engine_inotify_s *ino = (vc_engine_inotify_s *)calloc(1, sizeof(vc_engine_inotify_s)); + if (NULL == ino) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to allocate memory"); + return -1; + } + + ino->dir_fd = inotify_init(); + if (ino->dir_fd < 0) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to init inotify"); + free(ino); + ino = NULL; + + return -1; + } + + ino->dir_wd = inotify_add_watch(ino->dir_fd, path, IN_CLOSE_WRITE); + SLOG(LOG_DEBUG, vc_config_tag(), "Add inotify watch(%s)", path); + if (ino->dir_wd < 0) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to add watch"); + free(ino); + ino = NULL; + return -1; + } + + ino->dir_fd_handler = ecore_main_fd_handler_add(ino->dir_fd, ECORE_FD_READ, (Ecore_Fd_Cb)__vc_config_mgr_engine_config_inotify_event_callback, (void *)ino, NULL, NULL); + if (NULL == ino->dir_fd_handler) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to add fd handler"); + free(ino); + ino = NULL; + return -1; + } + + /* Set non-blocking mode of file */ + int value; + value = fcntl(ino->dir_fd, F_GETFL, 0); + value |= O_NONBLOCK; + + if (0 > fcntl(ino->dir_fd, F_SETFL, value)) { + SLOG(LOG_WARN, vc_config_tag(), "[WARNING] Fail to set non-block mode"); + } + + g_ino_list = g_list_append(g_ino_list, ino); + + return 0; +} + +static int __vc_config_mgr_unregister_engine_config_updated_event() +{ + /* delete all inotify variable */ + if (0 < g_list_length(g_ino_list)) { + GList *iter = NULL; + iter = g_list_first(g_ino_list); + + while (NULL != iter) { + vc_engine_inotify_s *tmp = iter->data; + + if (NULL != tmp) { + ecore_main_fd_handler_del(tmp->dir_fd_handler); + inotify_rm_watch(tmp->dir_fd, tmp->dir_wd); + close(tmp->dir_fd); + + free(tmp); + tmp = NULL; + } + + g_ino_list = g_list_remove_link(g_ino_list, iter); + + iter = g_list_first(g_ino_list); + } + } + + return 0; +} + + + + + Eina_Bool vc_config_mgr_inotify_event_cb(void* data, Ecore_Fd_Handler *fd_handler) { SLOG(LOG_DEBUG, vc_config_tag(), "@@@ Config changed callback event"); @@ -529,14 +828,12 @@ int vc_config_mgr_initialize(int uid) } /* Get file name from default engine directory */ - DIR *dp = NULL; - struct dirent *dirp; - g_engine_list = NULL; if (0 != access(VC_CONFIG_BASE, F_OK)) { if (0 != mkdir(VC_CONFIG_BASE, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_CONFIG_BASE); + __vc_config_release_client(uid); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; } else { @@ -546,6 +843,7 @@ int vc_config_mgr_initialize(int uid) if (0 != access(VC_RUNTIME_INFO_ROOT, F_OK)) { if (0 != mkdir(VC_RUNTIME_INFO_ROOT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_RUNTIME_INFO_ROOT); + __vc_config_release_client(uid); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; } else { @@ -553,55 +851,49 @@ int vc_config_mgr_initialize(int uid) } } - dp = opendir(VC_DEFAULT_ENGINE_INFO); - if (NULL != dp) { - do { - dirp = readdir(dp); - - if (NULL != dirp) { - if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name)) - continue; - - vc_engine_info_s* info = NULL; - char* filepath = NULL; - int filesize = 0; - - filesize = strlen(VC_DEFAULT_ENGINE_INFO) + strlen(dirp->d_name) + 5; - filepath = (char*)calloc(filesize, sizeof(char)); - - if (NULL != filepath) { - snprintf(filepath, filesize, "%s/%s", VC_DEFAULT_ENGINE_INFO, dirp->d_name); - } else { - SLOG(LOG_ERROR, vc_config_tag(), "[Engine Agent ERROR] Memory not enough!!"); - continue; - } - - if (0 == vc_parser_get_engine_info(filepath, &info)) { - g_engine_list = g_slist_append(g_engine_list, info); - } - - if (NULL != filepath) { - free(filepath); - filepath = NULL; - } - } - } while (NULL != dirp); + if (0 != access(VC_DOWNLOAD_BASE, F_OK)) { + if (0 != mkdir(VC_DOWNLOAD_BASE, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_DOWNLOAD_BASE); + __vc_config_release_client(uid); + pthread_mutex_unlock(&vc_config_mgr_mutex); + return -1; + } else { + SLOG(LOG_DEBUG, vc_config_tag(), "Success to make directory : %s", VC_DOWNLOAD_BASE); + } + } + if (0 != access(VC_DOWNLOAD_ENGINE_INFO, F_OK)) { + if (0 != mkdir(VC_DOWNLOAD_ENGINE_INFO, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_DOWNLOAD_ENGINE_INFO); + __vc_config_release_client(uid); + pthread_mutex_unlock(&vc_config_mgr_mutex); + return -1; + } else { + SLOG(LOG_DEBUG, vc_config_tag(), "Success to make directory : %s", VC_DOWNLOAD_ENGINE_INFO); + } + } - closedir(dp); - } else { - SLOG(LOG_WARN, vc_config_tag(), "[Engine Agent WARNING] Fail to open default directory"); + if (0 != __vc_config_mgr_get_engine_info()) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get engine info"); + __vc_config_release_client(uid); + __vc_config_release_engine(); + pthread_mutex_unlock(&vc_config_mgr_mutex); + return VC_CONFIG_ERROR_ENGINE_NOT_FOUND; } __vc_config_mgr_print_engine_info(); if (0 != vc_parser_load_config(&g_config_info)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse configure information"); + __vc_config_release_client(uid); + __vc_config_release_engine(); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; } if (0 != __vc_config_mgr_check_engine_is_valid(g_config_info->engine_id)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get default engine"); + __vc_config_release_client(uid); + __vc_config_release_engine(); vc_parser_unload_config(g_config_info); pthread_mutex_unlock(&vc_config_mgr_mutex); return VC_CONFIG_ERROR_ENGINE_NOT_FOUND; @@ -616,6 +908,8 @@ int vc_config_mgr_initialize(int uid) char* tmp_language; if (0 != __vc_config_mgr_select_lang(g_config_info->engine_id, &tmp_language)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to select language"); + __vc_config_release_client(uid); + __vc_config_release_engine(); vc_parser_unload_config(g_config_info); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; @@ -630,6 +924,8 @@ int vc_config_mgr_initialize(int uid) if (0 != vc_parser_set_language(tmp_language)) { free(tmp_language); SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to save config"); + __vc_config_release_client(uid); + __vc_config_release_engine(); vc_parser_unload_config(g_config_info); pthread_mutex_unlock(&vc_config_mgr_mutex); return -1; @@ -655,6 +951,8 @@ int vc_config_mgr_initialize(int uid) temp_client = (vc_config_client_s*)calloc(1, sizeof(vc_config_client_s)); if (NULL == temp_client) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to allocate memory"); + __vc_config_release_client(uid); + __vc_config_release_engine(); vc_parser_unload_config(g_config_info); pthread_mutex_unlock(&vc_config_mgr_mutex); return VC_ERROR_OUT_OF_MEMORY; @@ -676,62 +974,22 @@ int vc_config_mgr_initialize(int uid) int vc_config_mgr_finalize(int uid) { - GSList *iter = NULL; - vc_config_client_s* temp_client = NULL; - SLOG(LOG_INFO, vc_config_tag(), "[WARNING] Enter critical section"); - pthread_mutex_lock(&vc_config_mgr_mutex); - if (0 < g_slist_length(g_config_client_list)) { - /* Check uid */ - iter = g_slist_nth(g_config_client_list, 0); - - while (NULL != iter) { - temp_client = iter->data; - - if (NULL != temp_client) { - if (uid == temp_client->uid) { - g_config_client_list = g_slist_remove(g_config_client_list, temp_client); - free(temp_client); - break; - } - } - - iter = g_slist_next(iter); - } - } + pthread_mutex_lock(&vc_config_mgr_mutex); - if (0 < g_slist_length(g_config_client_list)) { - SLOG(LOG_DEBUG, vc_config_tag(), "Client count (%d)", g_slist_length(g_config_client_list)); + if (0 < __vc_config_release_client(uid)) { pthread_mutex_unlock(&vc_config_mgr_mutex); - + SLOG(LOG_DEBUG, vc_config_tag(), "[WARNING] Leave critical section"); + if (0 != pthread_mutex_destroy(&vc_config_mgr_mutex)) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to destroy vc_config_mgr_mutex."); } - return 0; } - vc_engine_info_s *engine_info = NULL; - - if (0 < g_slist_length(g_engine_list)) { - - /* Get a first item */ - iter = g_slist_nth(g_engine_list, 0); - - while (NULL != iter) { - engine_info = iter->data; - - if (NULL != engine_info) { - g_engine_list = g_slist_remove(g_engine_list, engine_info); - - vc_parser_free_engine_info(engine_info); - } - - iter = g_slist_nth(g_engine_list, 0); - } - } - + __vc_config_release_engine(); + vconf_ignore_key_changed(VCONFKEY_LANGSET, __vc_config_language_changed_cb); vc_parser_unload_config(g_config_info); diff --git a/common/vc_config_parser.c b/common/vc_config_parser.c index ac89c5a..a862549 100644 --- a/common/vc_config_parser.c +++ b/common/vc_config_parser.c @@ -302,12 +302,12 @@ int vc_parser_load_config(vc_config_s** config_info) bool is_default_open = false; if (0 != access(VC_CONFIG, F_OK)) { - doc = xmlParseFile(VC_CONFIG_DEFAULT); + doc = xmlParseFile(VC_DEFAULT_CONFIG); if (doc == NULL) { - SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG_DEFAULT); + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_DEFAULT_CONFIG); return -1; } - SLOG(LOG_DEBUG, vc_config_tag(), "Use default config : %s", VC_CONFIG_DEFAULT); + SLOG(LOG_DEBUG, vc_config_tag(), "Use default config : %s", VC_DEFAULT_CONFIG); is_default_open = true; } else { int retry_count = 0; @@ -322,9 +322,9 @@ int vc_parser_load_config(vc_config_s** config_info) if (VC_RETRY_COUNT == retry_count) { SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG); - doc = xmlParseFile(VC_CONFIG_DEFAULT); + doc = xmlParseFile(VC_DEFAULT_CONFIG); if (NULL == doc) { - SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG_DEFAULT); + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_DEFAULT_CONFIG); xmlCleanupParser(); return -1; } @@ -760,6 +760,56 @@ int vc_parser_find_config_changed(int* auto_lang, char** language, int* enabled) return 0; } +int vc_parser_copy_xml(const char* original, const char* destination) +{ + if (NULL == original || NULL == destination) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Input parameter is NULL"); + return -1; + } + + xmlDocPtr doc = NULL; + if (0 == access(original, F_OK)) { + SLOG(LOG_DEBUG, vc_config_tag(), "[DEBUG] Success to access to %s", original); + doc = xmlParseFile(original); + if (doc == NULL) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", original); + return -1; + } + } else { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to access to %s", original); + return -1; + } + + int ret = xmlSaveFile(destination, doc); + if (0 > ret) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Save result : %d", ret); + } else { + static FILE* pFile; + pFile = fopen(destination, "r"); + int fd = -1; + if (NULL == pFile) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to open file %s", destination); + } else { + fd = fileno(pFile); + fsync(fd); + fclose(pFile); + SLOG(LOG_INFO, vc_config_tag(), "[DEBUG] Success to fsync %s", destination); + } + SLOG(LOG_ERROR, vc_config_tag(), "[DEBUG] Success to save %s", destination); + } + + /* Set mode */ + if (0 > chmod(destination, 0600)) { + SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to change file mode : %d", ret); + } + + xmlFreeDoc(doc); + doc = NULL; + SLOG(LOG_DEBUG, vc_config_tag(), "[SUCCESS] Copying xml"); + + return 0; +} + int vc_parser_set_foreground(int pid, bool value) { int cur_pid = 0; diff --git a/common/vc_config_parser.h b/common/vc_config_parser.h index 253aa11..15635f0 100644 --- a/common/vc_config_parser.h +++ b/common/vc_config_parser.h @@ -61,6 +61,8 @@ int vc_parser_set_enabled(bool value); int vc_parser_find_config_changed(int* auto_lang, char** language, int* enabled); +int vc_parser_copy_xml(const char* original, const char* destination); + /* Set / Get foreground info */ int vc_parser_set_foreground(int pid, bool value); diff --git a/common/vc_defs.h b/common/vc_defs.h index 096aa4f..d58ed69 100644 --- a/common/vc_defs.h +++ b/common/vc_defs.h @@ -179,7 +179,7 @@ extern "C" { #define VC_DAEMON_PATH tzplatform_mkpath(tzplatform_getid("TZ_SYS_BIN"), "vc-daemon") -#define VC_CONFIG_DEFAULT tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0/vc-config.xml") +#define VC_DEFAULT_CONFIG tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0/vc-config.xml") #define VC_DEFAULT_BASE tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0") @@ -207,6 +207,10 @@ extern "C" { #define VC_RUNTIME_INFO_CLIENT tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.voice/vc/vc-client-info.xml") +#define VC_DOWNLOAD_BASE tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/vc/1.0") + +#define VC_DOWNLOAD_ENGINE_INFO tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/vc/1.0/engine-info") + #define VC_NO_FOREGROUND_PID -1 #define VC_BASE_LANGUAGE "en_US" #define VC_RETRY_COUNT 5 diff --git a/engine-parser/CMakeLists.txt b/engine-parser/CMakeLists.txt new file mode 100644 index 0000000..84dafbe --- /dev/null +++ b/engine-parser/CMakeLists.txt @@ -0,0 +1,37 @@ +pkg_check_modules(parser-pkgs REQUIRED + capi-base-common + dlog + glib-2.0 + libxml-2.0 + pkgmgr-info + pkgmgr-installer + capi-appfw-app-manager + libtzplatform-config +) + +FOREACH(flag ${parser-pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET (SRCS + src/vc-engine-parser.c +) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall" ) +SET(extapi "-fvisibility=hidden") + +## SET C COMPILER FLAGS +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} ${extapi}") + +## SET CPP COMPILER FLAGS +#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") +#SET(CMAKE_CXX_FLAGS "${OSP_DEBUG_FLAGS} ${OSP_OPT_FLAGS} ${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} ${OSP_COMPILER_FLAGS}") + +## SET LINKER FLAGS +SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") + +## Create Library +ADD_LIBRARY ("${PROJECT_NAME}-engine-parser" SHARED ${SRCS}) +TARGET_LINK_LIBRARIES("${PROJECT_NAME}-engine-parser" ${parser-pkgs_LDFLAGS} ) + +INSTALL(TARGETS "${PROJECT_NAME}-engine-parser" DESTINATION "/etc/package-manager/parserlib/metadata") diff --git a/engine-parser/src/vc-engine-parser.c b/engine-parser/src/vc-engine-parser.c new file mode 100644 index 0000000..0e4a92a --- /dev/null +++ b/engine-parser/src/vc-engine-parser.c @@ -0,0 +1,883 @@ +// +// Copyright (c) 2016 Samsung Electronics Co., Ltd. +// +// 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. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Define EXPORT_API */ +#ifndef EXPORT_API +#define EXPORT_API __attribute__((visibility("default"))) +#endif + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "vc-engine-parser" + +#define VC_TAG_ENGINE_BASE "voice-control-engine" +#define VC_TAG_ENGINE_NAME "name" +#define VC_TAG_ENGINE_ID "id" +#define VC_TAG_ENGINE_SETTING "setting" +#define VC_TAG_ENGINE_LANGUAGE_SET "languages" +#define VC_TAG_ENGINE_LANGUAGE "lang" +#define VC_TAG_ENGINE_NON_FIXED_SUPPORT "non-fixed-support" +#define VC_TAG_ENGINE_CREDENTIAL "credential" + +#define VC_CONFIG_BASE tzplatform_mkpath(TZ_USER_HOME, "share/.voice") +#define VC_HOME tzplatform_mkpath(TZ_USER_HOME, "share/.voice/vc") +#define VC_ENGINE_BASE tzplatform_mkpath(TZ_USER_HOME, "share/.voice/vc/1.0") +#define VC_ENGINE_INFO tzplatform_mkpath(TZ_USER_SHARE, ".voice/vc/1.0/engine-info") + +#define VC_GLOBAL_CONFIG_BASE "/etc/skel/share/.voice" +#define VC_GLOBAL_HOME "/etc/skel/share/.voice/vc" +#define VC_GLOBAL_ENGINE_BASE "/etc/skel/share/.voice/vc/1.0" +#define VC_GLOBAL_ENGINE_INFO "/etc/skel/share/.voice/vc/1.0/engine-info" + +#define VC_METADATA_LANGUAGE "http://tizen.org/metadata/vc-engine/language" +#define VC_METADATA_NON_FIXED_SUPPORT "http://tizen.org/metadata/vc-engine/non-fixed-support" +#define VC_METADATA_CREDENTIAL_REQUIRED "http://tizen.org/metadata/vc-engine/credential-required" +#define VC_METADATA_ENGINE_SETTING "http://tizen.org/metadata/vc-engine/setting" +#define VC_METADATA_ENGINE_NAME "http://tizen.org/metadata/vc-engine/name" + +/* Define Macro */ +#define FREE(x) { if (NULL != x) { free(x); x = NULL; } } +#define G_FREE(x) { if (NULL != x) { g_free(x); x = NULL; } } + +typedef struct metadata { + const char *key; + const char *value; +} metadata; + +static xmlDocPtr g_doc; +GumUser *g_guser = NULL; +uid_t g_uid = 301; // app_fw +gid_t g_gid = 301; // app_fw +GumUserType g_ut = GUM_USERTYPE_NONE; +gchar *g_user_type = NULL; + +char *g_dir_config_base = NULL; +char *g_dir_home = NULL; +char *g_dir_engine_base = NULL; +char *g_dir_engine_info = NULL; + + +static int __create_engine_info_xml(const char *pkgid) +{ + LOGD("=== Create engine info doc"); + g_doc = xmlNewDoc((xmlChar*)"1.0"); + if (NULL == g_doc) { + LOGE("[ERROR] Fail to new doc"); + return -1; + } + LOGD("==="); + return 0; +} + +static int __save_engine_info_xml(const char *pkgid, gchar *ut, uid_t uid, gid_t gid) +{ + LOGD("=== Save engine info doc"); + char *dir_config_base = NULL; + char *dir_home = NULL; + char *dir_engine_base = NULL; + char *dir_engine_info = NULL; + + if (NULL == ut || (NULL != ut && 0 == strcmp(ut, "none"))) { + LOGE("[ERROR] Usertype is NONE"); + return -1; + } + + uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + uid_t tmp_uid = 0; + gid_t tmp_gid = 0; + LOGD("uid(%d)", uid); + + if (globalapp_uid == uid) { + /* Global app */ + dir_config_base = strdup(VC_GLOBAL_CONFIG_BASE); + dir_home = strdup(VC_GLOBAL_HOME); + dir_engine_base = strdup(VC_GLOBAL_ENGINE_BASE); + dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO); + tmp_uid = 301; // app_fw + tmp_gid = 301; // app_fw + } else { + /* User app, Guest app, Security app */ + if (NULL != g_dir_config_base) + dir_config_base = strdup(g_dir_config_base); + if (NULL != g_dir_home) + dir_home = strdup(g_dir_home); + if (NULL != g_dir_engine_base) + dir_engine_base = strdup(g_dir_engine_base); + if (NULL != g_dir_engine_info) + dir_engine_info = strdup(g_dir_engine_info); + tmp_uid = uid; + tmp_gid = gid; + } + + if (NULL == dir_config_base || NULL == dir_home || NULL == dir_engine_base || NULL == dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } + + LOGD("[DEBUG] dir_engine_info(%s)", dir_engine_info); + + /* Make directories */ + int fd = -1; +// if (0 != access(dir_config_base, F_OK)) { + fd = open(dir_config_base, O_DIRECTORY); + if (-1 == fd) { + LOGE("[INFO] No directory : %s, errno : %d", dir_config_base, errno); + if (0 != mkdir(dir_config_base, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_config_base, errno); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } else { + LOGD("Success to make directory : %s", dir_config_base); + if (0 != chown(dir_config_base, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group, errno : %d", errno); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + } else { + close(fd); + } + +// if (0 != access(dir_home, F_OK)) { + fd = open(dir_home, O_DIRECTORY); + if (-1 == fd) { + LOGE("[INFO] No directory : %s, errno : %d", dir_home, errno); + if (0 != mkdir(dir_home, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_home, errno); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } else { + LOGD("Success to make directory : %s", dir_home); + if (0 != chown(dir_home, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group, errno : %d", errno); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + } else { + close(fd); + } + +// if (0 != access(dir_engine_base, F_OK)) { + fd = open(dir_engine_base, O_DIRECTORY); + if (-1 == fd) { + LOGE("[INFO] No directory : %s, errno : %d", dir_engine_base, errno); + if (0 != mkdir(dir_engine_base, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_engine_base, errno); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } else { + LOGD("Success to make directory : %s", dir_engine_base); + if (0 != chown(dir_engine_base, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group, errno : %d", errno); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + } else { + close(fd); + } + +// if (0 != access(dir_engine_info, F_OK)) { + fd = open(dir_engine_info, O_DIRECTORY); + if (-1 == fd) { + LOGE("[INFO] No directory : %s, errno : %d", dir_engine_info, errno); + if (0 != mkdir(dir_engine_info, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { + LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_engine_info, errno); + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + return -1; + } else { + LOGD("Success to make directory : %s", dir_engine_info); + if (0 != chown(dir_engine_info, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group, errno : %d", errno); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + } else { + close(fd); + } + + char path[256] = {'\0',}; + snprintf(path, 256, "%s/%s.xml", dir_engine_info, pkgid); + int ret = xmlSaveFormatFile(path, g_doc, 1); + LOGD("xmlSaveFile (%d)", ret); + if (0 == ret) { + if (0 != chown(path, tmp_uid, tmp_gid)) { + LOGD("[ERROR] Fail to change user and group"); + } else { + LOGD("[DEBUG] Success to change user and group"); + } + } + + FREE(dir_config_base) + FREE(dir_home) + FREE(dir_engine_base) + FREE(dir_engine_info) + + LOGD("==="); + + return 0; +} + +static int __remove_engine_info_xml(const char *pkgid, gchar *ut, uid_t uid) +{ + LOGD("=== Remove engine info doc"); + char *dir_engine_info = NULL; + + if (NULL == ut || (NULL != ut && 0 == strcmp(ut, "none"))) { + LOGE("[ERROR] Usertype is NONE"); + return -1; + } + + uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + + LOGD("uid(%d)", uid); + + if (globalapp_uid == uid) { + /* Global app */ + dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO); + } else { + /* User app, Guest app, Security app */ + if (NULL != g_dir_engine_info) + dir_engine_info = strdup(g_dir_engine_info); + } + + if (NULL == dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + return -1; + } + + LOGD("[DEBUG] dir_engine_info(%s)", dir_engine_info); + + char path[256] = {'\0',}; + snprintf(path, 256, "%s/%s.xml", dir_engine_info, pkgid); + if (0 == access(path, F_OK)) { + LOGD("Remove engine info xml(%s)", path); + if (0 != remove(path)) { + LOGE("[ERROR] Fail to emove engine info xml(%s)", path); + } + } + + FREE(dir_engine_info) + + LOGD("==="); + + return 0; +} + +static void __insert_language_from_metadata(xmlNodePtr root, const char *language) +{ + LOGD("==== Insert language"); + char* lang = NULL; + + if (NULL == root || NULL == language) { + LOGE("Invalid parameter, root(%p), language(%s)", root, language); + return; + } + + char *tmp_lang, *tmp_free; + tmp_free = tmp_lang = strdup(language); + xmlNodePtr languages_node = NULL; + xmlNodePtr lang_node = NULL; + + languages_node = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_LANGUAGE_SET); + + lang = strsep(&tmp_lang, ","); + while (NULL != lang) { + LOGD("lang (%s)", lang); + lang_node = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_LANGUAGE); + xmlNodeSetContent(lang_node, (const xmlChar*)lang); + xmlAddChild(languages_node, lang_node); + lang = strsep(&tmp_lang, ","); + } + xmlAddChild(root, languages_node); + + FREE(tmp_free) +} + +static int __write_metadata_inxml(const char *pkgid, const char *appid, GList *list) +{ + GList *iter = NULL; + metadata *md = NULL; + + __create_engine_info_xml(pkgid); + + xmlNodePtr root = NULL; + xmlNodePtr cur = NULL; + + root = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_BASE); + + if (NULL == root) { + LOGE("[ERROR] Fail to get new node"); +// xmlFreeDoc(g_doc); + return -1; + } + xmlDocSetRootElement(g_doc, root); + + iter = g_list_first(list); + while (NULL != iter) { + md = (metadata *)iter->data; + if (NULL != md && NULL != md->key && NULL != md->value) { + LOGD(" - key(%s) value(%s)", md->key, md->value); + if (!strcmp(md->key, VC_METADATA_LANGUAGE)) { + __insert_language_from_metadata(root, md->value); + } else if (!strcmp(md->key, VC_METADATA_NON_FIXED_SUPPORT)) { + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_NON_FIXED_SUPPORT); + xmlNodeSetContent(cur, (const xmlChar*)md->value); + xmlAddChild(root, cur); + } else if (!strcmp(md->key, VC_METADATA_CREDENTIAL_REQUIRED)) { + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_CREDENTIAL); + xmlNodeSetContent(cur, (const xmlChar*)md->value); + xmlAddChild(root, cur); + } else if (!strcmp(md->key, VC_METADATA_ENGINE_SETTING)) { + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_SETTING); + xmlNodeSetContent(cur, (const xmlChar*)md->value); + xmlAddChild(root, cur); + } else if (!strcmp(md->key, VC_METADATA_ENGINE_NAME)) { + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_NAME); + xmlNodeSetContent(cur, (const xmlChar*)md->value); + xmlAddChild(root, cur); + } else { + LOGW("[WARNING] Unknown metadata type"); + } + } + iter = g_list_next(iter); + } + + cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_ID); + xmlNodeSetContent(cur, (const xmlChar*)appid); + xmlAddChild(root, cur); + + LOGD(""); + return 0; +} + +EXPORT_API +int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgid, const char *appid, GList *list) +{ + LOGD("METADATA INSTALL"); + LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list)); + + int ret = -1; + ret = pkgmgr_installer_info_get_target_uid(&g_uid); + if (ret < 0) { + LOGE("[ERROR] Fail to get target uid"); + return 0; + } else { + LOGD("uid(%d)", g_uid); + printf("[Parser Debug][DEBUG] uid(%d)", g_uid); + } + + uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + if (globalapp_uid == g_uid) { + g_user_type = g_strdup("admin"); + } else { + g_guser = gum_user_get_sync(g_uid, FALSE); + if (NULL == g_guser) { + LOGE("[ERROR] g_guser is NULL"); + return -1; + } + + g_object_get(G_OBJECT(g_guser), "gid", &g_gid, NULL); + g_object_get(G_OBJECT(g_guser), "usertype", &g_ut, NULL); + g_user_type = g_strdup(gum_user_type_to_string(g_ut)); + } + + if (NULL == g_user_type) { + LOGE("[ERROR] Fail to allocate memory"); + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + return -1; + } + + if (0 == strcmp(g_user_type, "none")) { + /* GUM_USERTYPE_NONE */ + LOGE("[ERROR] Fail to get target uid"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + if (globalapp_uid == g_uid) { + /* global directory */ + LOGD("[DEBUG] usertype: %s", g_user_type); + if (0 >= g_list_length(list)) { + LOGE("[ERROR] No Engine Metadata"); + G_FREE(g_user_type) + return 0; + } + + if (0 != __write_metadata_inxml(pkgid, appid, list)) { + LOGE("[ERROR] Fail to write metadata in the xml"); + xmlFreeDoc(g_doc); + G_FREE(g_user_type) + return -1; + } + + /* Save in /etc/skel/share/ */ + g_dir_config_base = strdup(VC_GLOBAL_CONFIG_BASE); + g_dir_home = strdup(VC_GLOBAL_HOME); + g_dir_engine_base = strdup(VC_GLOBAL_ENGINE_BASE); + g_dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO); + + if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + xmlFreeDoc(g_doc); + G_FREE(g_user_type) + return -1; + } + + if (0 != __save_engine_info_xml(pkgid, g_user_type, g_uid, g_gid)) { + LOGE("[ERROR] Fail to make engine info file"); + xmlFreeDoc(g_doc); + G_FREE(g_user_type) + return -1; + } + + /* Get user data by using libgum */ + + GumUserService *gus = NULL; + GumUserList *users = NULL; + GumUserList *iter = NULL; + GumUser *user = NULL; + gchar **query; + GumUserType gumut = GUM_USERTYPE_NONE; + gchar *user_type = NULL; + + uid_t uid; + gid_t gid; + gchar *home_dir = NULL; + + gus = gum_user_service_create_sync(TRUE); + if (!gus) { + LOGE("Failed to create gum user service"); + G_FREE(g_user_type) + return -1; + } + + query = g_strsplit("admin,normal", ",", -1); + + users = gum_user_service_get_user_list_sync(gus, (const gchar *const *)query); + g_strfreev(query); + + if (!users) { + LOGD("NO users"); + g_object_unref(gus); + gus = NULL; + G_FREE(g_user_type) + return 0; + } + + /* Make new user list */ + + iter = users; + while (iter != NULL) { + user = (GumUser*) iter->data; + g_object_get(G_OBJECT(user), "uid", &uid, NULL); + G_FREE(home_dir) + + g_object_get(G_OBJECT(user), "gid", &gid, NULL); + g_object_get(G_OBJECT(user), "homedir", &home_dir, NULL); + g_object_get(G_OBJECT(user), "usertype", &gumut, NULL); + user_type = g_strdup(gum_user_type_to_string(gumut)); + if (NULL == user_type) { + gum_user_service_list_free(users); + G_FREE(home_dir) + g_object_unref(gus); + gus = NULL; + return -1; + } + + LOGD("[DEBUG] user info"); + if (NULL != home_dir) { + LOGD("[DEBUG] uid(%d), gid(%d), user_type(%s), home_dir(%s)", uid, gid, user_type, home_dir); + + g_dir_config_base = (char*)calloc(strlen(home_dir) + 14, sizeof(char)); + g_dir_home = (char*)calloc(strlen(home_dir) + 17, sizeof(char)); + g_dir_engine_base = (char*)calloc(strlen(home_dir) + 21, sizeof(char)); + g_dir_engine_info = (char*)calloc(strlen(home_dir) + 33, sizeof(char)); + + if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + gum_user_service_list_free(users); + g_object_unref(gus); + gus = NULL; + G_FREE(user_type) + G_FREE(home_dir) + return -1; + } + snprintf(g_dir_config_base, strlen(home_dir) + 14, "%s/share/.voice", home_dir); + snprintf(g_dir_home, strlen(home_dir) + 17, "%s/share/.voice/vc", home_dir); + snprintf(g_dir_engine_base, strlen(home_dir) + 21, "%s/share/.voice/vc/1.0", home_dir); + snprintf(g_dir_engine_info, strlen(home_dir) + 33, "%s/share/.voice/vc/1.0/engine-info", home_dir); + + LOGD("[DEBUG] g_dir_engine_info(%s)", g_dir_engine_info); + + if (0 != __save_engine_info_xml(pkgid, user_type, uid, gid)) { + LOGE("[ERROR] Fail to make engine info file"); + } + + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + + G_FREE(home_dir) + } + + G_FREE(user_type) + iter = g_list_next(iter); + } + + gum_user_service_list_free(users); + g_object_unref(gus); + gus = NULL; + } else { + /* user directory */ + LOGD("[DEBUG] usertype: %s", g_user_type); + + ret = tzplatform_set_user(g_uid); + if (ret < 0) { + LOGE("[ERROR] Invalid uid"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return 0; + } else { + LOGD("TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/")); + printf("[Parser Debug][DEBUG] TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/")); + } + + if (0 >= g_list_length(list)) { + LOGE("[ERROR] No Engine Metadata"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return 0; + } + + if (0 != __write_metadata_inxml(pkgid, appid, list)) { + LOGE("[ERROR] Fail to write metadata in the xml"); + xmlFreeDoc(g_doc); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + g_dir_config_base = strdup(VC_CONFIG_BASE); + g_dir_home = strdup(VC_HOME); + g_dir_engine_base = strdup(VC_ENGINE_BASE); + g_dir_engine_info = strdup(VC_ENGINE_INFO); + + if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + xmlFreeDoc(g_doc); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + if (0 != __save_engine_info_xml(pkgid, g_user_type, g_uid, g_gid)) { + LOGE("[ERROR] Fail to make engine info file"); + xmlFreeDoc(g_doc); + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + G_FREE(g_user_type) + return -1; + } + } + + xmlFreeDoc(g_doc); + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + G_FREE(g_user_type) + + FREE(g_dir_config_base) + FREE(g_dir_home) + FREE(g_dir_engine_base) + FREE(g_dir_engine_info) + + return 0; +} + +EXPORT_API +int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgid, const char *appid, GList *list) +{ + LOGD("METADATA UNINSTALL"); + LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list)); + + int ret = -1; + ret = pkgmgr_installer_info_get_target_uid(&g_uid); + if (ret < 0) { + LOGE("[ERROR] Fail to get target uid"); + return 0; + } else { + LOGD("uid(%d)", g_uid); + printf("[Parser Debug][DEBUG] uid(%d)", g_uid); + } + + uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + if (globalapp_uid == g_uid) { + g_user_type = g_strdup("admin"); + } else { + g_guser = gum_user_get_sync(g_uid, FALSE); + if (NULL == g_guser) { + LOGE("[ERROR] g_guser is NULL"); + return -1; + } + + g_object_get(G_OBJECT(g_guser), "usertype", &g_ut, NULL); + g_user_type = g_strdup(gum_user_type_to_string(g_ut)); + } + + if (NULL == g_user_type) { + LOGE("[ERROR] Fail to allocate memory"); + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + return -1; + } + + if (0 == strcmp(g_user_type, "none")) { + /* GUM_USERTYPE_NONE */ + LOGE("[ERROR] Fail to get target uid"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + if (globalapp_uid == g_uid) { + /* global directory */ + LOGD("[DEBUG] usertype: %s", g_user_type); + + /* Remove files in /etc/skel/share/ */ + g_dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO); + if (NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + G_FREE(g_user_type) + return -1; + } + + if (0 != __remove_engine_info_xml(pkgid, g_user_type, g_uid)) { + LOGE("[ERROR] Fail to remove engine info file"); + } + + /* Get user data by using libgum */ + + GumUserService *gus = NULL; + GumUserList *users = NULL; + GumUserList *iter = NULL; + GumUser *user = NULL; + gchar **query; + GumUserType gumut = GUM_USERTYPE_NONE; + gchar *user_type = NULL; + + uid_t uid; + gchar *home_dir = NULL; + + GList *md_iter = NULL; + metadata *md = NULL; + + gus = gum_user_service_create_sync(TRUE); + if (!gus) { + LOGE("Failed to create gum user service"); + G_FREE(g_user_type) + return -1; + } + + query = g_strsplit("admin,normal", ",", -1); + + users = gum_user_service_get_user_list_sync(gus, (const gchar *const *)query); + g_strfreev(query); + + if (!users) { + LOGD("NO users"); + g_object_unref(gus); + gus = NULL; + G_FREE(g_user_type) + return 0; + } + + /* Make new user list */ + + iter = users; + while (iter != NULL) { + user = (GumUser*) iter->data; + g_object_get(G_OBJECT(user), "uid", &uid, NULL); + G_FREE(home_dir) + g_object_get(G_OBJECT(user), "homedir", &home_dir, NULL); + g_object_get(G_OBJECT(user), "usertype", &gumut, NULL); + user_type = g_strdup(gum_user_type_to_string(gumut)); + if (NULL == user_type) { + gum_user_service_list_free(users); + G_FREE(home_dir) + g_object_unref(gus); + gus = NULL; + return -1; + } + + if (NULL != home_dir) { + g_dir_engine_info = (char*)calloc(strlen(home_dir) + 33, sizeof(char)); + if (NULL == g_dir_engine_info) { + gum_user_service_list_free(users); + G_FREE(home_dir) + g_object_unref(gus); + gus = NULL; + G_FREE(user_type) + return -1; + } + + snprintf(g_dir_engine_info, strlen(home_dir) + 33, "%s/share/.voice/vc/1.0/engine-info", home_dir); + + md_iter = g_list_first(list); + while (NULL != md_iter) { + md = (metadata *)md_iter->data; + LOGD(" - key(%s) value(%s)", md->key, md->value); + md_iter = g_list_next(md_iter); + } + + if (0 != __remove_engine_info_xml(pkgid, user_type, uid)) { + LOGE("[ERROR] Fail to remove engine info file"); + } + + G_FREE(home_dir) + G_FREE(g_dir_engine_info) + } + G_FREE(user_type) + + LOGD("Finish release memory"); + iter = g_list_next(iter); + LOGD("Finish next iter"); + } + + gum_user_service_list_free(users); + g_object_unref(gus); + gus = NULL; + } else { + /* user directory */ + LOGD("[DEBUG] usertype: %s", g_user_type); + + ret = tzplatform_set_user(g_uid); + if (ret < 0) { + LOGE("[ERROR] Invalid uid"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } else { + LOGD("TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/")); + printf("[Parser Debug][DEBUG] TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/")); + } + + g_dir_engine_info = strdup(VC_ENGINE_INFO); + if (NULL == g_dir_engine_info) { + LOGE("[ERROR] Fail to allocate memory"); + g_object_unref(g_guser); + g_guser = NULL; + G_FREE(g_user_type) + return -1; + } + + if (0 != __remove_engine_info_xml(pkgid, g_user_type, g_uid)) { + LOGE("[ERROR] Fail to remove engine info file"); + } + + } + + if (NULL != g_guser) { + g_object_unref(g_guser); + g_guser = NULL; + } + G_FREE(g_user_type) + + FREE(g_dir_engine_info) + + LOGD(""); + return 0; +} + +EXPORT_API +int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgid, const char *appid, GList *list) +{ + LOGD("METADATA UPGRADE"); + LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list)); + + PKGMGR_MDPARSER_PLUGIN_UNINSTALL(pkgid, appid, list); + PKGMGR_MDPARSER_PLUGIN_INSTALL(pkgid, appid, list); + + LOGD(""); + return 0; +} diff --git a/packaging/voice-control.spec b/packaging/voice-control.spec index 278936c..6d0cc6d 100644 --- a/packaging/voice-control.spec +++ b/packaging/voice-control.spec @@ -26,9 +26,12 @@ BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(ecore-wayland) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(json-glib-1.0) +BuildRequires: pkgconfig(libgum) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(sqlite3) +BuildRequires: pkgconfig(pkgmgr-info) +BuildRequires: pkgconfig(pkgmgr-installer) %if "%{tizen_profile_name}" == "tv" BuildRequires: pkgconfig(capi-network-bluetooth) BuildRequires: pkgconfig(capi-network-bluetooth-tv) @@ -128,6 +131,7 @@ mkdir -p %{_libdir}/voice/vc %{_libdir}/libvc_engine.so %{TZ_SYS_RO_SHARE}/voice/vc/1.0/vc-config.xml %{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.voice* +%{TZ_SYS_RO_ETC}/package-manager/parserlib/metadata/libvc-engine-parser.so* /etc/dbus-1/session.d/vc-server.conf %files devel