Add metadata to pkginfo 35/286635/8
authorSangyoon Jang <jeremy.jang@samsung.com>
Wed, 11 Jan 2023 01:14:42 +0000 (10:14 +0900)
committerSangyoon Jang <jeremy.jang@samsung.com>
Fri, 13 Jan 2023 01:29:17 +0000 (10:29 +0900)
Now metadata is available at package level.

Change-Id: Ic3f561fdb427d2482b1c3945366e6c26d7fe3976
Signed-off-by: Sangyoon Jang <jeremy.jang@samsung.com>
13 files changed:
include/pkgmgr-info.h
include/pkgmgrinfo_basic.h
include/pkgmgrinfo_type.h
parser/include/pkgmgr_parser_db_queries.h
src/common/parcel/filter_parcelable.cc
src/common/parcel/pkginfo_parcelable.cc
src/common/parcel/pkginfo_parcelable.hh
src/pkgmgrinfo_basic.c
src/pkgmgrinfo_pkginfo.c
src/pkgmgrinfo_private.c
src/pkgmgrinfo_private.h
src/server/database/db_handle_provider.cc
src/server/pkginfo_internal.cc

index 134af64..9a856d6 100644 (file)
@@ -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,
  * @}
  * @}
  */
-
index c89f31a..d75c33f 100644 (file)
@@ -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 {
index 2fe0274..7f83f16 100644 (file)
@@ -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()
index 6e9e738..2cbbdde 100644 (file)
        "  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,
 };
 
index 0d49721..9804eb8 100644 (file)
@@ -83,6 +83,11 @@ bool FilterParcelable::WriteFilter(tizen_base::Parcel* parcel,
     WritePkgmgrInfoMetadataNode(
         parcel, reinterpret_cast<pkgmgrinfo_metadata_node_x*>(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<pkgmgrinfo_metadata_node_x*>(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,
index 5cbc049..e0f35d3 100644 (file)
@@ -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<metadata_x*>(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<metadata_x*>(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<package_x*>(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;
 }
index 27dd14e..4e3d588 100644 (file)
@@ -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<std::shared_ptr<package_x>> pkg_list_;
index c153ffa..df90d39 100644 (file)
@@ -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);
 }
 
index ea5a3a4..4cf0cff 100644 (file)
@@ -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());
+}
index 1ace1b5..e81cf51 100644 (file)
@@ -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)
 {
index d0f5f56..4dc7604 100644 (file)
@@ -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);
index 0ee999d..78bc332 100644 (file)
@@ -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<std::string, std::string>& metadata_map) {
+  for (auto* it = metadata_list; it != nullptr; it = g_list_next(it)) {
+    auto* node = reinterpret_cast<metadata_x*>(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<package_x>& info) {
+    const std::shared_ptr<package_x>& info,
+    const std::unordered_map<std::string, std::string>& metadata_map) {
   for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
     auto node = reinterpret_cast<pkgmgrinfo_node_x*>(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<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
@@ -422,6 +444,17 @@ std::vector<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
     const std::string& package) {
   std::vector<std::shared_ptr<package_x>> ret;
 
+  /* make metadata filter map */
+  std::unordered_map<std::string, std::string> metadata_map;
+  for (auto* it = filter->list_pkg_metadata; it != nullptr;
+      it = g_slist_next(it)) {
+    auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(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<std::shared_ptr<package_x>> 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<application_x>& info,
-    const std::unordered_map<std::string, std::string>& metadata_map) {
-    for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
-      auto node = reinterpret_cast<pkgmgrinfo_node_x*>(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<metadata_x*>(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<application_x>& info,
+  const std::unordered_map<std::string, std::string>& metadata_map) {
+  for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
+    auto node = reinterpret_cast<pkgmgrinfo_node_x*>(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<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
index 4399f88..826f176 100644 (file)
@@ -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<std::string> 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<const char*>(r));
+    return PMINFO_R_ERROR;
+  }
+
+  for (const auto& rec : r) {
+    metadata_x* info = static_cast<metadata_x*>(
+        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<std::string>& 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<const char*>(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<const char*>(r));
+    return -1;
+  }
+
+  for (GList* tmp = mfx->metadata; tmp; tmp = tmp->next) {
+    metadata_x* md = reinterpret_cast<metadata_x*>(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<const char*>(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;
 }