From 39c677dccdb77e96fc7f6d072bfa16ae20fe7366 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 11 Apr 2019 08:10:49 +0900 Subject: [PATCH] Add a new pkgmgr parser plugin for component-based application Change-Id: I8a677cbfbea0760b8cc91e3f4b33b391b460d2f2 Signed-off-by: Hwankyu Jhun --- CMakeLists.txt | 2 +- packaging/aul.spec | 16 +- parser/CMakeLists.txt | 26 +- parser/component/CMakeLists.txt | 33 + parser/component/data/component.info | 1 + parser/component/data/component_db.sql | 23 + parser/component/inc/component_plugin_parser.h | 28 + parser/component/inc/component_plugin_parser_db.h | 36 + .../inc/component_plugin_parser_handler.h | 30 + .../inc/component_plugin_parser_private.h | 61 ++ .../component/inc/component_plugin_parser_type.h | 46 ++ parser/component/script/14_component-add.post | 53 ++ parser/component/src/component_plugin_parser.c | 92 +++ parser/component/src/component_plugin_parser_db.c | 767 ++++++++++++++++++ .../src/component_plugin_parser_handler.c | 887 +++++++++++++++++++++ .../src/component_plugin_parser_pkgmgr_interface.c | 37 + parser/metadata/CMakeLists.txt | 26 + parser/{ => metadata/inc}/metadata_plugin_parser.h | 0 .../{ => metadata/inc}/metadata_plugin_parser_db.h | 0 .../inc}/metadata_plugin_parser_handler.h | 0 parser/{ => metadata/src}/metadata_plugin_parser.c | 0 .../{ => metadata/src}/metadata_plugin_parser_db.c | 0 .../src}/metadata_plugin_parser_handler.c | 0 .../src}/metadata_plugin_parser_pkgmgr_interface.c | 0 24 files changed, 2137 insertions(+), 27 deletions(-) create mode 100644 parser/component/CMakeLists.txt create mode 100644 parser/component/data/component.info create mode 100644 parser/component/data/component_db.sql create mode 100644 parser/component/inc/component_plugin_parser.h create mode 100644 parser/component/inc/component_plugin_parser_db.h create mode 100644 parser/component/inc/component_plugin_parser_handler.h create mode 100644 parser/component/inc/component_plugin_parser_private.h create mode 100644 parser/component/inc/component_plugin_parser_type.h create mode 100755 parser/component/script/14_component-add.post create mode 100644 parser/component/src/component_plugin_parser.c create mode 100644 parser/component/src/component_plugin_parser_db.c create mode 100644 parser/component/src/component_plugin_parser_handler.c create mode 100644 parser/component/src/component_plugin_parser_pkgmgr_interface.c create mode 100644 parser/metadata/CMakeLists.txt rename parser/{ => metadata/inc}/metadata_plugin_parser.h (100%) rename parser/{ => metadata/inc}/metadata_plugin_parser_db.h (100%) rename parser/{ => metadata/inc}/metadata_plugin_parser_handler.h (100%) rename parser/{ => metadata/src}/metadata_plugin_parser.c (100%) rename parser/{ => metadata/src}/metadata_plugin_parser_db.c (100%) rename parser/{ => metadata/src}/metadata_plugin_parser_handler.c (100%) rename parser/{ => metadata/src}/metadata_plugin_parser_pkgmgr_interface.c (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8bdf8c..2b5dd6c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(EXEC_PREFIX "\${prefix}") diff --git a/packaging/aul.spec b/packaging/aul.spec index 6fd8c8b..7d8cf9a 100755 --- a/packaging/aul.spec +++ b/packaging/aul.spec @@ -69,6 +69,7 @@ MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` %__make %{?_smp_mflags} sqlite3 .appsvc.db < ./data/appsvc_db.sql +sqlite3 .component.db < ./parser/component/data/component_db.sql %install rm -rf %{buildroot} @@ -78,6 +79,8 @@ mkdir -p %{buildroot}%{_tmpfilesdir} mkdir -p %{buildroot}%{TZ_SYS_DB} install -m 0644 .appsvc.db %{buildroot}%{TZ_SYS_DB} install -m 0644 .appsvc.db-journal %{buildroot}%{TZ_SYS_DB} +install -m 0644 .component.db %{buildroot}%{TZ_SYS_DB} +install -m 0644 .component.db-journal %{buildroot}%{TZ_SYS_DB} mkdir -p %{buildroot}%{_datadir}/appsvc cp -R %{_builddir}/%{name}-%{version}/alias/* %{buildroot}%{_datadir}/appsvc @@ -94,6 +97,11 @@ chmod 666 %{TZ_SYS_DB}/.appsvc.db chmod 666 %{TZ_SYS_DB}/.appsvc.db-journal chsmack -a 'User::Home' %{TZ_SYS_DB}/.appsvc.db chsmack -a 'User::Home' %{TZ_SYS_DB}/.appsvc.db-journal +chmod 666 %{TZ_SYS_DB}/.component.db +chmod 666 %{TZ_SYS_DB}/.component.db-journal +chsmack -a 'User::Home' %{TZ_SYS_DB}/.component.db +chsmack -a 'User::Home' %{TZ_SYS_DB}/.component.db-journal + %postun /sbin/ldconfig @@ -113,10 +121,12 @@ chsmack -a 'User::Home' %{TZ_SYS_DB}/.appsvc.db-journal %{_datadir}/aul/miregex/* %{_datadir}/aul/preexec_list.txt %{_datadir}/appsvc/* -%{TZ_SYS_DB}/.appsvc.db -%{TZ_SYS_DB}/.appsvc.db-journal +%{_datadir}/parser-plugins/* +%{TZ_SYS_DB}/.appsvc.db* +%{TZ_SYS_DB}/.component.db* %{_sysconfdir}/package-manager/parserlib/metadata/libaul-parser.so -%attr(0755,root,root) %{_sysconfdir}/gumd/useradd.d/12_appsvc-add.post +%{_sysconfdir}/package-manager/parserlib/libcomponent-based-application.so +%attr(0755,root,root) %{_sysconfdir}/gumd/useradd.d/* %files test %{_bindir}/open_app diff --git a/parser/CMakeLists.txt b/parser/CMakeLists.txt index 0f964db..e42ed21 100644 --- a/parser/CMakeLists.txt +++ b/parser/CMakeLists.txt @@ -1,24 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT(aul-parser C) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/parser SRCS) - -pkg_check_modules(PKGS REQUIRED - glib-2.0 - libxml-2.0 - dlog - libtzplatform-config - pkgmgr-installer - sqlite3 - ) - -FOREACH(FLAGS ${PKGS_CFLAGS}) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}") -ENDFOREACH(FLAGS) - -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fPIC") - -ADD_LIBRARY(aul-parser SHARED ${SRCS}) -TARGET_LINK_LIBRARIES(aul-parser ${PKGS_LDFLAGS}) - -INSTALL(TARGETS aul-parser DESTINATION ${SYSCONF_INSTALL_DIR}/package-manager/parserlib/metadata) +ADD_SUBDIRECTORY(metadata) +ADD_SUBDIRECTORY(component) diff --git a/parser/component/CMakeLists.txt b/parser/component/CMakeLists.txt new file mode 100644 index 0000000..a76c26f --- /dev/null +++ b/parser/component/CMakeLists.txt @@ -0,0 +1,33 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +PROJECT(component-plugin-parser C) + +SET(SHARED_DIR "${CMAKE_INSTALL_PREFIX}/share") + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/inc) + +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SRCS) + +pkg_check_modules(PKGS REQUIRED + glib-2.0 + libxml-2.0 + dlog + libtzplatform-config + pkgmgr-installer + sqlite3 + ) + +FOREACH(FLAGS ${PKGS_CFLAGS}) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}") +ENDFOREACH(FLAGS) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fPIC") + +ADD_LIBRARY(component-based-application SHARED ${SRCS}) +TARGET_LINK_LIBRARIES(component-based-application ${PKGS_LDFLAGS} "-ldl") + +INSTALL(TARGETS component-based-application + DESTINATION ${SYSCONF_INSTALL_DIR}/package-manager/parserlib) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/component.info + DESTINATION ${SHARED_DIR}/parser-plugins) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/script/14_component-add.post + DESTINATION ${SYSCONF_INSTALL_DIR}/gumd/useradd.d) diff --git a/parser/component/data/component.info b/parser/component/data/component.info new file mode 100644 index 0000000..836722f --- /dev/null +++ b/parser/component/data/component.info @@ -0,0 +1 @@ +type="tag";name="component-based-application";path="/etc/package-manager/parserlib/libcomponent-based-application.so" diff --git a/parser/component/data/component_db.sql b/parser/component/data/component_db.sql new file mode 100644 index 0000000..8dfa36a --- /dev/null +++ b/parser/component/data/component_db.sql @@ -0,0 +1,23 @@ +PRAGMA journal_mode = PERSIST; + +CREATE TABLE IF NOT EXISTS component_info ( + package TEXT NOT NULL, + app_id TEXT NOT NULL, + component_id TEXT NOT NULL, + component_type TEXT NOT NULL, + component_launch_mode TEXT NOT NULL, + component_main TEXT NOT NULL, + component_icon_display NOT NULL, + component_taskmanage NOT NULL, + PRIMARY KEY (component_id) +); + +CREATE TABLE IF NOT EXISTS component_localized_info ( + component_id TEXT NOT NULL, + component_locale TEXT NOT NULL DEFAULT 'No Locale', + component_label TEXT, + component_icon TEXT, + PRIMARY KEY (component_id, component_locale) + FOREIGN KEY (component_id) + REFERENCES component_info(component_id) ON DELETE CASCADE +); diff --git a/parser/component/inc/component_plugin_parser.h b/parser/component/inc/component_plugin_parser.h new file mode 100644 index 0000000..c6b3e8b --- /dev/null +++ b/parser/component/inc/component_plugin_parser.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMPONENT_PLUGIN_PARSER_H__ +#define __COMPONENT_PLUGIN_PARSER_H__ + +#include + +int component_plugin_parser_install(xmlDocPtr doc, const char *package); + +int component_plugin_parser_uninstall(xmlDocPtr doc, const char *package); + +int component_plugin_parser_upgrade(xmlDocPtr doc, const char *package); + +#endif /* __COMPONENT_PLUGIN_PARSER_H__ */ diff --git a/parser/component/inc/component_plugin_parser_db.h b/parser/component/inc/component_plugin_parser_db.h new file mode 100644 index 0000000..b78c852 --- /dev/null +++ b/parser/component/inc/component_plugin_parser_db.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMPONENT_PLUGIN_PARSER_DB_H__ +#define __COMPONENT_PLUGIN_PARSER_DB_H__ + +#include "component_plugin_parser_type.h" + +int component_plugin_parser_db_init(void); + +int component_plugin_parser_db_fini(void); + +int component_plugin_parser_db_begin_transaction(void); + +int component_plugin_parser_db_end_transaction(void); + +int component_plugin_parser_db_rollback(void); + +int component_plugin_parser_db_insert(component_t *component); + +int component_plugin_parser_db_delete(const char *package); + +#endif /* __COMPONENT_PLUGIN_PARSER_DB_H__ */ diff --git a/parser/component/inc/component_plugin_parser_handler.h b/parser/component/inc/component_plugin_parser_handler.h new file mode 100644 index 0000000..2fb3c97 --- /dev/null +++ b/parser/component/inc/component_plugin_parser_handler.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMPONENT_PLUGIN_PARSER_HANDLER_H__ +#define __COMPONENT_PLUGIN_PARSER_HANDLER_H__ + +#include + +int component_plugin_parser_handler_install(const char *package, xmlDocPtr doc); + +int component_plugin_parser_handler_uninstall(const char *package); + +int component_plugin_parser_handler_init(void); + +int component_plugin_parser_handler_fini(void); + +#endif /* __COMPONENT_PLUGIN_PARSER_HANDLER_H__ */ diff --git a/parser/component/inc/component_plugin_parser_private.h b/parser/component/inc/component_plugin_parser_private.h new file mode 100644 index 0000000..6539384 --- /dev/null +++ b/parser/component/inc/component_plugin_parser_private.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMPONENT_PLUGIN_PARSER_PRIVATE_H__ +#define __COMPONENT_PLUGIN_PARSER_PRIVATE_H__ + +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "COMPONENT_PLUGIN_PARSER" + +#ifdef EXPORT +#undef EXPORT +#endif + +#define EXPORT __attribute__ ((visibility("default"))) + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#define ROOT_UID 0 + +#define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) + +#define FEATURE_SCREEN_DPI "http://tizen.org/feature/screen.dpi" + +#define DEFAULT_LOCALE "No Locale" + +#define LDPI "ldpi" +#define MDPI "mdpi" +#define HDPI "hdpi" +#define XHDPI "xhdpi" +#define XXHDPI "xxhdpi" + +#define LDPI_MIN 0 +#define LDPI_MAX 240 +#define MDPI_MIN 241 +#define MDPI_MAX 300 +#define HDPI_MIN 301 +#define HDPI_MAX 380 +#define XHDPI_MIN 381 +#define XHDPI_MAX 480 +#define XXHDPI_MIN 481 +#define XXHDPI_MAX 600 + +#endif /* __COMPONENT_PLUGIN_PARSER_PRIVATE_H__ */ diff --git a/parser/component/inc/component_plugin_parser_type.h b/parser/component/inc/component_plugin_parser_type.h new file mode 100644 index 0000000..1f465a1 --- /dev/null +++ b/parser/component/inc/component_plugin_parser_type.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMPONENT_PLUGIN_PARSER_TYPE_H__ +#define __COMPONENT_PLUGIN_PARSER_TYPE_H__ + +#include + +typedef struct { + char *label; + char *lang; +} label_t; + +typedef struct { + char *icon; + char *lang; + char *dpi; +} icon_t; + +typedef struct { + char *package; + char *app_id; + char *id; + char *type; + char *launch_mode; + char *main; + char *icon_display; + char *taskmanage; + GList *icon; + GList *label; +} component_t; + +#endif /* __COMPONENT_PLUGIN_PARSER_TYPE_H__ */ diff --git a/parser/component/script/14_component-add.post b/parser/component/script/14_component-add.post new file mode 100755 index 0000000..236bc55 --- /dev/null +++ b/parser/component/script/14_component-add.post @@ -0,0 +1,53 @@ +#!/bin/sh + +#------------------------------------------# +# Add Component DB # +#------------------------------------------# + +# Macro +PATH=/bin:/usr/bin:/sbin:/usr/sbin + +# Create DB Path +mkdir -p -Z User::Home -m 755 /opt/dbspace/user +export `tzplatform-get --user $2 TZ_USER_NAME` +mkdir -p -Z User::Home -m 770 /opt/dbspace/user/$2 +chown $TZ_USER_NAME:system_share /opt/dbspace/user/$2 + +# Create DB +sqlite3 /opt/dbspace/user/$2/.component.db << EOF +PRAGMA journal_mode = PERSIST; + +CREATE TABLE IF NOT EXISTS component_info ( + package TEXT NOT NULL, + app_id TEXT NOT NULL, + component_id TEXT NOT NULL, + component_type TEXT NOT NULL, + component_launch_mode TEXT NOT NULL, + component_main TEXT NOT NULL, + component_icon_display NOT NULL, + component_taskmanage NOT NULL, + PRIMARY KEY (component_id) +); + +CREATE TABLE IF NOT EXISTS component_localized_info ( + component_id TEXT NOT NULL, + component_locale TEXT NOT NULL DEFAULT 'No Locale', + component_label TEXT, + component_icon TEXT, + PRIMARY KEY (component_id, component_locale) + FOREIGN KEY (component_id) + REFERENCES component_info(component_id) ON DELETE CASCADE +); + +EOF + +# Adjust Permission +chmod 664 /opt/dbspace/user/$2/.component.db +chmod 664 /opt/dbspace/user/$2/.component.db-journal + +chown $TZ_USER_NAME:system_share /opt/dbspace/user/$2/.component.db +chown $TZ_USER_NAME:system_share /opt/dbspace/user/$2/.component.db-journal + +chsmack -a User::Home /opt/dbspace/user/$2/.component.db +chsmack -a User::Home /opt/dbspace/user/$2/.component.db-journal + diff --git a/parser/component/src/component_plugin_parser.c b/parser/component/src/component_plugin_parser.c new file mode 100644 index 0000000..ff9782e --- /dev/null +++ b/parser/component/src/component_plugin_parser.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#define _GNU_SOURCE +#include + +#include "component_plugin_parser.h" +#include "component_plugin_parser_handler.h" +#include "component_plugin_parser_private.h" + +int component_plugin_parser_install(xmlDocPtr doc, const char *package) +{ + int ret; + + ret = component_plugin_parser_handler_init(); + if (ret < 0) { + LOGE("Failed to initialize parser handler"); + return -1; + } + + ret = component_plugin_parser_handler_install(package, doc); + if (ret < 0) { + LOGE("Failed to intall components. package(%s)", package); + component_plugin_parser_handler_fini(); + return -1; + } + + component_plugin_parser_handler_fini(); + + return 0; +} + +int component_plugin_parser_uninstall(xmlDocPtr doc, const char *package) +{ + int ret; + + ret = component_plugin_parser_handler_init(); + if (ret < 0) { + LOGE("Failed to initializer parser handler"); + return -1; + } + + ret = component_plugin_parser_handler_uninstall(package); + if (ret < 0) { + LOGE("Failed to uninstall components. package(%s)", package); + component_plugin_parser_handler_fini(); + return 0; + } + + component_plugin_parser_handler_fini(); + + return 0; +} + +int component_plugin_parser_upgrade(xmlDocPtr doc, const char *package) +{ + int ret; + + ret = component_plugin_parser_handler_init(); + if (ret < 0) { + LOGE("Failed to initialize parser handler"); + return -1; + } + + ret = component_plugin_parser_handler_uninstall(package); + if (ret < 0) + LOGW("Failed to uninstall components. package(%s)", package); + + ret = component_plugin_parser_handler_install(package, doc); + if (ret < 0) { + LOGE("Failed to install components. package(%s)", package); + component_plugin_parser_handler_fini(); + return -1; + } + + component_plugin_parser_handler_fini(); + + return 0; +} diff --git a/parser/component/src/component_plugin_parser_db.c b/parser/component/src/component_plugin_parser_db.c new file mode 100644 index 0000000..8eb24da --- /dev/null +++ b/parser/component/src/component_plugin_parser_db.c @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "component_plugin_parser_db.h" +#include "component_plugin_parser_private.h" + +#define LIBCAPI_SYSTEM_INFO "/usr/lib/libcapi-system-info.so.0" + +#define BUSY_WAITING_USEC 50000 +#define BUSY_WAITING_MAX 40 + +#define BIND_TEXT(db, stmt, i, text) do { \ + if (sqlite3_bind_text(stmt, i, text, -1, SQLITE_STATIC) != SQLITE_OK) {\ + LOGE("sqlite3_bind_text() is failed. error(%s)", \ + sqlite3_errmsg(db)); \ + sqlite3_finalize(stmt); \ + return -1; \ + } \ +} while (0) + +struct cb_data_s { + const char *lang; + int dpi; +}; + +static sqlite3 *__db; +static int (*__system_info_get_platform_int)(const char *, int *); + +static int __load_system_info(void) +{ + void *handle; + + if (__system_info_get_platform_int) + return 0; + + __system_info_get_platform_int = dlsym(RTLD_DEFAULT, + "system_info_get_platform_int"); + if (__system_info_get_platform_int) + return 0; + + handle = dlopen(LIBCAPI_SYSTEM_INFO, RTLD_LAZY | RTLD_LOCAL); + if (!handle) { + LOGE("Failed to open %s", LIBCAPI_SYSTEM_INFO); + return -1; + } + + __system_info_get_platform_int = dlsym(handle, + "system_info_get_platform_int"); + if (!__system_info_get_platform_int) { + LOGE("Failed to find system_info_get_platform_int"); + return -1; + } + + return 0; +} + +static uid_t __get_target_uid(void) +{ + static uid_t target_uid = (uid_t)-1; + int ret; + + if (target_uid != (uid_t)-1) + return target_uid; + + ret = pkgmgr_installer_info_get_target_uid(&target_uid); + if (ret < 0) + LOGE("Failed to get target uid. error(%d)", ret); + + return target_uid; +} + +static bool __is_global_user(uid_t uid) +{ + if (uid == ROOT_UID || uid == GLOBAL_USER) + return true; + + return false; +} + +static const char *__get_db_path(uid_t uid) +{ + const char *path; + + if (!__is_global_user(uid)) + tzplatform_set_user(uid); + + path = tzplatform_mkpath(__is_global_user(uid) ? + TZ_SYS_DB : TZ_USER_DB, ".component.db"); + tzplatform_reset_user(); + + return path; +} + +static int __db_busy_handler(void *data, int count) +{ + const char *path = (const char *)data; + + if (count < BUSY_WAITING_MAX) { + usleep(BUSY_WAITING_USEC); + return 1; + } + + LOGE("Database(%s) is busy", path); + + return 0; +} + +static sqlite3 *__open_db(const char *path) +{ + sqlite3 *db = NULL; + int ret; + + ret = sqlite3_open_v2(path, &db, SQLITE_OPEN_READWRITE, NULL); + if (ret != SQLITE_OK) { + LOGE("sqlite3_open_v2() is failed. error(%d)", ret); + if (db) + sqlite3_close_v2(db); + return NULL; + } + + ret = sqlite3_busy_handler(db, __db_busy_handler, (void *)path); + if (ret != SQLITE_OK) { + LOGE("Failed to register busy handler. error(%s)", + sqlite3_errmsg(db)); + sqlite3_close_v2(db); + return NULL; + } + + return db; +} + +void __close_db(sqlite3 *db) +{ + if (!db) + return; + + sqlite3_close_v2(db); +} + +static bool __integrity_check(sqlite3 *db) +{ + static const char query[] = "PRAGMA integrity_check"; + sqlite3_stmt *stmt = NULL; + const char *res; + int ret; + + ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + LOGE("sqlite3_prepare_v2() is failed. error(%s)", + sqlite3_errmsg(db)); + return false; + } + + ret = sqlite3_step(stmt); + if (ret != SQLITE_ROW) { + LOGE("sqlite3_step() is failed. error(%s)", sqlite3_errmsg(db)); + sqlite3_finalize(stmt); + return false; + } + + res = (const char *)sqlite3_column_text(stmt, 0); + if (!res) { + LOGE("Failed to check integrity db. error(%s)", + sqlite3_errmsg(db)); + sqlite3_finalize(stmt); + return false; + } + + if (strcmp(res, "ok") != 0) { + sqlite3_finalize(stmt); + return false; + } + + sqlite3_finalize(stmt); + + return true; +} + +static gint __compare_lang(gconstpointer a, gconstpointer b, + gpointer user_data) +{ + const char *lang_a = (const char *)a; + const char *lang_b = (const char *)b; + + if (lang_a == NULL || lang_b == NULL) + return 0; + + return strcmp(lang_a, lang_b); +} + +static gint __compare_label_with_lang(gconstpointer a, gconstpointer b) +{ + label_t *label = (label_t *)a; + const char *lang = (const char *)b; + + return strcasecmp(label->lang, lang); +} + +static int __check_screen_dpi(const char *dpi_str, int dpi_int) +{ + if (dpi_str == NULL) + return -1; + + if (strcasecmp(dpi_str, LDPI) == 0) { + if (dpi_int >= LDPI_MIN && dpi_int <= LDPI_MAX) + return 0; + } else if (strcasecmp(dpi_str, MDPI) == 0) { + if (dpi_int >= MDPI_MIN && dpi_int <= MDPI_MAX) + return 0; + } else if (strcasecmp(dpi_str, HDPI) == 0) { + if (dpi_int >= HDPI_MIN && dpi_int <= HDPI_MAX) + return 0; + } else if (strcasecmp(dpi_str, XHDPI) == 0) { + if (dpi_int >= XHDPI_MIN && dpi_int <= XHDPI_MAX) + return 0; + } else if (strcasecmp(dpi_str, XXHDPI) == 0) { + if (dpi_int >= XXHDPI_MIN && dpi_int <= XXHDPI_MAX) + return 0; + } + + return -1; +} + +static int __get_screen_dpi_strings(int dpi, const char *(*dpi_str)[2]) +{ + if (!dpi_str) + return -1; + + if (dpi >= LDPI_MIN && dpi <= LDPI_MAX) { + (*dpi_str)[0] = "LDPI"; + (*dpi_str)[1] = "ldpi"; + } else if (dpi >= MDPI_MIN && dpi <= MDPI_MAX) { + (*dpi_str)[0] = "MDPI"; + (*dpi_str)[1] = "mdpi"; + } else if (dpi >= HDPI_MIN && dpi <= HDPI_MAX) { + (*dpi_str)[0] = "HDPI"; + (*dpi_str)[1] = "hdpi"; + } else if (dpi >= XHDPI_MIN && dpi <= XHDPI_MAX) { + (*dpi_str)[0] = "XHDPI"; + (*dpi_str)[1] = "xhdpi"; + } else if (dpi >= XXHDPI_MIN && dpi <= XXHDPI_MAX) { + (*dpi_str)[0] = "XXHDPI"; + (*dpi_str)[1] = "xxhdpi"; + } else { + LOGE("Unidentified dpi[%d]", dpi); + return -1; + } + + return 0; +} + +static int __check_icon_resolution(int dpi, const char *icon, char **new_icon) +{ + const char *dpi_str[2] = { NULL, }; + char path[PATH_MAX]; + char buf[PATH_MAX]; + const char *file; + const char *dir; + int ret; + + if (!icon || !new_icon) + return -1; + + ret = __get_screen_dpi_strings(dpi, &dpi_str); + if (ret != 0) + return -1; + + snprintf(buf, sizeof(buf), "%s", icon); + file = basename(buf); + if (!file) + return -1; + + dir = dirname(buf); + if (!dir) + return -1; + + snprintf(path, sizeof(path), "%s/%s%s", dir, dpi_str[0], file); + if (access(path, F_OK) == 0) { + *new_icon = strdup(path); + return 0; + } + + snprintf(path, sizeof(path), "%s/%s%s", dir, dpi_str[1], file); + if (access(path, F_OK) == 0) { + *new_icon = strdup(path); + return 0; + } + + return -1; +} + +static gint __compare_icon_with_lang_dpi(gconstpointer a, gconstpointer b) +{ + icon_t *icon = (icon_t *)a; + struct cb_data_s *cb_data = (struct cb_data_s *)b; + + if (strcasecmp(icon->lang, cb_data->lang) == 0 && + __check_screen_dpi(icon->dpi, cb_data->dpi) == 0) + return 0; + + return -1; +} + +static gint __compare_icon_with_lang(gconstpointer a, gconstpointer b) +{ + icon_t *icon = (icon_t *)a; + struct cb_data_s *cb_data = (struct cb_data_s *)b; + char *new_icon = NULL; + + if (strcasecmp(icon->lang, cb_data->lang) == 0) { + if (strcmp(icon->lang, DEFAULT_LOCALE) == 0) { + __check_icon_resolution(cb_data->dpi, + icon->icon, &new_icon); + if (new_icon) { + free(icon->icon); + icon->icon = new_icon; + } + } + + return 0; + } + + return -1; +} + +static gint __compare_icon_with_dpi(gconstpointer a, gconstpointer b) +{ + icon_t *icon = (icon_t *)a; + struct cb_data_s *cb_data = (struct cb_data_s *)b; + + if (icon->lang && strcasecmp(icon->lang, DEFAULT_LOCALE) != 0) + return -1; + + if (icon->dpi == NULL) + return -1; + + if (__check_screen_dpi(icon->dpi, cb_data->dpi) == 0) + return 0; + + return -1; +} + +static gint __compare_icon_with_default_lang(gconstpointer a, gconstpointer b) +{ + icon_t *icon = (icon_t *)a; + struct cb_data_s *cb_data = (struct cb_data_s *)b; + char *new_icon = NULL; + + if (icon->lang && strcasecmp(icon->lang, DEFAULT_LOCALE) != 0) + return -1; + + if (icon->dpi != NULL) + return -1; + + __check_icon_resolution(cb_data->dpi, icon->icon, &new_icon); + if (new_icon) { + free(icon->icon); + icon->icon = new_icon; + } + + return 0; +} + +static void __foreach_label_lang(gpointer data, gpointer user_data) +{ + label_t *label = (label_t *)data; + GList **locales = (GList **)user_data; + + if (!label) + return; + + if (!label->lang) + return; + + *locales = g_list_insert_sorted_with_data(*locales, + (gpointer)label->lang, __compare_lang, NULL); +} + +static void __foreach_icon_lang(gpointer data, gpointer user_data) +{ + icon_t *icon = (icon_t *)data; + GList **locales = (GList **)user_data; + + if (!icon) + return; + + if (!icon->lang) + return; + + *locales = g_list_insert_sorted_with_data(*locales, + (gpointer)icon->lang, __compare_lang, NULL); +} + +static GList *__create_locale_list(GList *labels, GList *icons) +{ + const char *prev_locale = NULL; + const char *locale; + GList *locales = NULL; + GList *iter; + + g_list_foreach(labels, __foreach_label_lang, &locales); + g_list_foreach(icons, __foreach_icon_lang, &locales); + + iter = locales; + while (iter) { + locale = (const char *)iter->data; + iter = g_list_next(iter); + if (prev_locale) { + if (!strcmp(prev_locale, locale)) + locales = g_list_remove(locales, locale); + else + prev_locale = locale; + } else { + prev_locale = locale; + + } + } + + return locales; +} + +static const char *__find_label(GList *labels, const char *locale) +{ + label_t *label; + GList *found; + + found = g_list_find_custom(labels, locale, __compare_label_with_lang); + if (!found) + return NULL; + + label = (label_t *)found->data; + if (!label) + return NULL; + + return label->label; +} + +static const char *__find_icon(GList *icons, const char *locale) +{ + struct cb_data_s cb_data = { locale, -1}; + icon_t *icon; + GList *found; + int ret; + + ret = __load_system_info(); + if (ret < 0) + return NULL; + + ret = __system_info_get_platform_int(FEATURE_SCREEN_DPI, &cb_data.dpi); + if (ret != 0) + return NULL; + + /* Step 1 */ + found = g_list_find_custom(icons, &cb_data, + (GCompareFunc)__compare_icon_with_lang_dpi); + if (found) { + icon = (icon_t *)found->data; + return icon->icon; + } + + /* Step 2 */ + found = g_list_find_custom(icons, &cb_data, + (GCompareFunc)__compare_icon_with_lang); + if (found) { + icon = (icon_t *)found->data; + return icon->icon; + } + + /* Step 3 */ + found = g_list_find_custom(icons, &cb_data, + (GCompareFunc)__compare_icon_with_dpi); + if (found) { + icon = (icon_t *)found->data; + return icon->icon; + } + + /* Step 4 */ + found = g_list_find_custom(icons, &cb_data, + (GCompareFunc)__compare_icon_with_default_lang); + if (found) { + icon = (icon_t *)found->data; + return icon->icon; + } + + return NULL; +} + +static int __insert_component_localized_info(component_t *component, + GList *locales) +{ + static const char query[] = + "INSERT INTO component_localized_info " + "(component_id, component_locale, component_label, " + "component_icon) VALUES (?, ?, ?, ?)"; + sqlite3_stmt *stmt = NULL; + const char *locale; + const char *label; + const char *icon; + GList *iter; + int idx; + int ret; + + ret = sqlite3_prepare_v2(__db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + LOGE("sqlite3_prepare_v2() is failed. error(%s)", + sqlite3_errmsg(__db)); + return -1; + } + + iter = locales; + while (iter) { + locale = (const char *)iter->data; + iter = g_list_next(iter); + + label = __find_label(component->label, locale); + icon = __find_icon(component->icon, locale); + if (!label && !icon) + continue; + + idx = 1; + BIND_TEXT(__db, stmt, idx++, component->id); + BIND_TEXT(__db, stmt, idx++, locale); + BIND_TEXT(__db, stmt, idx++, label); + BIND_TEXT(__db, stmt, idx++, icon); + + ret = sqlite3_step(stmt); + if (ret != SQLITE_DONE) { + LOGE("sqlite3_step() is failed. error(%s)", + sqlite3_errmsg(__db)); + sqlite3_finalize(stmt); + return -1; + } + + sqlite3_reset(stmt); + } + + sqlite3_finalize(stmt); + + return 0; +} + +int component_plugin_parser_db_insert(component_t *component) +{ + static const char query[] = + "INSERT INTO component_info " + "(package, app_id, component_id, component_type, " + "component_launch_mode, component_main, " + "component_icon_display, component_taskmanage) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + sqlite3_stmt *stmt = NULL; + GList *locales = NULL; + int idx; + int ret; + + if (!component) { + LOGE("Invalid parameter"); + return -1; + } + + if (!__db) { + LOGE("Database is not prepared"); + return -1; + } + + ret = sqlite3_prepare_v2(__db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + LOGE("sqlite3_prepare_v2() is failed. error(%s)", + sqlite3_errmsg(__db)); + return -1; + } + + idx = 1; + BIND_TEXT(__db, stmt, idx++, component->package); + BIND_TEXT(__db, stmt, idx++, component->app_id); + BIND_TEXT(__db, stmt, idx++, component->id); + BIND_TEXT(__db, stmt, idx++, component->type); + BIND_TEXT(__db, stmt, idx++, component->launch_mode); + BIND_TEXT(__db, stmt, idx++, component->main); + BIND_TEXT(__db, stmt, idx++, component->icon_display); + BIND_TEXT(__db, stmt, idx++, component->taskmanage); + + ret = sqlite3_step(stmt); + if (ret != SQLITE_DONE) { + LOGE("sqlite3_step() is failed. error(%s)", + sqlite3_errmsg(__db)); + sqlite3_finalize(stmt); + return -1; + } + + locales = __create_locale_list(component->label, component->icon); + ret = __insert_component_localized_info(component, locales); + if (ret < 0) { + LOGE("Failed to insert component localized info"); + g_list_free(locales); + return -1; + } + g_list_free(locales); + + return 0; +} + +int component_plugin_parser_db_delete(const char *package) +{ + static const char query[] = + "DELETE FROM component_info WHERE package=?"; + sqlite3_stmt *stmt = NULL; + int ret; + + if (!package) { + LOGE("Invalid parameter"); + return -1; + } + + if (!__db) { + LOGE("Database is not prepared"); + return -1; + } + + ret = sqlite3_prepare_v2(__db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + LOGE("sqlite3_prepare_v2() is failed. error(%s)", + sqlite3_errmsg(__db)); + return -1; + } + + BIND_TEXT(__db, stmt, 1, package); + + ret = sqlite3_step(stmt); + if (ret != SQLITE_DONE) { + LOGE("sqlite3_step() is failed. error(%s)", + sqlite3_errmsg(__db)); + sqlite3_finalize(stmt); + return -1; + } + + sqlite3_finalize(stmt); + + return 0; +} + +int component_plugin_parser_db_begin_transaction(void) +{ + int ret; + + if (!__db) { + LOGE("Database is not prepared"); + return -1; + } + + ret = sqlite3_exec(__db, "BEGIN TRANSACTION", NULL, NULL, NULL); + if (ret != SQLITE_OK) { + LOGE("Transaction is failed. error(%s)", sqlite3_errmsg(__db)); + return -1; + } + + return 0; +} + +int component_plugin_parser_db_end_transaction(void) +{ + int ret; + + if (!__db) { + LOGE("Database is not prepared"); + return -1; + } + + ret = sqlite3_exec(__db, "END TRANSACTION", NULL, NULL, NULL); + if (ret != SQLITE_OK) { + LOGE("Transaction is failed. error(%s)", sqlite3_errmsg(__db)); + return -1; + } + + return 0; +} + +int component_plugin_parser_db_rollback(void) +{ + int ret; + + if (!__db) { + LOGE("Database is not prepared"); + return -1; + } + + ret = sqlite3_exec(__db, "ROLLBACK", NULL, NULL, NULL); + if (ret != SQLITE_OK) { + LOGE("Rollback is failed. error(%s)", sqlite3_errmsg(__db)); + return -1; + } + + return 0; +} + +int component_plugin_parser_db_init(void) +{ + const char *path; + uid_t target_uid; + int ret; + + target_uid = __get_target_uid(); + path = __get_db_path(target_uid); + if (!path) { + LOGE("Failed to get db path. uid(%u)", target_uid); + return -1; + } + + ret = access(path, F_OK); + if (ret != 0) { + LOGE("%s does not exists", path); + return -1; + } + + __db = __open_db(path); + if (!__db) { + LOGE("Failed to open db(%s)", path); + return -1; + } + + if (!__integrity_check(__db)) { + LOGE("Database(%s) is corrupted", path); + __close_db(__db); + __db = NULL; + return -1; + } + + return 0; +} + +int component_plugin_parser_db_fini(void) +{ + if (!__db) + return -1; + + __close_db(__db); + __db = NULL; + + return 0; +} diff --git a/parser/component/src/component_plugin_parser_handler.c b/parser/component/src/component_plugin_parser_handler.c new file mode 100644 index 0000000..4ece85d --- /dev/null +++ b/parser/component/src/component_plugin_parser_handler.c @@ -0,0 +1,887 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "component_plugin_parser_handler.h" +#include "component_plugin_parser_private.h" +#include "component_plugin_parser_type.h" +#include "component_plugin_parser_db.h" + +typedef enum { + COMPONENT_TYPE_NONE, + COMPONENT_TYPE_FRAME, + COMPONENT_TYPE_SERVICE, + COMPONENT_TYPE_MAX, +} component_type_e; + +typedef enum { + COMPONENT_ATTR_NONE, + COMPONENT_ATTR_ID, + COMPONENT_ATTR_LAUNCH_MODE, + COMPONENT_ATTR_MAIN, + COMPONENT_ATTR_ICON_DISPLAY, + COMPONENT_ATTR_TASKMANAGE, + COMPONENT_ATTR_MAX, +} component_attr_e; + +typedef enum { + COMPONENT_ELM_NONE, + COMPONENT_ELM_ICON, + COMPONENT_ELM_LABEL, + COMPONENT_ELM_MAX, +} component_elm_e; + +typedef enum { + COMPONENT_ICON_ATTR_NONE, + COMPONENT_ICON_ATTR_TEXT, + COMPONENT_ICON_ATTR_LANG, + COMPONENT_ICON_ATTR_DPI, + COMPONENT_ICON_ATTR_MAX, +} component_icon_attr_e; + +typedef enum { + COMPONENT_LABEL_ATTR_NONE, + COMPONENT_LABEL_ATTR_TEXT, + COMPONENT_LABEL_ATTR_LANG, + COMPONENT_LABEL_ATTR_MAX, +} component_label_attr_e; + +typedef struct { + uint32_t tag; + const char *name; +} tag_map_t; + +static tag_map_t __component_type_map[] = { + { COMPONENT_TYPE_FRAME, "frame-component" }, + { COMPONENT_TYPE_SERVICE, "service-component" }, +}; + +static const char *__component_type_string[] = { + [COMPONENT_TYPE_FRAME] = "frame", + [COMPONENT_TYPE_SERVICE] = "service", +}; + +static const char *__component_attr_string[] = { + [COMPONENT_ATTR_ID] = "id", + [COMPONENT_ATTR_LAUNCH_MODE] = "launch_mode", + [COMPONENT_ATTR_MAIN] = "main", + [COMPONENT_ATTR_ICON_DISPLAY] = "icon-display", + [COMPONENT_ATTR_TASKMANAGE] = "taskmanage", +}; + +static const char *__component_elm_string[] = { + [COMPONENT_ELM_ICON] = "icon", + [COMPONENT_ELM_LABEL] = "label", +}; + +static const char *__component_icon_attr_string[] = { + [COMPONENT_ICON_ATTR_TEXT] = "#text", + [COMPONENT_ICON_ATTR_LANG] = "lang", + [COMPONENT_ICON_ATTR_DPI] = "dpi", +}; + +static const char *__component_label_attr_string[] = { + [COMPONENT_LABEL_ATTR_TEXT] = "#text", + [COMPONENT_LABEL_ATTR_LANG] = "lang", +}; + +typedef int (*component_plugin_parser_func)(xmlNode *node, void *data); + +static uint32_t __get_component_type_tag(const char *name) +{ + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(__component_type_map); i++) { + if (!strcmp(__component_type_map[i].name, name)) + return __component_type_map[i].tag; + } + + return 0; +} + +static bool __is_service_component(const char *type) +{ + if (!strcmp(type, __component_type_string[COMPONENT_TYPE_SERVICE])) + return true; + + return false; +} + +static bool __is_boolean(const char *value) +{ + if (!strcmp(value, "true") || !strcmp(value, "false")) + return true; + + return false; +} + +static char *__get_attribute(xmlNode *node, const char *name) +{ + xmlChar *val; + char *attr = NULL; + + val = xmlGetProp(node, (const xmlChar *)name); + if (val) { + attr = strdup((char *)val); + xmlFree(val); + } + + return attr; +} + +static char *__get_language(xmlNode *node) +{ + xmlChar *val; + char *lang = NULL; + + val = xmlNodeGetLang(node); + if (val) { + lang = strdup((char *)val); + xmlFree(val); + } + + return lang; +} + +static const char *__get_name(xmlNode *node) +{ + if (!node) + return NULL; + + return (const char *)node->name; +} + +static void __destroy_label(gpointer data) +{ + label_t *info = (label_t *)data; + + if (!info) + return; + + if (info->label) + free(info->label); + if (info->lang) + free(info->lang); + free(info); +} + +static void __destroy_icon(gpointer data) +{ + icon_t *info = (icon_t *)data; + + if (!info) + return; + + if (info->icon) + free(info->icon); + if (info->lang) + free(info->lang); + if (info->dpi) + free(info->dpi); + free(info); +} + +static void __destroy_component(gpointer data) +{ + component_t *info = (component_t *)data; + + if (!info) + return; + + if (info->package) + free(info->package); + if (info->app_id) + free(info->app_id); + if (info->id) + free(info->id); + if (info->launch_mode) + free(info->launch_mode); + if (info->main) + free(info->main); + if (info->icon_display) + free(info->icon_display); + if (info->taskmanage) + free(info->taskmanage); + if (info->icon) + g_list_free_full(info->icon, __destroy_icon); + if (info->label) + g_list_free_full(info->label, __destroy_label); + free(info); +} + +static component_t *__create_component(const char *package, const char *app_id, + const char *type) +{ + component_t *info; + + info = calloc(1, sizeof(component_t)); + if (!info) { + LOGE("Out of memory"); + return NULL; + } + + info->package = strdup(package); + if (!info->package) { + LOGE("Failed to duplicate package"); + free(info); + return NULL; + } + + info->app_id = strdup(app_id); + if (!info->app_id) { + LOGE("Failed to duplicate app_id"); + __destroy_component(info); + return NULL; + } + + info->type = strdup(type); + if (!info->type) { + LOGE("Failed to duplicate type"); + __destroy_component(info); + return NULL; + } + + return info; +} + +static int __component_label_attr_text(xmlNode *node, void *data) +{ + label_t *info = (label_t *)data; + + info->label = strdup((const char *)node->children->content); + if (!info->label) { + LOGE("Failed to duplicate label"); + return -1; + } + + return 0; +} + +static int __component_label_attr_lang(xmlNode *node, void *data) +{ + label_t *info = (label_t *)data; + char *lang; + + lang = __get_language(node); + if (!lang) { + info->lang = strdup(DEFAULT_LOCALE); + if (!info->lang) { + LOGE("Out of memory"); + return -1; + } + } else { + info->lang = lang; + } + + return 0; +} + +static component_plugin_parser_func __label_attr_table[] = { + [COMPONENT_LABEL_ATTR_TEXT] = __component_label_attr_text, + [COMPONENT_LABEL_ATTR_LANG] = __component_label_attr_lang, +}; + +static int __component_icon_attr_text(xmlNode *node, void *data) +{ + icon_t *info = (icon_t *)data; + + info->icon = strdup((const char *)node->children->content); + if (!info->icon) { + LOGE("Failed to duplicate icon"); + return -1; + } + + return 0; +} + +static int __component_icon_attr_lang(xmlNode *node, void *data) +{ + icon_t *info = (icon_t *)data; + char *lang; + + lang = __get_language(node); + if (!lang) { + info->lang = strdup(DEFAULT_LOCALE); + if (!info->lang) { + LOGE("Out of memory"); + return -1; + } + } else { + info->lang = lang; + } + + return 0; +} + +static int __component_icon_attr_dpi(xmlNode *node, void *data) +{ + icon_t *info = (icon_t *)data; + const char *key; + + key = __component_icon_attr_string[COMPONENT_ICON_ATTR_DPI]; + info->dpi = __get_attribute(node, key); + + return 0; +} + +static component_plugin_parser_func __icon_attr_table[] = { + [COMPONENT_ICON_ATTR_TEXT] = __component_icon_attr_text, + [COMPONENT_ICON_ATTR_LANG] = __component_icon_attr_lang, + [COMPONENT_ICON_ATTR_DPI] = __component_icon_attr_dpi, +}; + +static int __component_elm_icon(xmlNode *node, void *data) +{ + component_t *info = (component_t *)data; + const char *key = __component_elm_string[COMPONENT_ELM_ICON]; + icon_t *icon; + uint32_t i; + int ret; + + if (strcmp(__get_name(node), key) != 0) + return 0; + + if (!node->children || !node->children->content) + return 0; + + icon = calloc(1, sizeof(icon_t)); + if (!icon) { + LOGE("Out of memory"); + return -1; + } + + for (i = 0; i < ARRAY_SIZE(__icon_attr_table); i++) { + if (!__icon_attr_table[i]) + continue; + + ret = __icon_attr_table[i](node, icon); + if (ret < 0) { + LOGE("Failed to parse icon attribute %s", + __component_icon_attr_string[i]); + __destroy_icon(icon); + return -1; + } + } + + info->icon = g_list_append(info->icon, icon); + + return 0; +} + +static int __component_elm_label(xmlNode *node, void *data) +{ + component_t *info = (component_t *)data; + const char *key = __component_elm_string[COMPONENT_ELM_LABEL]; + label_t *label; + uint32_t i; + int ret; + + if (strcmp(__get_name(node), key) != 0) + return 0; + + if (!node->children || !node->children->content) + return 0; + + label = calloc(1, sizeof(label_t)); + if (!label) { + LOGE("Out of memory"); + return -1; + } + + for (i = 0; i < ARRAY_SIZE(__label_attr_table); i++) { + if (!__label_attr_table[i]) + continue; + + ret = __label_attr_table[i](node, label); + if (ret < 0) { + LOGE("Failed to parse label attribute %s", + __component_label_attr_string[i]); + __destroy_label(label); + return -1; + } + } + + info->label = g_list_append(info->label, label); + + return 0; +} + +static component_plugin_parser_func __elm_table[] = { + [COMPONENT_ELM_ICON] = __component_elm_icon, + [COMPONENT_ELM_LABEL] = __component_elm_label, +}; + +/** + * @brief Parses the elements of the component. + */ +static int __parse_component_element(xmlNode *node, component_t *component) +{ + uint32_t i; + int ret; + + for (i = 0; i < ARRAY_SIZE(__elm_table); i++) { + if (!__elm_table[i]) + continue; + + ret = __elm_table[i](node, component); + if (ret < 0) { + LOGE("Failed to parse element %s", + __component_elm_string[i]); + return -1; + } + } + + return 0; +} + +static int __component_attr_id(xmlNode *node, void *data) +{ + component_t *info = (component_t *)data; + const char *key = __component_attr_string[COMPONENT_ATTR_ID]; + char *value; + + value = __get_attribute(node, key); + if (!value) { + LOGE("Failed to get id attribute"); + return -1; + } + + info->id = value; + + return 0; +} + +static int __component_attr_launch_mode(xmlNode *node, void *data) +{ + component_t *info = (component_t *)data; + const char *key = __component_attr_string[COMPONENT_ATTR_LAUNCH_MODE]; + char *value; + + if (__is_service_component(info->type)) { + info->launch_mode = strdup("single"); + if (!info->launch_mode) { + LOGE("Failed to duplicate launch mode"); + return -1; + } + + return 0; + } + + value = __get_attribute(node, key); + if (!value) { + info->launch_mode = strdup("single"); + if (!info->launch_mode) { + LOGE("Failed to duplicate launch mode"); + return -1; + } + + return 0; + } + + if (strcmp(value, "single") != 0 && + strcmp(value, "caller") != 0 && + strcmp(value, "group") != 0) { + LOGE("launch_mode should be 'single' or 'caller' or group'"); + free(value); + return -1; + } + + info->launch_mode = value; + + return 0; +} + +static int __component_attr_main(xmlNode *node, void *data) +{ + component_t *info = (component_t *)data; + const char *key = __component_attr_string[COMPONENT_ATTR_MAIN]; + char *value; + + value = __get_attribute(node, key); + if (!value) { + info->main = strdup("true"); + if (!info->launch_mode) { + LOGE("Failed to duplicate main"); + return -1; + } + + return 0; + } + + if (!__is_boolean(value)) { + LOGE("main should be 'true' or 'false'"); + free(value); + return -1; + } + + info->main = value; + + return 0; +} + +static int __component_attr_icon_display(xmlNode *node, void *data) +{ + component_t *info = (component_t *)data; + const char *key = __component_attr_string[COMPONENT_ATTR_ICON_DISPLAY]; + char *value; + + if (__is_service_component(info->type)) { + info->icon_display = strdup("false"); + if (!info->icon_display) { + LOGE("Failed to duplicate icon display"); + return -1; + } + + return 0; + } + + value = __get_attribute(node, key); + if (!value) { + info->icon_display = strdup("true"); + if (!info->icon_display) { + LOGE("Failed to duplicate icon display"); + return -1; + } + + return 0; + } + + if (!__is_boolean(value)) { + LOGE("icon-display should be 'true' or 'false'"); + free(value); + return -1; + } + + info->icon_display = value; + + return 0; +} + +static int __component_attr_taskmanage(xmlNode *node, void *data) +{ + component_t *info = (component_t *)data; + const char *key = __component_attr_string[COMPONENT_ATTR_TASKMANAGE]; + char *value; + + if (__is_service_component(info->type)) { + info->taskmanage = strdup("false"); + if (!info->taskmanage) { + LOGE("Failed to duplicate taskmanage"); + return -1; + } + + return 0; + } + + value = __get_attribute(node, key); + if (!value) { + info->taskmanage = strdup("true"); + if (!info->taskmanage) { + LOGE("Failed to duplicate taskmanage"); + return -1; + } + + return 0; + } + + if (!__is_boolean(value)) { + LOGE("taskmanage should be 'true' or 'false'"); + free(value); + return -1; + } + + info->taskmanage = value; + + return 0; +} + +static component_plugin_parser_func __attr_table[] = { + [COMPONENT_ATTR_ID] = __component_attr_id, + [COMPONENT_ATTR_LAUNCH_MODE] = __component_attr_launch_mode, + [COMPONENT_ATTR_MAIN] = __component_attr_main, + [COMPONENT_ATTR_ICON_DISPLAY] = __component_attr_icon_display, + [COMPONENT_ATTR_TASKMANAGE] = __component_attr_taskmanage, +}; + +/** + * @brief Parses the attributes of the component. + */ +static int __parse_component_attribute(xmlNode *node, component_t *component) +{ + uint32_t i; + int ret; + + for (i = 0; i < ARRAY_SIZE(__attr_table); i++) { + if (!__attr_table[i]) + continue; + + ret = __attr_table[i](node, component); + if (ret < 0) { + LOGE("Failed to parse attribute %s", + __component_attr_string[i]); + return -1; + } + } + + return 0; +} + +static int __parse_component(const char *package, const char *app_id, + xmlNode *node, component_t **component) +{ + component_t *info = NULL; + xmlNode *iter; + const char *type; + uint32_t tag; + int ret; + + tag = __get_component_type_tag(__get_name(node)); + if (tag == COMPONENT_TYPE_NONE || tag >= COMPONENT_TYPE_MAX) + return 0; + + type = __component_type_string[tag]; + info = __create_component(package, app_id, type); + if (!info) + return -1; + + ret = __parse_component_attribute(node, info); + if (ret < 0) { + __destroy_component(info); + return -1; + } + + for (iter = node->children; iter; iter = iter->next) { + if (!iter->name) + continue; + + ret = __parse_component_element(iter, info); + if (ret < 0) { + __destroy_component(info); + return -1; + } + } + + *component = info; + + return 0; +} + +/** + * @brief Parses component-based-application + * + * Structure of tizen-manifest.xml for xml elements: + * + * \_ + * \_