Implement pkgmgr plugin execution info 20/195920/16
authorJunghyun Yeon <jungh.yeon@samsung.com>
Thu, 13 Dec 2018 10:10:17 +0000 (19:10 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Fri, 8 Mar 2019 02:41:55 +0000 (02:41 +0000)
Change-Id: I091818b5e368542a5e44d6a61d58ef6cd5d9dee0
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
include/pkgmgr-info.h
include/pkgmgrinfo_basic.h
include/pkgmgrinfo_type.h
parser/include/pkgmgr_parser_db.h
parser/src/pkgmgr_parser_db.c
parser/src/pkgmgr_parser_db_queries.h
src/pkgmgrinfo_basic.c
src/pkgmgrinfo_pkginfo.c
src/pkgmgrinfo_plugininfo.c [new file with mode: 0644]

index 89f2ed6..9ba8de8 100644 (file)
@@ -1354,6 +1354,71 @@ int pkgmgrinfo_updateinfo_foreach_updateinfo(pkgmgrinfo_foreach_updateinfo_cb ca
 int pkgmgrinfo_updateinfo_usr_foreach_updateinfo(uid_t uid, pkgmgrinfo_foreach_updateinfo_cb callback, void *user_data);
 
 /**
+ * @fn int pkgmgrinfo_plugininfo_is_executed(const char *pkgid, const char *appid, const char *plugin_type, const char *plugin_name, bool *is_executed);
+ * @brief      This API checkes whether given plugin had been executed with given package ID and application ID or not.
+ *
+ * @par                This API is for package-manager client application
+ * @par Sync (or) Async : Synchronous API
+ *
+ * @param[in]  pkgid   package ID
+ * @param[in]  appid   application ID
+ * @param[in]  plugin_type     plugin type to be checked
+ * @param[in]  plugin_name     plugin name to be checked
+ * @param[out] is_executed     check result
+ * @return     0 if success, error code(<0) if fail
+ * @retval     PMINFO_R_OK     success
+ * @retval     PMINFO_R_EINVAL invalid argument
+ * @retval     PMINFO_R_ERROR  internal error
+ * @code
+static bool check_execute_info(const char *pkgid, const char *appid, const char *plugin_type, const char *plugin_name)
+{
+       int ret = 0;
+       bool is_executed;
+
+       ret = pkgmgrinfo_plugininfo_is_executed(pkgid, appid, plugin_type, plugin_name, &is_executed);
+       if (ret != PMINFO_R_OK)
+               return -1;
+       printf("is checked is [%d]\n", is_executed);
+       return 0;
+}
+ * @endcode
+ */
+int pkgmgrinfo_plugininfo_is_executed(const char *pkgid, const char *appid,
+               const char *plugin_type, const char *plugin_name, bool *is_executed);
+
+/**
+ * @fn int pkgmgrinfo_plugininfo_foreach_plugininfo(const char *pkgid, const char *plugin_type, const char *plugin_name, pkgmgrinfo_plugin_list_cb plugin_list_cb, void *user_data);
+ * @brief      This API retrieve the previous plugin execution info and invoke callbacks each of it.
+ *
+ * @par                This API is for package-manager client application
+ * @par Sync (or) Async : Synchronous API
+ *
+ * @param[in]  pkgid                   package ID
+ * @param[in]  plugin_type             type of plugin
+ * @param[in]  plugin_name             name of plugin
+ * @param[in]  plugin_list_cb  callback to be invoked for each plugin execution info
+ * @param[out] user_data               user data to be passed to callback
+ * @return     0 if success, error code(<0) if fail
+ * @retval     PMINFO_R_OK     success
+ * @retval     PMINFO_R_EINVAL invalid argument
+ * @retval     PMINFO_R_ERROR  internal error
+ * @code
+static int foreach_pkg_plugininfo(const char *pkgid, const char *plugin_type, const char *plugin_name, pkgmgrinfo_plugin_list_cb callback)
+{
+       int ret = 0;
+
+       ret = pkgmgrinfo_plugininfo_foreach_plugininfo(pkgid, plugin_type, plugin_name, callback, NULL);
+       if (ret != PMINFO_R_OK)
+               return -1;
+       return 0;
+}
+ * @endcode
+ */
+int pkgmgrinfo_plugininfo_foreach_plugininfo(const char *pkgid,
+               const char *plugin_type, const char *plugin_name,
+               pkgmgrinfo_plugin_list_cb plugin_list_cb, void *user_data);
+
+/**
  * @fn int pkgmgrinfo_appinfo_get_launch_mode(pkgmgrinfo_appinfo_h handle, char **mode)
  * @brief      This API gets the launch mode of package from the package ID
  *
@@ -2487,6 +2552,52 @@ static int list_appdefined_privilege(const char *package)
 int pkgmgrinfo_pkginfo_foreach_appdefined_privilege(pkgmgrinfo_pkginfo_h handle,
                        pkgmgrinfo_pkg_appdefined_privilege_list_cb privilege_func, void *user_data);
 
+/**
+ * @fn int pkgmgrinfo_pkginfo_foreach_plugin(pkgmgrinfo_pkginfo_h handle,
+                       pkgmgrinfo_plugin_list_cb plugin_func, void *user_data);
+ * @brief      This API gets the list of plugin execution info for a particular package
+ *
+ * @par                This API is for package-manager client application
+ * @par Sync (or) Async : Synchronous API
+ * @param[in]  handle          pointer to the package info handle.
+ * @param[in]  plugin_func             callback function for list
+ * @param[in] user_data        user data to be passed to callback function
+ * @return     0 if success, error code(<0) if fail
+ * @retval     PMINFO_R_OK     success
+ * @retval     PMINFO_R_EINVAL invalid argument
+ * @retval     PMINFO_R_ERROR  internal error
+ * @pre                pkgmgrinfo_pkginfo_get_pkginfo()
+ * @post               pkgmgrinfo_pkginfo_destroy_pkginfo()
+ * @code
+int plugin_func(const char *pkgid, const char *appid,
+                               const char *plugin_type, const char *plugin_name,
+                               void *user_data)
+{
+       printf("appid : %s, type : %s, name : %s\n", appid, plugin_type, plugin_name);
+
+       return 0;
+}
+
+static int list_plugin(const char *package)
+{
+       int ret = 0;
+       pkgmgrinfo_pkginfo_h handle;
+       ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
+       if (ret != PMINFO_R_OK)
+               return -1;
+       ret = pkgmgrinfo_pkginfo_foreach_plugin(handle, plugin_func, NULL);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+               return -1;
+       }
+       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+       return 0;
+}
+ * @endcode
+ */
+int pkgmgrinfo_pkginfo_foreach_plugin(pkgmgrinfo_pkginfo_h handle,
+                       pkgmgrinfo_plugin_list_cb plugin_func, void *user_data);
+
 /* TODO: add doxygen comment here */
 int pkgmgrinfo_pkginfo_is_for_all_users(pkgmgrinfo_pkginfo_h handle, bool *for_all_users);
 
index 87b6109..974d9b8 100644 (file)
@@ -91,6 +91,13 @@ typedef struct compatibility_x {
        char *text;
 } compatibility_x;
 
+typedef struct plugin_x {
+       char *pkgid;
+       char *appid;
+       char *plugin_type;
+       char *plugin_name;
+} plugin_x;
+
 typedef struct datacontrol_x {
        char *providerid;
        char *access;
@@ -233,6 +240,7 @@ typedef struct package_x {
        GList *compatibility;           /**< package compatibility, element*/
        GList *deviceprofile;           /**< package device profile, element*/
        GList *dependencies;            /**< package dependencies, element*/
+       GList *plugin;          /**< plugin execution list, no xml part*/
 } package_x;
 
 typedef struct updateinfo_x {
index 283878c..870d376 100644 (file)
@@ -343,6 +343,25 @@ typedef int (*pkgmgrinfo_pkg_dependency_list_cb) (const char *pkgid,
                void *user_data);
 
 /**
+ * @fn int (*pkgmgrinfo_plugin_list_cb) (const char *pkgid, const char *appid, const char *plugin_type, const char *plugin_name, void *user_data);
+ *
+ * @brief Specifies the type of function passed to pkgmgrinfo_plugininfo_foreach_plugininfo()
+ *
+ * @param[in] pkgid the name of the package
+ * @param[in] appid the name of the application
+ * @param[in] plugin_type the type of the executed plugin
+ * @param[in] plugin_name the name of the executed plugin
+ * @param[in] user_data user data passed to pkgmgrinfo_plugininfo_foreach_plugininfo()
+ *
+ * @return 0 if success, negative value(<0) if fail. Callback is not called if return value is negative.\n
+ *
+ * @see  pkgmgrinfo_plugininfo_foreach_plugininfo()
+ */
+typedef int (*pkgmgrinfo_plugin_list_cb) (const char *pkgid, const char *appid,
+               const char *plugin_type, const char *plugin_name,
+               void *user_data);
+
+/**
  * @fn int (*pkgmgrinfo_app_metadata_list_cb) (const char *metadata_key, const char *metadata_value, void *user_data)
  *
  * @brief Specifies the type of function passed to pkgmgrinfo_appinfo_foreach_metadata()
index 0e91f62..2e84101 100644 (file)
@@ -503,6 +503,81 @@ static int unregister_all_pkg_update_info(void)
  */
 int pkgmgr_parser_unregister_all_pkg_update_info_in_db(void);
 
+/**
+ * @fn int pkgmgr_parser_register_pkg_plugin_info_in_usr_db(manifest_x *mfx, uid_t uid)
+ * @brief      This API registers package plugin execution information
+ *
+ * @par                This API is only for internal usage
+ * @par Sync (or) Async : Synchronous API
+ *
+ * @param[in]  mfx     manifest structure pointer which contains plugin execution info
+ * @return     0 if success, error code(<0) if fail
+ * @pre None
+ * @post        None
+ * @code
+static int register_pkg_plugin_info(manifest_x *mfx)
+{
+       int ret = 0;
+       ret = pkgmgr_parser_register_pkg_plugin_info_in_db(mfx);
+       if (ret < 0)
+               return -1;
+       return 0;
+}
+ * @endcode
+ */
+int pkgmgr_parser_register_pkg_plugin_info_in_db(manifest_x *mfx);
+int pkgmgr_parser_register_pkg_plugin_info_in_usr_db(manifest_x *mfx, uid_t uid);
+
+/**
+ * @fn int pkgmgr_parser_update_pkg_plugin_info_in_usr_db(manifest_x *mfx, uid_t uid)
+ * @brief      This API updates package plugin execution information
+ *
+ * @par                This API is only for internal usage
+ * @par Sync (or) Async : Synchronous API
+ *
+ * @param[in]  mfx     manifest structure pointer which contains plugin execution info
+ * @return     0 if success, error code(<0) if fail
+ * @pre None
+ * @post        None
+ * @code
+static int update_pkg_plugin_info(manifest_x *mfx)
+{
+       int ret = 0;
+       ret = pkgmgr_parser_update_pkg_plugin_info_in_db(mfx);
+       if (ret < 0)
+               return -1;
+       return 0;
+}
+ * @endcode
+ */
+int pkgmgr_parser_update_pkg_plugin_info_in_db(manifest_x *mfx);
+int pkgmgr_parser_update_pkg_plugin_info_in_usr_db(manifest_x *mfx, uid_t uid);
+
+/**
+ * @fn int pkgmgr_parser_unregister_pkg_plugin_info_in_usr_db(const char *pkgid, uid_t uid)
+ * @brief      This API unregisters package plugin execution information
+ *
+ * @par                This API is only for internal usage
+ * @par Sync (or) Async : Synchronous API
+ *
+ * @param[in]  pkgid   package ID
+ * @return     0 if success, error code(<0) if fail
+ * @pre None
+ * @post        None
+ * @code
+static int unregister_pkg_plugin_info(const char *pkgid)
+{
+       int ret = 0;
+       ret = pkgmgr_parser_unregister_pkg_plugin_info_in_db(pkgid);
+       if (ret < 0)
+               return -1;
+       return 0;
+}
+ * @endcode
+ */
+int pkgmgr_parser_unregister_pkg_plugin_info_in_db(const char *pkgid);
+int pkgmgr_parser_unregister_pkg_plugin_info_in_usr_db(const char *pkgid, uid_t uid);
+
 int pkgmgr_parser_create_and_initialize_db(uid_t uid);
 int pkgmgr_parser_initialize_parser_db(uid_t uid);
 int pkgmgr_parser_initialize_cert_db(void);
index 8f4c854..b6db523 100644 (file)
@@ -330,6 +330,7 @@ static const char *parser_init_queries[] = {
        QUERY_CREATE_TRIGGER_UPDATE_PACKAGE_APP_INFO_FOR_UID,
        QUERY_CREATE_TABLE_PACKAGE_APP_SPLASH_SCREEN,
        QUERY_CREATE_TABLE_PACKAGE_DEPENDENCY_INFO,
+       QUERY_CREATE_TABLE_PACKAGE_PLUGIN_INFO,
        NULL,
 };
 
@@ -1713,6 +1714,81 @@ static int __insert_package_privilege_info(sqlite3 *db, manifest_x *mfx)
        return 0;
 }
 
+static int __insert_package_plugin_execution_info(sqlite3 *db,
+               manifest_x *mfx)
+{
+       static const char query[] =
+               "INSERT INTO package_plugin_info "
+               "(pkgid, appid, plugin_type, plugin_name) "
+               "VALUES (?, ?, ?, ?)";
+       int ret;
+       sqlite3_stmt *stmt;
+       int idx;
+       GList *tmp;
+       plugin_x *plugin;
+
+       if (!mfx->plugin)
+               return 0;
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               _LOGE("prepare failed: %s", sqlite3_errmsg(db));
+               return -1;
+       }
+
+       for (tmp = mfx->plugin; tmp; tmp = tmp->next) {
+               plugin = (plugin_x *)tmp->data;
+               if (plugin == NULL)
+                       continue;
+
+               idx = 1;
+               __BIND_TEXT(db, stmt, idx++, plugin->pkgid);
+               __BIND_TEXT(db, stmt, idx++, plugin->appid);
+               __BIND_TEXT(db, stmt, idx++, plugin->plugin_type);
+               __BIND_TEXT(db, stmt, idx++, plugin->plugin_name);
+
+               ret = sqlite3_step(stmt);
+               if (ret != SQLITE_DONE) {
+                       _LOGE("step failed: %s", sqlite3_errmsg(db));
+                       sqlite3_finalize(stmt);
+                       return -1;
+               }
+               sqlite3_reset(stmt);
+       }
+
+       sqlite3_finalize(stmt);
+
+       return 0;
+}
+
+static int __delete_package_plugin_execution_info(sqlite3 *db,
+               const char *pkgid)
+{
+       static const char query[] =
+               "DELETE FROM package_plugin_info WHERE pkgid=?";
+       int ret;
+       sqlite3_stmt *stmt;
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               _LOGE("prepare failed: %s", sqlite3_errmsg(db));
+               return -1;
+       }
+
+       __BIND_TEXT(db, stmt, 1, pkgid);
+
+       ret = sqlite3_step(stmt);
+       if (ret != SQLITE_DONE) {
+               _LOGE("step failed: %s", sqlite3_errmsg(db));
+               sqlite3_finalize(stmt);
+               return -1;
+       }
+
+       sqlite3_finalize(stmt);
+
+       return 0;
+}
+
 static int __insert_package_appdefined_privilege_info(sqlite3 *db,
                manifest_x *mfx)
 {
@@ -3067,3 +3143,92 @@ API int pkgmgr_parser_unregister_all_pkg_update_info_in_db(void)
        return pkgmgr_parser_unregister_all_pkg_update_info_in_usr_db(
                        __getuid());
 }
+
+API int pkgmgr_parser_register_pkg_plugin_info_in_usr_db(
+               manifest_x *mfx, uid_t uid)
+{
+       int ret;
+       const char *dbpath;
+       sqlite3 *db;
+
+       if (!mfx)
+               return PM_PARSER_R_EINVAL;
+       dbpath = __get_parser_db_path(uid);
+       ret = __open_db(uid, dbpath, &db, SQLITE_OPEN_READWRITE);
+       if (ret != SQLITE_OK) {
+               _LOGE("open db failed: %d", ret);
+               return PM_PARSER_R_ERROR;
+       }
+
+       __BEGIN_TRANSACTION(db);
+       __DO_TRANSACTION(db, __insert_package_plugin_execution_info(db, mfx));
+       __END_TRANSACTION(db);
+
+       sqlite3_close_v2(db);
+
+       return PM_PARSER_R_OK;
+}
+
+API int pkgmgr_parser_register_pkg_plugin_info_in_db(manifest_x *mfx)
+{
+       return pkgmgr_parser_register_pkg_plugin_info_in_usr_db(mfx, __getuid());
+}
+
+API int pkgmgr_parser_update_pkg_plugin_info_in_usr_db(
+               manifest_x *mfx, uid_t uid)
+{
+       int ret;
+       const char *dbpath;
+       sqlite3 *db;
+
+       if (!mfx)
+               return PM_PARSER_R_EINVAL;
+       dbpath = __get_parser_db_path(uid);
+       ret = __open_db(uid, dbpath, &db, SQLITE_OPEN_READWRITE);
+       if (ret != SQLITE_OK) {
+               _LOGE("open db failed: %d", ret);
+               return PM_PARSER_R_ERROR;
+       }
+
+       __BEGIN_TRANSACTION(db);
+       __DO_TRANSACTION(db, __delete_package_plugin_execution_info(db, mfx->package));
+       __DO_TRANSACTION(db, __insert_package_plugin_execution_info(db, mfx));
+       __END_TRANSACTION(db);
+
+       sqlite3_close_v2(db);
+
+       return PM_PARSER_R_OK;
+}
+
+API int pkgmgr_parser_update_pkg_plugin_info_in_db(manifest_x *mfx)
+{
+       return pkgmgr_parser_update_pkg_plugin_info_in_usr_db(mfx, __getuid());
+}
+
+API int pkgmgr_parser_unregister_pkg_plugin_info_in_usr_db(
+               const char *pkgid, uid_t uid)
+{
+       int ret;
+       const char *dbpath;
+       sqlite3 *db;
+
+       dbpath = __get_parser_db_path(uid);
+       ret = __open_db(uid, dbpath, &db, SQLITE_OPEN_READWRITE);
+       if (ret != SQLITE_OK) {
+               _LOGE("open db failed: %d", ret);
+               return PM_PARSER_R_ERROR;
+       }
+
+       __BEGIN_TRANSACTION(db);
+       __DO_TRANSACTION(db, __delete_package_plugin_execution_info(db, pkgid));
+       __END_TRANSACTION(db);
+
+       sqlite3_close_v2(db);
+
+       return PM_PARSER_R_OK;
+}
+
+API int pkgmgr_parser_unregister_pkg_plugin_info_in_db(const char *pkgid)
+{
+       return pkgmgr_parser_unregister_pkg_plugin_info_in_usr_db(pkgid, __getuid());
+}
\ No newline at end of file
index 69ba61e..d444f4c 100644 (file)
        "  FOREIGN KEY(package)\n" \
        "  REFERENCES package_info(package) ON DELETE CASCADE)"
 
+#define QUERY_CREATE_TABLE_PACKAGE_PLUGIN_INFO \
+       "CREATE TABLE IF NOT EXISTS package_plugin_info (\n" \
+       "  pkgid TEXT NOT NULL,\n" \
+       "  appid TEXT,\n" \
+       "  plugin_type TEXT NOT NULL,\n" \
+       "  plugin_name TEXT NOT NULL)"
+
 /* FIXME: duplicated at pkgmgrinfo_db.c */
 #define QUERY_CREATE_TABLE_PACKAGE_CERT_INDEX_INFO \
        "CREATE TABLE IF NOT EXISTS package_cert_index_info (\n" \
index 7f0f30c..381c0ac 100644 (file)
@@ -85,6 +85,22 @@ static void __ps_free_compatibility(gpointer data)
        free((void *)compatibility);
 }
 
+static void __ps_free_plugin_info(gpointer data)
+{
+       plugin_x *plugin = (plugin_x *)data;
+       if (plugin == NULL)
+               return;
+       if (plugin->pkgid)
+               free((void *)plugin->pkgid);
+       if (plugin->appid)
+               free((void *)plugin->appid);
+       if (plugin->plugin_type)
+               free((void *)plugin->plugin_type);
+       if (plugin->plugin_name)
+               free((void *)plugin->plugin_name);
+       free((void *)plugin);
+}
+
 static void __ps_free_appcontrol(gpointer data)
 {
        appcontrol_x *appcontrol = (appcontrol_x *)data;
@@ -501,6 +517,8 @@ API void pkgmgrinfo_basic_free_package(package_x *package)
        g_list_free_full(package->deviceprofile, free);
        /*Free Dependencies*/
        g_list_free_full(package->dependencies, __ps_free_dependency);
+       /*Free Plugin execution history*/
+       g_list_free_full(package->plugin, __ps_free_plugin_info);
        free((void *)package);
 }
 
index d800064..d7a6a52 100644 (file)
@@ -181,6 +181,51 @@ static int _pkginfo_add_description_info_into_list(const char *locale,
        return PMINFO_R_OK;
 }
 
+static int _pkginfo_get_plugin_execution_info(sqlite3 *db, const char *pkgid,
+               GList **plugins)
+{
+       static const char query_raw[] =
+               "SELECT appid, plugin_type, plugin_name FROM package_plugin_info "
+               "WHERE pkgid=%Q";
+       int ret;
+       char *query;
+       sqlite3_stmt *stmt;
+       plugin_x *plugin;
+
+       query = sqlite3_mprintf(query_raw, pkgid);
+       if (query == NULL) {
+               LOGE("out of memory");
+               return PMINFO_R_ERROR;
+       }
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query),
+                       &stmt, NULL);
+       sqlite3_free(query);
+       if (ret != SQLITE_OK) {
+               LOGE("prepare failed: %s", sqlite3_errmsg(db));
+               return PMINFO_R_ERROR;
+       }
+
+       while (sqlite3_step(stmt) == SQLITE_ROW) {
+               plugin = calloc(1, sizeof(plugin_x));
+               if (!plugin) {
+                       LOGE("out of memory");
+                       sqlite3_finalize(stmt);
+                       return PMINFO_R_ERROR;
+               }
+               plugin->pkgid = strdup(pkgid);
+               _save_column_str(stmt, 0, &plugin->appid);
+               _save_column_str(stmt, 1, &plugin->plugin_type);
+               _save_column_str(stmt, 2, &plugin->plugin_name);
+               *plugins = g_list_append(*plugins,
+                               (gpointer)plugin);
+       }
+
+       sqlite3_finalize(stmt);
+
+       return PMINFO_R_OK;
+}
+
 static int _pkginfo_get_privilege(sqlite3 *db, const char *pkgid,
                GList **privileges)
 {
@@ -556,6 +601,11 @@ static int _pkginfo_get_packages(uid_t uid, const char *locale,
                info->for_all_users =
                        strdup((uid != global_user_uid) ? "false" : "true");
 
+               if (_pkginfo_get_plugin_execution_info(db, info->package, &info->plugin)) {
+                       ret = PMINFO_R_ERROR;
+                       goto catch;
+               }
+
                if (flag & PMINFO_PKGINFO_GET_AUTHOR) {
                        /* TODO : author should be retrieved at package_localized_info */
                        author = calloc(1, sizeof(author_x));
@@ -2027,6 +2077,33 @@ API int pkgmgrinfo_pkginfo_foreach_privilege(pkgmgrinfo_pkginfo_h handle,
        return PMINFO_R_OK;
 }
 
+API int pkgmgrinfo_pkginfo_foreach_plugin(pkgmgrinfo_pkginfo_h handle,
+                       pkgmgrinfo_plugin_list_cb plugin_func, void *user_data)
+{
+       retvm_if(handle == NULL, PMINFO_R_EINVAL, "pkginfo handle is NULL");
+       retvm_if(plugin_func == NULL, PMINFO_R_EINVAL,
+                       "Callback function is NULL");
+       int ret;
+       plugin_x *plugin;
+       GList *tmp;
+       pkgmgr_pkginfo_x *info = (pkgmgr_pkginfo_x *)handle;
+
+       if (info->pkg_info == NULL)
+               return PMINFO_R_ERROR;
+
+       for (tmp = info->pkg_info->plugin; tmp; tmp = tmp->next) {
+               plugin = (plugin_x *)tmp->data;
+               if (plugin == NULL)
+                       continue;
+               ret = plugin_func(plugin->pkgid, plugin->appid,
+                               plugin->plugin_type, plugin->plugin_name, user_data);
+               if (ret < 0)
+                       return PMINFO_R_OK;
+       }
+
+       return PMINFO_R_OK;
+}
+
 API int pkgmgrinfo_pkginfo_foreach_appdefined_privilege(
                pkgmgrinfo_pkginfo_h handle,
                pkgmgrinfo_pkg_appdefined_privilege_list_cb privilege_func,
diff --git a/src/pkgmgrinfo_plugininfo.c b/src/pkgmgrinfo_plugininfo.c
new file mode 100644 (file)
index 0000000..01ff505
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * pkgmgr-info
+ *
+ * Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Junghyun Yeon <jungh.yeon@samsung.com>, Sangyoon Jang <jeremy.jang@samsung.com>
+ *
+ * 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 <stdlib.h>
+#include <stdbool.h>
+#include <sqlite3.h>
+
+#include "pkgmgrinfo_private.h"
+#include "pkgmgrinfo_debug.h"
+#include "pkgmgr-info.h"
+
+static void _free_plugin(gpointer data)
+{
+       plugin_x *plugin = (plugin_x *)data;
+       if (plugin == NULL)
+               return;
+       if (plugin->appid)
+               free((void *)plugin->appid);
+       free((void *)plugin);
+}
+
+API int pkgmgrinfo_plugininfo_foreach_plugininfo(const char *pkgid,
+               const char *plugin_type, const char *plugin_name,
+               pkgmgrinfo_plugin_list_cb plugin_list_cb, void *user_data)
+{
+       int ret;
+       int idx = 0;
+       char *dbpath;
+       const char *appid;
+       sqlite3 *db;
+       sqlite3_stmt *stmt = NULL;
+       plugin_x *plugin;
+       GList *plugin_list = NULL;
+       GList *tmp_list;
+
+       static const char query[] =
+                       "SELECT appid FROM "
+                       "package_plugin_info WHERE pkgid=? AND "
+                       "plugin_type=? AND plugin_name=?";
+
+       if (!pkgid || !plugin_type || !plugin_name || !plugin_list_cb) {
+               _LOGE("Invalid parameter");
+               return PMINFO_R_EINVAL;
+       }
+
+       dbpath = getUserPkgParserDBPathUID(_getuid());
+       if (dbpath == NULL) {
+               _LOGE("Failed to get db path");
+               return PMINFO_R_ERROR;
+       }
+
+       ret = __open_db(dbpath, &db, SQLITE_OPEN_READONLY);
+       if (ret != SQLITE_OK) {
+               _LOGD("failed to open db(%s): %d", dbpath, ret);
+               free(dbpath);
+               return PMINFO_R_ERROR;
+       }
+       free(dbpath);
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               LOGE("prepare failed: %s", sqlite3_errmsg(db));
+               ret = PMINFO_R_ERROR;
+               goto catch;
+       }
+
+       ret = sqlite3_bind_text(stmt, ++idx, pkgid, -1, SQLITE_STATIC);
+       if (ret != SQLITE_OK) {
+               ret = PMINFO_R_ERROR;
+               goto catch;
+       }
+
+       ret = sqlite3_bind_text(stmt, ++idx, plugin_type, -1, SQLITE_STATIC);
+       if (ret != SQLITE_OK) {
+               ret = PMINFO_R_ERROR;
+               goto catch;
+       }
+       ret = sqlite3_bind_text(stmt, ++idx, plugin_name, -1, SQLITE_STATIC);
+       if (ret != SQLITE_OK) {
+               ret = PMINFO_R_ERROR;
+               goto catch;
+       }
+
+       while (sqlite3_step(stmt) == SQLITE_ROW) {
+               plugin = calloc(1, sizeof(plugin_x));
+               if (plugin == NULL)  {
+                       _LOGE("out of memory");
+                       ret = PMINFO_R_ERROR;
+                       goto catch;
+               }
+               idx = 0;
+               appid = (const char *)sqlite3_column_text(stmt, idx++);
+               if (appid) {
+                       plugin->appid = strdup(appid);
+               }
+               plugin_list = g_list_append(plugin_list, plugin);
+       }
+
+       for (tmp_list = plugin_list; tmp_list != NULL; tmp_list = tmp_list->next) {
+               plugin = (plugin_x *)tmp_list->data;
+               if (!plugin)
+                       continue;
+               ret = plugin_list_cb(pkgid, plugin->appid, plugin_type,
+                                                        plugin_name, user_data);
+               if (ret != 0)
+                       break;
+       }
+       g_list_free_full(plugin_list, _free_plugin);
+
+catch:
+       sqlite3_finalize(stmt);
+       sqlite3_close_v2(db);
+
+       return ret;
+
+}
\ No newline at end of file