From 65094c403adc5f30def16209a1e57554b1838d29 Mon Sep 17 00:00:00 2001 From: Sangyoon Jang Date: Wed, 11 Jan 2023 10:14:42 +0900 Subject: [PATCH] Add metadata to pkginfo Now metadata is available at package level. Change-Id: Ic3f561fdb427d2482b1c3945366e6c26d7fe3976 Signed-off-by: Sangyoon Jang --- include/pkgmgr-info.h | 252 +++++++++++++++++++++++++++++- include/pkgmgrinfo_basic.h | 1 + include/pkgmgrinfo_type.h | 24 ++- parser/include/pkgmgr_parser_db_queries.h | 11 ++ src/common/parcel/filter_parcelable.cc | 10 ++ src/common/parcel/pkginfo_parcelable.cc | 27 ++++ src/common/parcel/pkginfo_parcelable.hh | 2 + src/pkgmgrinfo_basic.c | 2 + src/pkgmgrinfo_pkginfo.c | 102 ++++++++++++ src/pkgmgrinfo_private.c | 20 +++ src/pkgmgrinfo_private.h | 3 + src/server/database/db_handle_provider.cc | 83 ++++++---- src/server/pkginfo_internal.cc | 91 ++++++++++- 13 files changed, 593 insertions(+), 35 deletions(-) diff --git a/include/pkgmgr-info.h b/include/pkgmgr-info.h index 134af64..9a856d6 100644 --- a/include/pkgmgr-info.h +++ b/include/pkgmgr-info.h @@ -2708,6 +2708,257 @@ static int list_plugin(const char *package) int pkgmgrinfo_pkginfo_foreach_plugin(pkgmgrinfo_pkginfo_h handle, pkgmgrinfo_plugin_list_cb plugin_func, void *user_data); +/** + * @fn int pkgmgrinfo_pkginfo_foreach_metadata(pkgmgrinfo_pkginfo_h handle, + pkgmgrinfo_pkg_metadata_list_cb metadata_func, void *user_data); + * @brief This API gets the list of metadata 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] metadata_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 metadata_func(const char *key, const char *value, void *user_data) +{ + if (strcmp(key, (char *)user_data) == 0) { + printf("Value is %s\n", value); + return -1; + } + else + return 0; +} + +static int list_metadata(const char *pkgid, char *key) +{ + int ret = 0; + pkgmgrinfo_pkginfo_h handle; + ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &handle); + if (ret != PMINFO_R_OK) + return -1; + ret = pkgmgrinfo_pkginfo_foreach_metadata(handle, metadata_func, (void *)key); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_destroy_pkginfo(handle); + return -1; + } + pkgmgrinfo_pkginfo_destroy_pkginfo(handle); + return 0; +} + * @endcode + */ +int pkgmgrinfo_pkginfo_foreach_metadata(pkgmgrinfo_pkginfo_h handle, + pkgmgrinfo_pkg_metadata_list_cb metadata_func, void *user_data); + +/** + * @fn int pkgmgrinfo_pkginfo_metadata_filter_create(pkgmgrinfo_pkginfo_metadata_filter_h *handle) + * @brief This API creates the application's metadata information filter handle from db. + * + * @par This API is for package-manager client application + * @par Sync (or) Async : Synchronous API + * + * @param[out] handle pointer to the package metadata info filter handle. + * @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 None + * @post pkgmgrinfo_pkginfo_metadata_filter_destroy() + * @see pkgmgrinfo_pkginfo_metadata_filter_foreach() + * @code +int pkg_list_cb(pkgmgrinfo_pkginfo_h handle, void *user_data) +{ + char *pkgid = NULL; + pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid); + printf("pkgid : %s\n", pkgid); + return 0; +} + +static int get_pkg_list(const char *mkey, const char *mvalue) +{ + int ret = 0; + pkgmgrinfo_pkginfo_metadata_filter_h handle; + ret = pkgmgrinfo_pkginfo_metadata_filter_create(&handle); + if (ret != PMINFO_R_OK) + return -1; + ret = pkgmgrinfo_pkginfo_metadata_filter_add(handle, mkey, mvalue); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return -1; + } + ret = pkgmgrinfo_pkginfo_metadata_filter_foreach(handle, pkg_list_cb, NULL); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return -1; + } + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return 0; +} + * @endcode + */ +int pkgmgrinfo_pkginfo_metadata_filter_create(pkgmgrinfo_pkginfo_metadata_filter_h *handle); + +/** + * @fn int pkgmgrinfo_pkginfo_metadata_filter_destroy(pkgmgrinfo_pkginfo_metadata_filter_h handle) + * @brief This API destroys the package's metadata information filter handle. + * + * @par This API is for package-manager client application + * @par Sync (or) Async : Synchronous API + * + * @param[in] handle pointer to the package metadata info filter handle. + * @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_metadata_filter_create() + * @post None + * @see pkgmgrinfo_pkginfo_metadata_filter_foreach() + * @code +int pkg_list_cb(pkgmgrinfo_pkginfo_h handle, void *user_data) +{ + char *pkgid = NULL; + pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid); + printf("pkgid : %s\n", pkgid); + return 0; +} + +static int get_pkg_list(const char *mkey, const char *mvalue) +{ + int ret = 0; + pkgmgrinfo_pkginfo_metadata_filter_h handle; + ret = pkgmgrinfo_pkginfo_metadata_filter_create(&handle); + if (ret != PMINFO_R_OK) + return -1; + ret = pkgmgrinfo_pkginfo_metadata_filter_add(handle, mkey, mvalue); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return -1; + } + ret = pkgmgrinfo_pkginfo_metadata_filter_foreach(handle, pkg_list_cb, NULL); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return -1; + } + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return 0; +} + * @endcode + */ +int pkgmgrinfo_pkginfo_metadata_filter_destroy(pkgmgrinfo_pkginfo_metadata_filter_h handle); + +/** + * @fn int pkgmgrinfo_pkginfo_metadata_filter_add(pkgmgrinfo_pkginfo_metadata_filter_h handle, const char *key, const char *value) + * @brief This API adds filter condition for the query API. The query will search the entire package metadata information collected from + * the manifest file of all the installed packages. You can specify value as NULL to search based on key only. + * + * @par This API is for package-manager client application + * @par Sync (or) Async : Synchronous API + * + * @param[in] handle pointer to the package metadata info filter handle. + * @param[in] key pointer to metadata key + * @param[in] value pointer to metadata value + * @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_metadata_filter_create() + * @post pkgmgrinfo_pkginfo_metadata_filter_foreach(), pkgmgrinfo_pkginfo_metadata_filter_destroy() + * @see pkgmgrinfo_pkginfo_metadata_filter_foreach() + * @code +int pkg_list_cb(pkgmgrinfo_pkginfo_h handle, void *user_data) +{ + char *pkgid = NULL; + pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid); + printf("pkgid : %s\n", pkgid); + return 0; +} + +static int get_pkg_list(const char *mkey, const char *mvalue) +{ + int ret = 0; + pkgmgrinfo_pkginfo_metadata_filter_h handle; + ret = pkgmgrinfo_pkginfo_metadata_filter_create(&handle); + if (ret != PMINFO_R_OK) + return -1; + ret = pkgmgrinfo_pkginfo_metadata_filter_add(handle, mkey, mvalue); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return -1; + } + ret = pkgmgrinfo_pkginfo_metadata_filter_foreach(handle, pkg_list_cb, NULL); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return -1; + } + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return 0; +} + * @endcode + */ +int pkgmgrinfo_pkginfo_metadata_filter_add(pkgmgrinfo_pkginfo_metadata_filter_h handle, + const char *key, const char *value); + +/** + * @fn int pkgmgrinfo_pkginfo_metadata_filter_foreach(pkgmgrinfo_pkginfo_metadata_filter_h handle, pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data) + * @fn int pkgmgrinfo_pkginfo_usr_metadata_filter_foreach(pkgmgrinfo_pkginfo_metadata_filter_h handle, pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data, uid_t uid) + * @brief This API executes the filter query. The query will search the entire package metadata information collected from + * the manifest file of all the installed packages. For each package returned by the query, the callback will be called. If callback returns + * negative value, no more callbacks will be called and API will return. + * + * @par This API is for package-manager client application + * @par Sync (or) Async : Synchronous API + * + * @param[in] handle pointer to the package metadata info filter handle. + * @param[in] app_cb function pointer to callback + * @param[in] user_data pointer to user data + * @param[in] uid the addressee user id of the instruction + * @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_metadata_filter_create() + * @post pkgmgrinfo_pkginfo_metadata_filter_destroy() + * @code +int pkg_list_cb(pkgmgrinfo_pkginfo_h handle, void *user_data) +{ + char *pkgid = NULL; + pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid); + printf("pkgid : %s\n", pkgid); + return 0; +} + +static int get_pkg_list(const char *mkey, const char *mvalue) +{ + int ret = 0; + pkgmgrinfo_pkginfo_metadata_filter_h handle; + ret = pkgmgrinfo_pkginfo_metadata_filter_create(&handle); + if (ret != PMINFO_R_OK) + return -1; + ret = pkgmgrinfo_pkginfo_metadata_filter_add(handle, mkey, mvalue); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return -1; + } + ret = pkgmgrinfo_pkginfo_metadata_filter_foreach(handle, pkg_list_cb, NULL); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return -1; + } + pkgmgrinfo_pkginfo_metadata_filter_destroy(handle); + return 0; +} + * @endcode + */ +int pkgmgrinfo_pkginfo_metadata_filter_foreach(pkgmgrinfo_pkginfo_metadata_filter_h handle, + pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data); +int pkgmgrinfo_pkginfo_usr_metadata_filter_foreach(pkgmgrinfo_pkginfo_metadata_filter_h handle, + pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data, uid_t uid); + /* TODO: add doxygen comment here */ int pkgmgrinfo_pkginfo_is_for_all_users(pkgmgrinfo_pkginfo_h handle, bool *for_all_users); @@ -6950,4 +7201,3 @@ int pkgmgrinfo_archiveinfo_foreach_dependency(pkgmgrinfo_archiveinfo_h handle, * @} * @} */ - diff --git a/include/pkgmgrinfo_basic.h b/include/pkgmgrinfo_basic.h index c89f31a..d75c33f 100644 --- a/include/pkgmgrinfo_basic.h +++ b/include/pkgmgrinfo_basic.h @@ -259,6 +259,7 @@ typedef struct package_x { GList *dependencies; /**< package dependencies, element*/ GList *plugin; /**< plugin execution list, no xml part*/ GList *res_allowed_packages; /**< res allowed packages, element*/ + GList *metadata; /*element*/ } package_x; typedef struct updateinfo_x { diff --git a/include/pkgmgrinfo_type.h b/include/pkgmgrinfo_type.h index 2fe0274..7f83f16 100644 --- a/include/pkgmgrinfo_type.h +++ b/include/pkgmgrinfo_type.h @@ -114,7 +114,8 @@ typedef enum { PMINFO_PKGINFO_GET_APPDEFINED_PRIVILEGE = 0x0040, PMINFO_PKGINFO_GET_DEPENDENCY = 0x0080, PMINFO_PKGINFO_GET_RES_INFO = 0x0100, - PMINFO_PKGINFO_GET_ALL = 0x01FF + PMINFO_PKGINFO_GET_METADATA = 0x0200, + PMINFO_PKGINFO_GET_ALL = 0x03FF } pkgmgrinfo_pkginfo_get_option; /** @@ -202,6 +203,11 @@ typedef void *pkgmgrinfo_certinfo_h; typedef void *pkgmgrinfo_pkginfo_filter_h; /** + * @brief A handle to filter package metadata information + */ +typedef void *pkgmgrinfo_pkginfo_metadata_filter_h; + +/** * @brief A handle to get/set package update information */ typedef void *pkgmgrinfo_updateinfo_h; @@ -346,6 +352,22 @@ typedef int (*pkgmgrinfo_pkg_dependency_list_cb) (const char *from, const char * void *user_data); /** + * @fn int (*pkgmgrinfo_pkg_metadata_list_cb) (const char *metadata_key, const char *metadata_value, void *user_data) + * + * @brief Specifies the type of function passed to pkgmgrinfo_pkginfo_foreach_metadata() + * + * @param[in] metadata_name the name of the metadata + * @param[in] metadata_value the value of the metadata + * @param[in] user_data user data passed to pkgmgrinfo_pkginfo_foreach_metadata() + * + * @return 0 if success, negative value(<0) if fail. Callback is not called if return value is negative.\n + * + * @see pkgmgrinfo_pkginfo_foreach_metadata() + */ +typedef int (*pkgmgrinfo_pkg_metadata_list_cb) (const char *metadata_key, + const char *metadata_value, 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() diff --git a/parser/include/pkgmgr_parser_db_queries.h b/parser/include/pkgmgr_parser_db_queries.h index 6e9e738..2cbbdde 100644 --- a/parser/include/pkgmgr_parser_db_queries.h +++ b/parser/include/pkgmgr_parser_db_queries.h @@ -288,6 +288,15 @@ " FOREIGN KEY(package)\n" \ " REFERENCES package_info(package) ON DELETE CASCADE)" +#define QUERY_CREATE_TABLE_PACKAGE_METADATA \ + "CREATE TABLE IF NOT EXISTS package_metadata (\n" \ + " package TEXT NOT NULL,\n" \ + " md_key TEXT NOT NULL,\n" \ + " md_value TEXT,\n" \ + " PRIMARY KEY(package, md_key, md_value)\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" \ @@ -380,6 +389,7 @@ const char *PARSER_TABLES[] = { "package_app_splash_screen", "package_dependency_info", "package_plugin_info", + "package_metadata", NULL, }; @@ -415,6 +425,7 @@ const char *PARSER_INIT_QUERIES[] = { QUERY_CREATE_TABLE_PACKAGE_APP_RES_CONTROL, QUERY_CREATE_TABLE_PACKAGE_RES_INFO, QUERY_CREATE_TABLE_PACKAGE_RES_ALLOWED_PACKAGE, + QUERY_CREATE_TABLE_PACKAGE_METADATA, NULL, }; diff --git a/src/common/parcel/filter_parcelable.cc b/src/common/parcel/filter_parcelable.cc index 0d49721..9804eb8 100644 --- a/src/common/parcel/filter_parcelable.cc +++ b/src/common/parcel/filter_parcelable.cc @@ -83,6 +83,11 @@ bool FilterParcelable::WriteFilter(tizen_base::Parcel* parcel, WritePkgmgrInfoMetadataNode( parcel, reinterpret_cast(list->data)); + WriteInt(parcel, g_slist_length(filter->list_pkg_metadata)); + for (GSList* list = filter->list_pkg_metadata; list; list = list->next) + WritePkgmgrInfoMetadataNode( + parcel, reinterpret_cast(list->data)); + return true; } @@ -107,6 +112,11 @@ void FilterParcelable::ReadFilter(tizen_base::Parcel* parcel) { for (int i = 0; i < val; ++i) filter_->list_metadata = g_slist_append(filter_->list_metadata, ReadPkgmgrInfoMetadataNode(parcel)); + + ReadInt(parcel, &val); + for (int i = 0; i < val; ++i) + filter_->list_pkg_metadata = g_slist_append(filter_->list_pkg_metadata, + ReadPkgmgrInfoMetadataNode(parcel)); } bool FilterParcelable::WritePkgmgrInfoNode(tizen_base::Parcel* parcel, diff --git a/src/common/parcel/pkginfo_parcelable.cc b/src/common/parcel/pkginfo_parcelable.cc index 5cbc049..e0f35d3 100644 --- a/src/common/parcel/pkginfo_parcelable.cc +++ b/src/common/parcel/pkginfo_parcelable.cc @@ -186,6 +186,17 @@ void PkgInfoParcelable::WriteResAllowedPackages(tizen_base::Parcel* parcel, } } +void PkgInfoParcelable::WriteMetadata(tizen_base::Parcel* parcel, + GList* metadata) const { + WriteInt(parcel, g_list_length(metadata)); + + for (GList* tmp = metadata; tmp; tmp = tmp->next) { + metadata_x* ptr = reinterpret_cast(tmp->data); + WriteString(parcel, ptr->key); + WriteString(parcel, ptr->value); + } +} + void PkgInfoParcelable::WritePackage(tizen_base::Parcel* parcel, package_x* package) const { WriteString(parcel, package->for_all_users); @@ -235,6 +246,7 @@ void PkgInfoParcelable::WritePackage(tizen_base::Parcel* parcel, WriteDependencies(parcel, package->dependencies); WritePlugin(parcel, package->plugin); WriteResAllowedPackages(parcel, package->res_allowed_packages); + WriteMetadata(parcel, package->metadata); } void PkgInfoParcelable::ReadIcon(tizen_base::Parcel* parcel, GList** list) { @@ -438,6 +450,20 @@ void PkgInfoParcelable::ReadResAllowedPackages(tizen_base::Parcel* parcel, } } +void PkgInfoParcelable::ReadMetadata(tizen_base::Parcel* parcel, GList** list) { + int size = 0; + ReadInt(parcel, &size); + + for (int i = 0; i < size; ++i) { + metadata_x* metadata = + reinterpret_cast(calloc(1, sizeof(metadata_x))); + ReadString(parcel, &metadata->key); + ReadString(parcel, &metadata->value); + + *list = g_list_append(*list, metadata); + } +} + package_x* PkgInfoParcelable::ReadPackage(tizen_base::Parcel* parcel) { package_x* package = reinterpret_cast(calloc(1, sizeof(package_x))); @@ -489,6 +515,7 @@ package_x* PkgInfoParcelable::ReadPackage(tizen_base::Parcel* parcel) { ReadDependencies(parcel, &package->dependencies); ReadPlugin(parcel, &package->plugin); ReadResAllowedPackages(parcel, &package->res_allowed_packages); + ReadMetadata(parcel, &package->metadata); return package; } diff --git a/src/common/parcel/pkginfo_parcelable.hh b/src/common/parcel/pkginfo_parcelable.hh index 27dd14e..4e3d588 100644 --- a/src/common/parcel/pkginfo_parcelable.hh +++ b/src/common/parcel/pkginfo_parcelable.hh @@ -53,6 +53,7 @@ class EXPORT_API PkgInfoParcelable : public AbstractParcelable { void WritePlugin(tizen_base::Parcel* parcel, GList* plugin) const; void WriteResAllowedPackages(tizen_base::Parcel* parcel, GList* plugin) const; + void WriteMetadata(tizen_base::Parcel* parcel, GList* metadata) const; void WritePackage(tizen_base::Parcel* parcel, package_x* package) const; void ReadIcon(tizen_base::Parcel* parcel, GList** list); void ReadLabel(tizen_base::Parcel* parcel, GList** list); @@ -69,6 +70,7 @@ class EXPORT_API PkgInfoParcelable : public AbstractParcelable { void ReadDependencies(tizen_base::Parcel* parcel, GList** list); void ReadPlugin(tizen_base::Parcel* parcel, GList** list); void ReadResAllowedPackages(tizen_base::Parcel* parcel, GList** list); + void ReadMetadata(tizen_base::Parcel* parcel, GList** list); package_x* ReadPackage(tizen_base::Parcel* parcel); std::vector> pkg_list_; diff --git a/src/pkgmgrinfo_basic.c b/src/pkgmgrinfo_basic.c index c153ffa..df90d39 100644 --- a/src/pkgmgrinfo_basic.c +++ b/src/pkgmgrinfo_basic.c @@ -590,6 +590,8 @@ API void pkgmgrinfo_basic_free_package(package_x *package) g_list_free_full(package->plugin, __ps_free_plugin_info); /*Free resource allowed packages*/ g_list_free_full(package->res_allowed_packages, __ps_free_res_allowed_packages); + /*Free Metadata*/ + g_list_free_full(package->metadata, __ps_free_metadata); free((void *)package); } diff --git a/src/pkgmgrinfo_pkginfo.c b/src/pkgmgrinfo_pkginfo.c index ea5a3a4..4cf0cff 100644 --- a/src/pkgmgrinfo_pkginfo.c +++ b/src/pkgmgrinfo_pkginfo.c @@ -1190,6 +1190,9 @@ API int pkgmgrinfo_pkginfo_filter_destroy(pkgmgrinfo_pkginfo_filter_h handle) if (filter->list_metadata) g_slist_free_full(filter->list_metadata, __destroy_metadata_node); + if (filter->list_pkg_metadata) + g_slist_free_full(filter->list_pkg_metadata, + __destroy_metadata_node); free(filter); @@ -1738,3 +1741,102 @@ API int pkgmgrinfo_compare_package_version(const char *current_version, return PMINFO_R_OK; } + +API int pkgmgrinfo_pkginfo_foreach_metadata(pkgmgrinfo_pkginfo_h handle, + pkgmgrinfo_pkg_metadata_list_cb metadata_func, void *user_data) +{ + retvm_if(handle == NULL, PMINFO_R_EINVAL, "pkginfo handle is NULL"); + retvm_if(metadata_func == NULL, PMINFO_R_EINVAL, + "Callback function is NULL"); + int ret = -1; + metadata_x *ptr; + GList *tmp; + pkgmgr_pkginfo_x *info = (pkgmgr_pkginfo_x *)handle; + + if (info->pkg_info == NULL) + return PMINFO_R_ERROR; + + for (tmp = info->pkg_info->metadata; tmp; tmp = tmp->next) { + ptr = (metadata_x *)tmp->data; + if (ptr == NULL) + continue; + if (ptr->key) { + ret = metadata_func(ptr->key, ptr->value ? + ptr->value : "", user_data); + if (ret < 0) + break; + } + } + return PMINFO_R_OK; +} + +API int pkgmgrinfo_pkginfo_metadata_filter_create( + pkgmgrinfo_pkginfo_metadata_filter_h *handle) +{ + return pkgmgrinfo_pkginfo_filter_create(handle); +} + +API int pkgmgrinfo_pkginfo_metadata_filter_destroy( + pkgmgrinfo_pkginfo_metadata_filter_h handle) +{ + return pkgmgrinfo_pkginfo_filter_destroy(handle); +} + +API int pkgmgrinfo_pkginfo_metadata_filter_add( + pkgmgrinfo_pkginfo_metadata_filter_h handle, + const char *key, const char *value) +{ + pkgmgrinfo_filter_x *filter = (pkgmgrinfo_filter_x *)handle; + pkgmgrinfo_metadata_node_x *node; + + /* value can be NULL. + * In that case all pkgs with specified key should be displayed + */ + if (handle == NULL || key == NULL) { + LOGE("invalid parameter"); + return PMINFO_R_EINVAL; + } + + node = calloc(1, sizeof(pkgmgrinfo_metadata_node_x)); + if (node == NULL) { + LOGE("out of memory"); + return PMINFO_R_ERROR; + } + + node->key = strdup(key); + if (value && strlen(value)) + node->value = strdup(value); + + filter->list_pkg_metadata = g_slist_append(filter->list_pkg_metadata, + (gpointer)node); + + return PMINFO_R_OK; +} + +API int pkgmgrinfo_pkginfo_usr_metadata_filter_foreach( + pkgmgrinfo_pkginfo_metadata_filter_h handle, + pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data, uid_t uid) +{ + if (handle == NULL || pkg_cb == NULL) { + LOGE("invalid parameter"); + return PMINFO_R_EINVAL; + } + + pkgmgrinfo_filter_x *filter = (pkgmgrinfo_filter_x *)handle; + + if (pkgmgrinfo_pkginfo_filter_add_bool(filter, + PMINFO_PKGINFO_PROP_PACKAGE_DISABLE, false)) + return PMINFO_R_ERROR; + + return _pkginfo_get_filtered_foreach_pkginfo(uid, handle, + PMINFO_PKGINFO_GET_ALL, pkg_cb, + user_data); +} + +API int pkgmgrinfo_pkginfo_metadata_filter_foreach( + pkgmgrinfo_pkginfo_metadata_filter_h handle, + pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data) +{ + return pkgmgrinfo_pkginfo_usr_metadata_filter_foreach(handle, pkg_cb, + user_data, _getuid()); +} diff --git a/src/pkgmgrinfo_private.c b/src/pkgmgrinfo_private.c index 1ace1b5..e81cf51 100644 --- a/src/pkgmgrinfo_private.c +++ b/src/pkgmgrinfo_private.c @@ -454,6 +454,26 @@ API int __get_filter_condition(gpointer data, uid_t uid, char **condition, GList return flag; } +API int __get_pkg_metadata_filter_condition(gpointer data, char **condition, + GList **params) +{ + pkgmgrinfo_metadata_node_x *node = (pkgmgrinfo_metadata_node_x *)data; + char buf[MAX_QUERY_LEN]; + + snprintf(buf, sizeof(buf), "(package_metadata.md_key=?"); + if (node->value) + strncat(buf, " AND package_metadata.md_value=?", + sizeof(buf) - strlen(buf) - 1); + strncat(buf, ")", sizeof(buf) - strlen(buf) - 1); + + *condition = strdup(buf); + *params = g_list_append(*params, strdup(node->key)); + if (node->value) + *params = g_list_append(*params, strdup(node->value)); + + return E_PMINFO_PKGINFO_JOIN_METADATA; +} + API int __get_metadata_filter_condition(gpointer data, char **condition, GList **params) { diff --git a/src/pkgmgrinfo_private.h b/src/pkgmgrinfo_private.h index d0f5f56..4dc7604 100644 --- a/src/pkgmgrinfo_private.h +++ b/src/pkgmgrinfo_private.h @@ -173,6 +173,7 @@ typedef enum _pkgmgrinfo_pkginfo_join_flag { E_PMINFO_PKGINFO_JOIN_LOCALIZED_INFO = 0x0001, E_PMINFO_PKGINFO_JOIN_PRIVILEGE_INFO = 0x0002, E_PMINFO_PKGINFO_JOIN_RES_INFO = 0x0004, + E_PMINFO_PKGINFO_JOIN_METADATA = 0x0008, } pkgmgrinfo_pkginfo_join_flag; typedef enum _pkgmgrinfo_appinfo_join_flag { @@ -206,6 +207,7 @@ typedef struct _pkgmgrinfo_filter_x { uid_t uid; GSList *list; GSList *list_metadata; + GSList *list_pkg_metadata; bool cache_flag; /* flag for pkginfo-server used to make cache */ } pkgmgrinfo_filter_x; @@ -321,6 +323,7 @@ void _pkgmgrinfo_node_destroy(pkgmgrinfo_node_x *node); int _check_create_cert_db(void); int __get_filter_condition(gpointer data, uid_t uid, char **condition, GList **param); +int __get_pkg_metadata_filter_condition(gpointer data, char **condition, GList **param); int __get_metadata_filter_condition(gpointer data, char **condition, GList **param); int _add_icon_info_into_list(const char *locale, char *value, GList **icon); int _add_label_info_into_list(const char *locale, char *value, GList **label); diff --git a/src/server/database/db_handle_provider.cc b/src/server/database/db_handle_provider.cc index 0ee999d..78bc332 100644 --- a/src/server/database/db_handle_provider.cc +++ b/src/server/database/db_handle_provider.cc @@ -404,8 +404,26 @@ int DBHandleProvider::UpdateCache(const tizen_base::Database& db, pid_t pid, return ret; } +inline bool CheckMetadataFilter(GList* metadata_list, + const std::unordered_map& metadata_map) { + for (auto* it = metadata_list; it != nullptr; it = g_list_next(it)) { + auto* node = reinterpret_cast(it->data); + if (node->key != nullptr) { + auto metadata = metadata_map.find(node->key); + if (metadata == metadata_map.end()) + continue; + + if (metadata->second.empty() || + strcmp(node->value ? node->value : "", metadata->second.c_str()) == 0) + return true; + } + } + return false; +} + inline bool CheckPkgFilters(pkgmgrinfo_filter_x* filter, - const std::shared_ptr& info) { + const std::shared_ptr& info, + const std::unordered_map& metadata_map) { for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) { auto node = reinterpret_cast(it->data); auto* checker = FilterCheckerProvider::GetInst(). @@ -414,7 +432,11 @@ inline bool CheckPkgFilters(pkgmgrinfo_filter_x* filter, return false; } - return true; + bool pass = true; + if (!metadata_map.empty()) + pass = CheckMetadataFilter(info->metadata, metadata_map); + + return pass; } std::vector> DBHandleProvider::GetPackages( @@ -422,6 +444,17 @@ std::vector> DBHandleProvider::GetPackages( const std::string& package) { std::vector> ret; + /* make metadata filter map */ + std::unordered_map metadata_map; + for (auto* it = filter->list_pkg_metadata; it != nullptr; + it = g_slist_next(it)) { + auto node = reinterpret_cast(it->data); + if (node->key == nullptr) + continue; + LOG(ERROR) << "add metadata filter"; + metadata_map[node->key] = (node->value ? node->value : ""); + } + if (internal::CheckPackageStorageStatus(filter)) { if (pkgmgrinfo_pkginfo_filter_add_bool(filter, PMINFO_PKGINFO_PROP_PACKAGE_CHECK_STORAGE, true) != PMINFO_R_OK) { @@ -431,12 +464,13 @@ std::vector> DBHandleProvider::GetPackages( } if (package.empty()) { for (auto& info : pkg_map_) { - if (CheckPkgFilters(filter, info.second)) + if (CheckPkgFilters(filter, info.second, metadata_map)) ret.push_back(info.second); } } else { auto map_it = pkg_map_.find(package); - if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second)) + if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second, + metadata_map)) ret.push_back(map_it->second); } @@ -449,35 +483,20 @@ void DBHandleProvider::AddPackage(std::string package, } inline bool CheckAppFilters(pkgmgrinfo_filter_x* filter, - const std::shared_ptr& info, - const std::unordered_map& metadata_map) { - for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) { - auto node = reinterpret_cast(it->data); - auto* checker = FilterCheckerProvider::GetInst(). - GetAppFilterChecker(node->prop); - if (!checker->CheckFilter(node, info.get())) - return false; - } - - bool pass = true; - if (!metadata_map.empty()) { - pass = false; - for (auto* it = info->metadata; it != nullptr; it = g_list_next(it)) { - auto* node = reinterpret_cast(it->data); - if (node->key != nullptr) { - auto metadata = metadata_map.find(node->key); - if (metadata == metadata_map.end()) - continue; - - if (metadata->second.empty() || - strcmp(node->value ? node->value : "", - metadata->second.c_str()) == 0) - return true; - } - } - } + const std::shared_ptr& info, + const std::unordered_map& metadata_map) { + for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) { + auto node = reinterpret_cast(it->data); + auto* checker = FilterCheckerProvider::GetInst(). + GetAppFilterChecker(node->prop); + if (!checker->CheckFilter(node, info.get())) + return false; + } - return pass; + bool pass = true; + if (!metadata_map.empty()) + pass = CheckMetadataFilter(info->metadata, metadata_map); + return pass; } std::vector> DBHandleProvider::GetApplications( diff --git a/src/server/pkginfo_internal.cc b/src/server/pkginfo_internal.cc index 4399f88..826f176 100644 --- a/src/server/pkginfo_internal.cc +++ b/src/server/pkginfo_internal.cc @@ -69,6 +69,9 @@ constexpr const char join_privilege_info[] = constexpr const char join_res_info[] = " LEFT OUTER JOIN package_res_info" " ON pi.package=package_res_info.package"; +constexpr const char join_metadata[] = + " LEFT OUTER JOIN package_metadata" + " ON pi.package=package_metadata.package"; char* GetCString(int idx, const tizen_base::Database::Result::Record& rec) { std::optional str = rec.GetString(idx); @@ -292,6 +295,36 @@ int GetResInfo(const tizen_base::Database& db, const char* pkgid, return PMINFO_R_OK; } +int GetPackageMetadata(const tizen_base::Database& db, + const char* pkgid, GList** metadata) { + auto q = tizen_base::Database::Sql( + "SELECT md_key, md_value " + "FROM package_metadata WHERE package=?") + .Bind(pkgid); + + auto r = db.Exec(q); + if (!r) { + _LOGE("db.Exec() failed: %s", static_cast(r)); + return PMINFO_R_ERROR; + } + + for (const auto& rec : r) { + metadata_x* info = static_cast( + calloc(1, sizeof(metadata_x))); + if (info == nullptr) { + LOGE("out of memory"); + return PMINFO_R_ERROR; + } + + int idx = 0; + info->key = GetCString(idx++, rec); + info->value = GetCString(idx++, rec); + *metadata = g_list_prepend(*metadata, info); + } + + return PMINFO_R_OK; +} + int _get_filtered_query(pkgmgrinfo_filter_x *filter, const std::string& locale, uid_t uid, std::string& query, std::vector& bind_params) { @@ -302,7 +335,8 @@ int _get_filtered_query(pkgmgrinfo_filter_x *filter, if (filter->cache_flag) { joined = E_PMINFO_PKGINFO_JOIN_LOCALIZED_INFO | E_PMINFO_PKGINFO_JOIN_PRIVILEGE_INFO | - E_PMINFO_PKGINFO_JOIN_RES_INFO; + E_PMINFO_PKGINFO_JOIN_RES_INFO | + E_PMINFO_PKGINFO_JOIN_METADATA; } std::string buf = " WHERE 1=1 "; @@ -319,6 +353,21 @@ int _get_filtered_query(pkgmgrinfo_filter_x *filter, free(condition); } + if (filter->list_pkg_metadata) + buf += " AND ("; + for (GSList* list = filter->list_pkg_metadata; list; list = list->next) { + char* condition = nullptr; + joined |= __get_pkg_metadata_filter_condition(list->data, + &condition, &tmp_params); + if (condition == nullptr) + continue; + buf += condition; + free(condition); + buf += " OR "; + } + if (filter->list_pkg_metadata) + buf += " 1=0)"; + std::string buf2; if (joined & E_PMINFO_PKGINFO_JOIN_LOCALIZED_INFO) { buf2 += join_localized_info; @@ -329,6 +378,8 @@ int _get_filtered_query(pkgmgrinfo_filter_x *filter, buf2 += join_privilege_info; if (joined & E_PMINFO_PKGINFO_JOIN_RES_INFO) buf2 += join_res_info; + if (joined & E_PMINFO_PKGINFO_JOIN_METADATA) + buf2 += join_metadata; for (GList* l = tmp_params; l != nullptr; l = l->next) bind_params.push_back(reinterpret_cast(l->data)); @@ -566,6 +617,11 @@ int DoGetPkgInfo(const tizen_base::Database& db, uid_t uid, } } + if (flag & PMINFO_PKGINFO_GET_METADATA) { + if (GetPackageMetadata(db, info->package, &info->metadata) < 0) + return PMINFO_R_ERROR; + } + if (is_check_storage && __pkginfo_check_installed_storage(info) != PMINFO_R_OK) continue; @@ -1723,6 +1779,37 @@ int InsertPackageResInfo(const tizen_base::Database& db, manifest_x* mfx) { return 0; } +int InsertPackageMetadataInfo(const tizen_base::Database& db, manifest_x* mfx) { + if (mfx->metadata == nullptr) + return 0; + + auto q = tizen_base::Database::Sql( + "INSERT INTO package_metadata (package," + " md_key, md_value) VALUES (?, ?, ?)"); + auto r = db.Prepare(q); + if (!r) { + _LOGE("db.Prepare() failed: %s", static_cast(r)); + return -1; + } + + for (GList* tmp = mfx->metadata; tmp; tmp = tmp->next) { + metadata_x* md = reinterpret_cast(tmp->data); + if (md == nullptr) + continue; + q.Reset() + .Bind(mfx->package) + .Bind(md->key) + .Bind(md->value); + + if (!db.Exec(q, r)) { + _LOGE("db.Exec() failed: %s", static_cast(r)); + return -1; + } + } + + return 0; +} + int InsertApplicationInfo(const tizen_base::Database& db, manifest_x *mfx) { auto q = tizen_base::Database::Sql( "INSERT INTO package_app_info (app_id, app_component," @@ -1993,6 +2080,8 @@ int DoInsertPackageInfo(const tizen_base::Database& db, manifest_x* mfx) { return -1; if (InsertPackageResInfo(db, mfx)) return -1; + if (InsertPackageMetadataInfo(db, mfx)) + return -1; return 0; } -- 2.7.4