Add package dependency attribute 34/197434/10
authorSangyoon Jang <jeremy.jang@samsung.com>
Thu, 3 Jan 2019 04:57:09 +0000 (13:57 +0900)
committerSangyoon Jang <jeremy.jang@samsung.com>
Mon, 21 Jan 2019 11:58:18 +0000 (20:58 +0900)
Change-Id: I5cd2dc375e7ff4e070ce9f4292c0368a7ed16a4f
Signed-off-by: Sangyoon Jang <jeremy.jang@samsung.com>
include/pkgmgr-info.h
include/pkgmgrinfo_basic.h
include/pkgmgrinfo_type.h
parser/src/pkgmgr_parser_db.c
parser/src/pkgmgr_parser_db_queries.h
src/pkgmgrinfo_basic.c
src/pkgmgrinfo_pkginfo.c

index 1b5c965..89f2ed6 100644 (file)
@@ -6225,6 +6225,102 @@ int pkgmgrinfo_compare_package_version(const char *current_version,
                const char *target_version, pkgmgrinfo_version_compare_type *res);
 
 /**
+ * @fn int pkgmgrinfo_pkginfo_foreach_dependency(pkgmgrinfo_pkginfo_h handle,
+                       pkgmgrinfo_pkg_dependency_list_cb dependency_cb,
+                       void *user_data);
+ * @brief      This API gets the list of dependency of 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]  dependency_cb           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 dependency_cb(const char *pkgid, const char *type,
+               const char *required_version,void *user_data)
+{
+       printf("this package %s %s", type, pkgid);
+       if (required_version)
+               printf("required version : %s", required_version);
+       return 0;
+}
+
+static int list_dependency(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_dependency(handle, dependency_cb, 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_dependency(pkgmgrinfo_pkginfo_h handle,
+               pkgmgrinfo_pkg_dependency_list_cb dependency_cb,
+               void *user_data);
+
+/**
+ * @fn int pkgmgrinfo_pkginfo_foreach_required_by(pkgmgrinfo_pkginfo_h handle,
+                       pkgmgrinfo_pkg_dependency_list_cb dependency_cb,
+                       void *user_data);
+ * @brief      This API gets the list of packages which has dependency of 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]  dependency_cb           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 dependency_cb(const char *pkgid, const char *type,
+               const char *required_version,void *user_data)
+{
+       printf("%s %s this package", pkgid, type);
+       if (required_version)
+               printf("required version : %s", required_version);
+       return 0;
+}
+
+static int list_required_by(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_required_by(handle, dependency_cb, 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_required_by(pkgmgrinfo_pkginfo_h handle,
+               pkgmgrinfo_pkg_dependency_list_cb dependency_cb,
+               void *user_data);
+
+/**
  * @brief      TEMP
  */
 
index b7bb44e..87b6109 100644 (file)
@@ -120,6 +120,12 @@ typedef struct appdefined_privilege_x {
        char *license;
 } appdefined_privilege_x;
 
+typedef struct dependency_x {
+       char *depends_on;
+       char *type;
+       char *required_version;
+} dependency_x;
+
 typedef struct application_x {
        char *appid;    /*attr*/
        char *exec;     /*attr*/
@@ -226,6 +232,7 @@ typedef struct package_x {
        GList *application;             /**< package's application, element*/
        GList *compatibility;           /**< package compatibility, element*/
        GList *deviceprofile;           /**< package device profile, element*/
+       GList *dependencies;            /**< package dependencies, element*/
 } package_x;
 
 typedef struct updateinfo_x {
index f4e49a3..283878c 100644 (file)
@@ -111,7 +111,8 @@ typedef enum {
        PMINFO_PKGINFO_GET_DESCRIPTION = 0x0010,
        PMINFO_PKGINFO_GET_PRIVILEGE = 0x0020,
        PMINFO_PKGINFO_GET_APPDEFINED_PRIVILEGE = 0x0040,
-       PMINFO_PKGINFO_GET_ALL = 0x007F
+       PMINFO_PKGINFO_GET_DEPENDENCY = 0x0080,
+       PMINFO_PKGINFO_GET_ALL = 0x00FF
 } pkgmgrinfo_pkginfo_get_option;
 
 /**
@@ -322,6 +323,24 @@ typedef int (*pkgmgrinfo_pkg_privilege_list_cb) (const char *privilege_name,
 typedef int (*pkgmgrinfo_pkg_appdefined_privilege_list_cb) (const char *privilege_name,
                                                        const char *license_path,
                                                        void *user_data);
+/**
+ * @fn int (*pkgmgrinfo_pkg_dependency_list_cb) (const char *pkgid, const char *type, const char *required_version, void *user_data)
+ *
+ * @brief Specifies the dependency info of given package passed to pkgmgrinfo_pkginfo_foreach_dependency() or pkgmgrinfo_pkginfo_foreach_required_by()
+ *
+ * @param[in] pkgid the pkgid which has dependency with given package
+ * @param[in] type type of dependency
+ * @param[in] required_version required version of dependency
+ * @param[in] user_data user data passed
+ *
+ * @return 0 if success, negative value(<0) if fail. Callback is not called if return value is negative.\n
+ *
+ * @see  pkgmgrinfo_pkginfo_foreach_dependency()
+ * @see  pkgmgrinfo_pkginfo_foreach_required_by()
+ */
+typedef int (*pkgmgrinfo_pkg_dependency_list_cb) (const char *pkgid,
+               const char *type, const char *required_version,
+               void *user_data);
 
 /**
  * @fn int (*pkgmgrinfo_app_metadata_list_cb) (const char *metadata_key, const char *metadata_value, void *user_data)
index b663211..e065349 100644 (file)
@@ -329,6 +329,7 @@ static const char *parser_init_queries[] = {
        QUERY_CREATE_TABLE_PACKAGE_APP_INFO_FOR_UID,
        QUERY_CREATE_TRIGGER_UPDATE_PACKAGE_APP_INFO_FOR_UID,
        QUERY_CREATE_TABLE_PACKAGE_APP_SPLASH_SCREEN,
+       QUERY_CREATE_TABLE_PACKAGE_DEPENDENCY_INFO,
        NULL,
 };
 
@@ -1748,6 +1749,49 @@ static int __insert_package_appdefined_privilege_info(sqlite3 *db,
        return 0;
 }
 
+static int __insert_package_dependency_info(sqlite3 *db, manifest_x *mfx)
+{
+       static const char query[] =
+               "INSERT INTO package_dependency_info"
+               "  (package, depends_on, type, required_version) "
+               "VALUES (?, ?, ?, ?)";
+       int ret;
+       sqlite3_stmt *stmt;
+       int idx;
+       GList *tmp;
+       dependency_x *dep;
+
+       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->dependencies; tmp; tmp = tmp->next) {
+               dep = (dependency_x *)tmp->data;
+               if (dep == NULL)
+                       continue;
+
+               idx = 1;
+               __BIND_TEXT(db, stmt, idx++, mfx->package);
+               __BIND_TEXT(db, stmt, idx++, dep->depends_on);
+               __BIND_TEXT(db, stmt, idx++, dep->type);
+               __BIND_TEXT(db, stmt, idx++, dep->required_version);
+
+               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;
+}
+
 /* _PRODUCT_LAUNCHING_ENHANCED_
  *  app->indicatordisplay, app->portraitimg, app->landscapeimg,
  *  app->guestmode_appstatus
@@ -2091,6 +2135,8 @@ static int __insert_package_info(sqlite3 *db, manifest_x *mfx)
                return -1;
        if (__insert_package_appdefined_privilege_info(db, mfx))
                return -1;
+       if (__insert_package_dependency_info(db, mfx))
+               return -1;
 
        return 0;
 }
index 282918b..69ba61e 100644 (file)
        "  FOREIGN KEY(app_id)\n" \
        "  REFERENCES package_app_info(app_id) ON DELETE CASCADE)"
 
+#define QUERY_CREATE_TABLE_PACKAGE_DEPENDENCY_INFO \
+       "CREATE TABLE IF NOT EXISTS package_dependency_info (\n" \
+       "  package TEXT NOT NULL,\n" \
+       "  depends_on TEXT NOT NULL,\n" \
+       "  type TEXT NOT NULL,\n" \
+       "  required_version TEXT,\n" \
+       "  PRIMARY KEY(package, depends_on),\n" \
+       "  FOREIGN KEY(package)\n" \
+       "  REFERENCES package_info(package) ON DELETE CASCADE)"
+
 /* 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 c5c95a8..7f0f30c 100644 (file)
@@ -260,6 +260,20 @@ static void __ps_free_datacontrol(gpointer data)
        free((void *)datacontrol);
 }
 
+static void __ps_free_dependency(gpointer data)
+{
+       dependency_x *dependency = (dependency_x *)data;
+       if (dependency == NULL)
+               return;
+       if (dependency->depends_on)
+               free((void *)dependency->depends_on);
+       if (dependency->type)
+               free((void *)dependency->type);
+       if (dependency->required_version)
+               free((void *)dependency->required_version);
+       free((void *)dependency);
+}
+
 static void __ps_free_application(gpointer data)
 {
        application_x *application = (application_x *)data;
@@ -485,6 +499,8 @@ API void pkgmgrinfo_basic_free_package(package_x *package)
        g_list_free_full(package->compatibility, __ps_free_compatibility);
        /*Free Device profiles*/
        g_list_free_full(package->deviceprofile, free);
+       /*Free Dependencies*/
+       g_list_free_full(package->dependencies, __ps_free_dependency);
        free((void *)package);
 }
 
index dc8981b..d800064 100644 (file)
@@ -263,6 +263,41 @@ static int _pkginfo_get_appdefined_privilege(sqlite3 *db, const char *pkgid,
        return PMINFO_R_OK;
 }
 
+static int _pkginfo_get_dependency(sqlite3 *db, const char *pkgid,
+               GList **dependencies)
+{
+       static const char query[] =
+               "SELECT DISTINCT depends_on, type, required_version "
+               "FROM package_dependency_info WHERE package=?";
+       int ret;
+       sqlite3_stmt *stmt;
+       dependency_x *dependency;
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               LOGE("prepare failed: %s", sqlite3_errmsg(db));
+               return PMINFO_R_ERROR;
+       }
+
+       while (sqlite3_step(stmt) == SQLITE_ROW) {
+               dependency = calloc(1, sizeof(dependency_x));
+               if (!dependency) {
+                       LOGE("failed to alloc memory");
+                       sqlite3_finalize(stmt);
+                       return PMINFO_R_ERROR;
+               }
+               _save_column_str(stmt, 0, &dependency->depends_on);
+               _save_column_str(stmt, 1, &dependency->type);
+               _save_column_str(stmt, 2, &dependency->required_version);
+               *dependencies = g_list_append(*dependencies,
+                               (gpointer)dependency);
+       }
+
+       sqlite3_finalize(stmt);
+
+       return PMINFO_R_OK;
+}
+
 static const char join_localized_info[] =
        " LEFT OUTER JOIN package_localized_info"
        "  ON pi.package=package_localized_info.package"
@@ -579,6 +614,14 @@ static int _pkginfo_get_packages(uid_t uid, const char *locale,
                        }
                }
 
+               if (flag & PMINFO_PKGINFO_GET_DEPENDENCY) {
+                       if (_pkginfo_get_dependency(db, info->package,
+                                               &info->dependencies)) {
+                               ret = PMINFO_R_ERROR;
+                               goto catch;
+                       }
+               }
+
                if (is_check_storage &&
                                __pkginfo_check_installed_storage(info) != PMINFO_R_OK) {
                        ret = PMINFO_R_ERROR;
@@ -2013,6 +2056,190 @@ API int pkgmgrinfo_pkginfo_foreach_appdefined_privilege(
        return PMINFO_R_OK;
 }
 
+API int pkgmgrinfo_pkginfo_foreach_dependency(pkgmgrinfo_pkginfo_h handle,
+               pkgmgrinfo_pkg_dependency_list_cb dependency_cb,
+               void *user_data)
+{
+       int ret;
+       pkgmgr_pkginfo_x *info = (pkgmgr_pkginfo_x *)handle;
+       GList *tmp;
+       dependency_x *dependency;
+
+       if (handle == NULL || dependency_cb == NULL) {
+               LOGE("invalid parameter");
+               return PMINFO_R_EINVAL;
+       }
+
+       if (info->pkg_info == NULL)
+               return PMINFO_R_ERROR;
+
+       for (tmp = info->pkg_info->dependencies; tmp; tmp = tmp->next) {
+               dependency = (dependency_x *)tmp->data;
+               if (dependency == NULL)
+                       continue;
+               ret = dependency_cb(dependency->depends_on, dependency->type,
+                               dependency->required_version, user_data);
+               if (ret < 0)
+                       break;
+       }
+
+       return PMINFO_R_OK;
+}
+
+struct required_by {
+       char *pkgid;
+       char *type;
+       char *version;
+};
+
+static int _get_required_by(sqlite3 *db, const char *pkgid, GQueue **queue,
+               GHashTable **table, GList **pkg_list)
+{
+       static const char query[] =
+               "SELECT package, type, required_version "
+               "FROM package_dependency_info WHERE depends_on=?";
+       int ret;
+       sqlite3_stmt *stmt;
+       struct required_by *req;
+
+       /* already checked */
+       if (!g_hash_table_insert(*table, strdup(pkgid), GINT_TO_POINTER(1)))
+               return PMINFO_R_OK;
+
+       ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               LOGE("prepare failed: %s", sqlite3_errmsg(db));
+               return PMINFO_R_ERROR;
+       }
+
+       ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_STATIC);
+       if (ret != SQLITE_OK) {
+               LOGE("bind failed: %s", sqlite3_errmsg(db));
+               sqlite3_finalize(stmt);
+               return PMINFO_R_ERROR;
+       }
+
+       while (sqlite3_step(stmt) == SQLITE_ROW) {
+               req = calloc(1, sizeof(struct required_by));
+               if (req == NULL) {
+                       LOGE("out of memory");
+                       sqlite3_finalize(stmt);
+                       return PMINFO_R_ERROR;
+               }
+               _save_column_str(stmt, 0, &req->pkgid);
+               _save_column_str(stmt, 1, &req->type);
+               _save_column_str(stmt, 2, &req->version);
+
+               *pkg_list = g_list_append(*pkg_list, req);
+               g_queue_push_tail(*queue, strdup(req->pkgid));
+       }
+
+       sqlite3_finalize(stmt);
+
+       return PMINFO_R_OK;
+}
+
+static int _pkginfo_foreach_required_by(uid_t uid, const char *pkgid,
+               GList **pkg_list)
+{
+       int ret;
+       char *dbpath;
+       sqlite3 *db;
+       GQueue *queue;
+       GHashTable *table;
+       char *item;
+
+       dbpath = getUserPkgParserDBPathUID(uid);
+       if (dbpath == NULL)
+               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);
+
+       queue = g_queue_new();
+       if (queue == NULL) {
+               LOGE("out of memory");
+               sqlite3_close_v2(db);
+               return PMINFO_R_ERROR;
+       }
+
+       table = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
+
+       g_queue_push_tail(queue, strdup(pkgid));
+       while (!g_queue_is_empty(queue)) {
+               item = g_queue_pop_head(queue);
+               ret = _get_required_by(db, item, &queue, &table, pkg_list);
+               free(item);
+               if (ret != PMINFO_R_OK) {
+                       LOGE("failed to get required by pkgs");
+                       g_hash_table_destroy(table);
+                       g_queue_free_full(queue, free);
+                       sqlite3_close_v2(db);
+                       return PMINFO_R_ERROR;
+               }
+       }
+
+       g_hash_table_destroy(table);
+       g_queue_free_full(queue, free);
+       sqlite3_close_v2(db);
+
+       return PMINFO_R_OK;
+}
+
+static void __free_required_by(gpointer data)
+{
+       struct required_by *req = (struct required_by *)data;
+
+       free(req->pkgid);
+       free(req->type);
+       free(req->version);
+       free(req);
+}
+
+API int pkgmgrinfo_pkginfo_foreach_required_by(pkgmgrinfo_pkginfo_h handle,
+               pkgmgrinfo_pkg_dependency_list_cb dependency_cb,
+               void *user_data)
+{
+       int ret;
+       pkgmgr_pkginfo_x *info = (pkgmgr_pkginfo_x *)handle;
+       GList *pkg_list = NULL;
+       GList *l;
+       struct required_by *req;
+
+       if (handle == NULL || dependency_cb == NULL || info->pkg_info == NULL) {
+               LOGE("invalid parameter");
+               return PMINFO_R_EINVAL;
+       }
+
+       ret = _pkginfo_foreach_required_by(info->uid, info->pkg_info->package,
+                       &pkg_list);
+       if (ret == PMINFO_R_OK && info->uid != GLOBAL_USER)
+               ret = _pkginfo_foreach_required_by(GLOBAL_USER,
+                               info->pkg_info->package, &pkg_list);
+
+       if (ret != PMINFO_R_OK) {
+               g_list_free_full(pkg_list, __free_required_by);
+               return ret;
+       }
+
+       for (l = pkg_list; l != NULL; l = l->next) {
+               req = (struct required_by *)l->data;
+               ret = dependency_cb(req->pkgid, req->type, req->version,
+                               user_data);
+               if (ret < 0)
+                       break;
+       }
+
+       g_list_free_full(pkg_list, __free_required_by);
+
+       return PMINFO_R_OK;
+}
+
 int __compare_package_version(const char *version, int *major,
                int *minor, int *macro, int *nano)
 {