From fef40c291ab14ccb5e9c061d749c133a595d09e1 Mon Sep 17 00:00:00 2001 From: Inkyun Kil Date: Tue, 10 Jan 2017 16:42:22 +0900 Subject: [PATCH] Add new api for subscribing db update callback - To inform task-manager of updated rua list. Change-Id: Ia7e8cb28221e21bd383a5171dd97dc2bf9b78737 Signed-off-by: Inkyun Kil (cherry picked from commit 4259894fde81136eca754812738695dc6871fe74) --- CMakeLists.txt | 3 +- include/rua.h | 37 +++++++++ include/rua_dbus.h | 59 +++++++++++++ packaging/librua.spec | 1 + src/rua.c | 40 +++++++++ src/rua_dbus.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/rua_internal.c | 15 ++++ test/rua-test.c | 150 +++++++++++++++++++++++++++------ 8 files changed, 505 insertions(+), 24 deletions(-) create mode 100644 include/rua_dbus.h create mode 100644 src/rua_dbus.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 80f24be..cca4366 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ AUX_SOURCE_DIRECTORY(src SRCS) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) INCLUDE(FindPkgConfig) -pkg_check_modules(pkgs REQUIRED sqlite3 db-util libtzplatform-config bundle aul) +pkg_check_modules(pkgs REQUIRED sqlite3 db-util libtzplatform-config bundle aul gio-2.0) FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") @@ -39,6 +39,7 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/rua_internal.h DESTINATION inc INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/rua_stat.h DESTINATION include/${PROJECT_NAME}) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/rua_stat_internal.h DESTINATION include/${PROJECT_NAME}) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/rua_util.h DESTINATION include/${PROJECT_NAME}) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/rua_dbus.h DESTINATION include/${PROJECT_NAME}) ADD_SUBDIRECTORY(test) diff --git a/include/rua.h b/include/rua.h index 3bf79d1..ad38464 100755 --- a/include/rua.h +++ b/include/rua.h @@ -78,6 +78,19 @@ struct rua_rec { }; /** + * @brief Called when the history is updated. + * @param[in] table db table pointer + * @param[in] nrows the number of record + * @param[in] ncols the number of field + * @param[in] user_data The user data passed from rua_register_update_cb() + */ +typedef void (*rua_history_update_cb) ( + char **table, + int nrows, + int ncols, + void *user_data); + +/** * @brief Add history * @param[in] pkg_name package name to delete history * @return 0 on success, otherwise a nagative error value @@ -170,6 +183,30 @@ API int rua_delete_history_with_instance_id(const char *app_id, const char *instance_id); /** + * @brief Registers a callback function to be invoked when the history is updated + * @param[in] callback The callback function to be registered + * @param[in] user_data The user data passed to rua_register_update_cb() + * @param[out] callback_id Added callback id + * @return 0 on success, otherwise a nagative error value + * @retval 0 if on successful + * @retval -1 if it is already registered or on failed + */ +API int rua_register_update_cb(rua_history_update_cb callback, + void *user_data, int *callback_id); +API int rua_register_update_cb_for_uid(rua_history_update_cb callback, + void *user_data, int *callback_id, uid_t uid); + +/** + * @brief Unregisters a callback function + * @param[in] callback_id Target callback id + * @return 0 on success, otherwise a nagative error value + * @retval 0 if on successful + * @retval -1 if the callback was not registered or on failed + */ +API int rua_unregister_update_cb(int callback_id); +API int rua_unregister_update_cb_for_uid(int callback_id, uid_t uid); + +/** * @brief Initialize rua * @return 0 on success, otherwise a nagative error value * @retval 0 on successful diff --git a/include/rua_dbus.h b/include/rua_dbus.h new file mode 100644 index 0000000..f0110ae --- /dev/null +++ b/include/rua_dbus.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file rua_dbus.h + * @brief RUA DBUS API declaration header file. + * @version 0.1 + * @history 0.1: RUA DBUS API Declarations, structure declaration + */ + +#ifndef __RUA_DBUS_H__ +#define __RUA_DBUS_H__ + +#include +#include +#include + +#ifndef API +#define API __attribute__ ((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "RUA" + +typedef enum +{ + ADD, + DELETE +} update_type; + +int rua_dbus_send_update_signal(update_type type); +int rua_dbus_signal_subscribe(rua_history_update_cb callback, + void *user_data, int *callback_id); +int rua_dbus_signal_unsubscribe(int callback_id); + +#ifdef __cplusplus +} +#endif +#endif /*__RUA_DBUS_H__*/ diff --git a/packaging/librua.spec b/packaging/librua.spec index 57078f3..e76f9e1 100644 --- a/packaging/librua.spec +++ b/packaging/librua.spec @@ -13,6 +13,7 @@ BuildRequires: pkgconfig(aul) BuildRequires: pkgconfig(db-util) BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(gio-2.0) %define upgrade_script_path /usr/share/upgrade/scripts diff --git a/src/rua.c b/src/rua.c index f8bab6a..6381870 100644 --- a/src/rua.c +++ b/src/rua.c @@ -24,6 +24,7 @@ #include "rua_internal.h" #include "rua.h" #include "db-schema.h" +#include "rua_dbus.h" int rua_add_history_for_uid(char *pkg_name, char *app_path, char *arg, uid_t uid) { @@ -172,6 +173,45 @@ int rua_history_load_db_for_uid(char ***table, int *nrows, int *ncols, uid_t uid return r; } +int rua_register_update_cb(rua_history_update_cb callback, void *user_data, int *callback_id) +{ + return rua_register_update_cb_for_uid(callback, user_data, callback_id, getuid()); +} + +int rua_register_update_cb_for_uid(rua_history_update_cb callback, void *user_data, int *callback_id, uid_t uid) +{ + int r; + + if (callback == NULL) + return -1; + + r = _rua_util_check_uid(uid); + if (r == -1) + return r; + + r = rua_dbus_signal_subscribe(callback, user_data, callback_id); + + return r; +} + +int rua_unregister_update_cb(int callback_id) +{ + return rua_unregister_update_cb_for_uid(callback_id, getuid()); +} + +int rua_unregister_update_cb_for_uid(int callback_id, uid_t uid) +{ + int r; + + r = _rua_util_check_uid(uid); + if (r == -1) + return r; + + r = rua_dbus_signal_unsubscribe(callback_id); + + return r; +} + int rua_history_unload_db(char ***table) { if (*table) { diff --git a/src/rua_dbus.c b/src/rua_dbus.c new file mode 100644 index 0000000..132bb4a --- /dev/null +++ b/src/rua_dbus.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include + +#include "rua.h" +#include "rua_dbus.h" + +#define RUA_INTERFACE "org.tizen.rua" +#define RUA_PATH "/org/tizen/rua" +#define RUA_SIGNAL_DATA_UPDATE "dataupdate" + +struct cb_data +{ + int callback_id; + rua_history_update_cb callback; + void *user_data; +}; + +static GDBusConnection *conn; +static guint s_id; + +static gint atomic_callback_id; +static GHashTable* callback_hash_table; + +static void __foreach_callback(gpointer key, gpointer value, + gpointer user_data); +static void __signal_handler(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data); +static void __rua_dbus_init(void); +static void __rua_dbus_exit(void); + +int rua_dbus_send_update_signal(update_type type) +{ + __rua_dbus_init(); + GError *err = NULL; + + if (g_dbus_connection_emit_signal(conn, + NULL, + RUA_PATH, + RUA_INTERFACE, + RUA_SIGNAL_DATA_UPDATE, + g_variant_new("(i)", type), + &err) == FALSE) { + LOGE("g_dbus_connection_emit_signal() is failed. %s", + err->message); + __rua_dbus_exit(); + return -1; + } + + if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) { + LOGE("g_dbus_connection_flush_sync() is failed. %s", + err->message); + __rua_dbus_exit(); + return -1; + } + + g_clear_error(&err); + + __rua_dbus_exit(); + + return 0; +} + +int rua_dbus_signal_subscribe(rua_history_update_cb callback, + void *user_data, int *callback_id) +{ + struct cb_data *cd = NULL; + + if (s_id == 0) { + __rua_dbus_init(); + + s_id = g_dbus_connection_signal_subscribe(conn, + NULL, + RUA_INTERFACE, + RUA_SIGNAL_DATA_UPDATE, + RUA_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + __signal_handler, + NULL, + NULL); + + if (s_id == 0) { + LOGE("g_dbus_connection_signal_subscribe() is failed."); + __rua_dbus_exit(); + return -1; + } + + if (!callback_hash_table) { + callback_hash_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, free); + if (!callback_hash_table) { + LOGE("out of memory : g_hash_table_new() is failed"); + __rua_dbus_exit(); + return -1; + } + } + } + + cd = (struct cb_data *)malloc(sizeof(struct cb_data)); + if (!cd) { + LOGE("out of memory : malloc() is failed"); + return -1; + } + + g_atomic_int_inc(&atomic_callback_id); + + cd->callback = callback; + cd->user_data = user_data; + cd->callback_id = atomic_callback_id; + + g_hash_table_insert(callback_hash_table, + GINT_TO_POINTER(cd->callback_id), (gpointer)cd); + + *callback_id = cd->callback_id; + + return 0; +} + +int rua_dbus_signal_unsubscribe(int callback_id) +{ + gboolean result = FALSE; + guint table_size = 0; + + result = g_hash_table_remove(callback_hash_table, GINT_TO_POINTER(callback_id)); + if (!result) { + LOGE("g_hash_table_remove failed(%d is wrong)", callback_id); + return -1; + } + + table_size = g_hash_table_size(callback_hash_table); + if (s_id && table_size == 0) { + g_dbus_connection_signal_unsubscribe(conn, s_id); + g_hash_table_destroy(callback_hash_table); + __rua_dbus_exit(); + callback_hash_table = NULL; + s_id = 0; + } + + return 0; +} + +static void __foreach_callback(gpointer key, gpointer value, + gpointer user_data) +{ + char **table = NULL; + int nrows = 0; + int ncols = 0; + int r = 0; + + struct cb_data *cd = (struct cb_data *)value; + + r = rua_history_load_db(&table, &nrows, &ncols); + if (r == -1) + return; + + if (cd->callback) { + cd->callback(table, nrows, ncols, cd->user_data); + } +} + +static void __signal_handler(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + int update_type; + + LOGI("__signal_handler"); + if (g_strcmp0(signal_name, RUA_SIGNAL_DATA_UPDATE)) + return; + + g_variant_get(parameters, "(i)", &update_type); + + g_hash_table_foreach(callback_hash_table, __foreach_callback, NULL); +} + +static void __rua_dbus_init(void) +{ + if (!conn) { + GError *err = NULL; + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (!conn) { + LOGE("g_bus_get_sync() is failed. %s", err->message); + g_error_free(err); + return; + } + } +} + +static void __rua_dbus_exit(void) +{ + if (conn) { + g_object_unref(conn); + conn = NULL; + } +} diff --git a/src/rua_internal.c b/src/rua_internal.c index 7995262..bc17818 100644 --- a/src/rua_internal.c +++ b/src/rua_internal.c @@ -20,6 +20,7 @@ #include "rua_internal.h" #include "db-schema.h" #include "rua_util.h" +#include "rua_dbus.h" static int __exec(sqlite3 *db, char *query) { @@ -120,6 +121,13 @@ int rua_usr_db_delete_history(bundle *b, uid_t uid) result = -1; } + r = rua_dbus_send_update_signal(DELETE); + if (r == -1) { + LOGE("[RUA SEND SIGNAL ERROR] \n"); + db_util_close(db); + return -1; + } + if (db != NULL) db_util_close(db); @@ -183,6 +191,13 @@ int rua_usr_db_add_history(struct rua_rec *rec, uid_t uid) return -1; } + r = rua_dbus_send_update_signal(ADD); + if (r == -1) { + LOGE("[RUA SEND SIGNAL ERROR] \n"); + db_util_close(db); + return -1; + } + db_util_close(db); return r; } diff --git a/test/rua-test.c b/test/rua-test.c index 2d85442..1dd6bf3 100644 --- a/test/rua-test.c +++ b/test/rua-test.c @@ -22,6 +22,7 @@ #include #include #include +#include /* For multi-user support */ #include @@ -31,6 +32,54 @@ #include "rua_stat.h" #include "rua_stat_internal.h" +static GMainLoop *mainloop = NULL; +static pthread_t g_thread; + +static int callback_id_table[10] = { 0, }; + +static gboolean run_test(int selected_number); +static void __print_menu() +{ + int test_num = 0; + int run_next = 1; + + while(run_next) { + printf("==========================================\n"); + printf(" Basic test menu \n"); + printf("==========================================\n"); + printf(" 0. EXIT\n"); + printf(" 1. Add rua history to DEFAULT USER(5001)\n"); + printf(" 2. Delete history with pkgname\n"); + printf(" 3. Load RUA history\n"); + printf(" 4. Update RUA stat\n"); + printf(" 5. Get RUA stat tags\n"); + printf(" 6. Register update callback (MAX 10)\n"); + printf(" 7. Unregister update callback\n"); + printf("------------------------------------------\n"); + int ret = scanf("%d", &test_num); + if (ret < 0) { + printf("scanf fail %d", ret); + break; + } + + run_next = run_test(test_num); + } + +} + +static void __update_cb(char **table, int rows, int cols) +{ + struct rua_rec record; + + printf("update_cb"); + int row; + for (row = 0; row < rows; ++row) { + rua_history_get_rec(&record, table, rows, cols, row); + printf("pkgname : %s, time : %d \n", record.pkg_name, (int)record.launch_time); + } + +} + static int __add_history() { int ret; @@ -95,13 +144,62 @@ static int __get_stat_tags() return ret; } -static gboolean run_test(int selected_number) +static int __register_callback() +{ + int ret; + + int i = 0; + for (i = 0; i < 10; i++) { + if (callback_id_table[i] == 0) { + int output = 0; + ret = rua_register_update_cb(__update_cb, NULL, &output); + if (ret == -1) { + printf("__register_callback error : %d \n", ret); + return -1; + } + + printf("callback id : %d \n", output); + callback_id_table[i] = output; + + return 0; + } + } + + return -1; +} + +static int __unregister_callback() { - gboolean go_to_loop = TRUE; + int ret; + + int i = 0; + int id = 0; + printf("Enter callback_id (The number from register_callback) : "); + scanf("%d", &id); + + for (i = 0; i < 10; i++) { + if (callback_id_table[i] == id) { + ret = rua_unregister_update_cb(callback_id_table[i]); + if (ret == -1) + printf("__unregister_callback : %d \n", ret); + callback_id_table[i] = 0; + return 0; + } + } + + return -1; +} + + +static gboolean run_test(int selected_number) +{ + int r = 0; + gboolean loop = TRUE; switch (selected_number) { case 0: - go_to_loop = FALSE; + g_main_loop_quit(mainloop); + loop = FALSE; break; case 1: @@ -124,38 +222,44 @@ static gboolean run_test(int selected_number) __get_stat_tags(); break; + case 6: + r = __register_callback(); + if (r == -1) + printf("table is full"); + break; + + case 7: + r = __unregister_callback(); + if (r == -1) + printf("id is wrong"); + + break; + default: break; } - return go_to_loop; + + return loop; } int main() { int ret = 0; - int test_num; - gboolean run_next = TRUE; - while(run_next) { - printf("==========================================\n"); - printf(" Basic test menu \n"); - printf("==========================================\n"); - printf(" 0. EXIT\n"); - printf(" 1. Add rua history to DEFAULT USER(5001)\n"); - printf(" 2. Delete history with pkgname\n"); - printf(" 3. Load RUA history\n"); - printf(" 4. Update RUA stat\n"); - printf(" 5. Get RUA stat tags\n"); - printf("------------------------------------------\n"); - ret = scanf("%d", &test_num); - if (ret < 0) { - printf("scanf fail %d", ret); - break; - } + mainloop = g_main_loop_new(NULL, FALSE); - run_next = run_test(test_num); + int result = pthread_create(&g_thread, NULL, __print_menu, (void *)NULL); + if (result < 0) + { + printf("pthread_create failed in initialize\n"); + return 0; } + + g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); + mainloop = NULL; + return ret; } -- 2.7.4