rust-app-event has been added.
Change-Id: Id22b832977fb6f91d96cf9e5f411d73c19760502
Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
+%global crate rust_app_event
+%global real_crate_name rust_app_event
+
Name: capi-appfw-event
Summary: App event API
Version: 0.6.11
BuildRequires: cmake
BuildRequires: pkgconfig(dlog)
BuildRequires: pkgconfig(bundle)
+BuildRequires: pkgconfig(parcel)
BuildRequires: pkgconfig(eventsystem)
BuildRequires: pkgconfig(capi-base-common)
BuildRequires: pkgconfig(aul)
BuildRequires: pkgconfig(gmock)
BuildRequires: pkgconfig(pkgmgr-info)
+BuildRequires: rust-mockall_double
+BuildRequires: rust-mockall
+BuildRequires: rust-tizen-bundle
+BuildRequires: rust-libc
+BuildRequires: rust
%if 0%{?gcov:1}
BuildRequires: lcov
%description devel
An Application event library in Tizen C API (Development) package.
+%package -n rust-app-event
+Summary: app-event for rust
+Group: Rust/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description -n rust-app-event
+App Event for rust
+
%if 0%{?gcov:1}
%package gcov
Summary: App event API(gcov)
%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
%__make %{?jobs:-j%jobs}
+%{rustc_std_build} --crate-type=dylib \
+ --crate-name=%{real_crate_name} \
+ -L native="./src/app-event/" \
+ %{?rustc_edition:--edition=%{rustc_edition}} \
+ %rust_dylib_extern tizen_base \
+ %rust_dylib_extern libc \
+ ./src/rust-app-event/src/lib.rs
+
+%{rustc_std_build} --test --crate-type=bin \
+ --extern mockall=%{_rust_dylibdir}/libmockall.so \
+ --extern mockall_double=%{_rust_dylibdir}/libmockall_double.so \
+ --crate-name=unittests_%{real_crate_name} \
+ -L native="./src/app-event/" \
+ %{?rustc_edition:--edition=%{rustc_edition}} \
+ %rust_dylib_extern tizen_base \
+ ./src/rust-app-event/src/lib.rs
+
%check
-ctest -V
+mv %{buildroot}/%{_rust_dylibdir}/lib%{real_crate_name} %{buildroot}/%{_rust_dylibdir}/lib%{real_crate_name}.so
+
+export LD_LIBRARY_PATH="../../src/app-event"
+ctest -V %{?_smp_mflags}
+
+export LD_LIBRARY_PATH="./src/app-event/:%{_rust_dylibdir}"
+RUST_BACKTRACE=1 RUST_TEST_THREADS=1 ./unittests_%{real_crate_name}
%if 0%{?gcov:1}
lcov -c --ignore-errors mismatch,graph,unused --no-external -b . -d . -o %{name}.info
mkdir -p %{buildroot}%{_bindir}/tizen-unittests/%{name}
install -m 0755 run-unittest.sh %{buildroot}%{_bindir}/tizen-unittests/%{name}/
+install -d -m 0755 %{buildroot}%{_rust_dylibdir}
+install -m 0644 lib%{real_crate_name}.so %{buildroot}/%{_rust_dylibdir}/lib%{real_crate_name}
+
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%{_libdir}/pkgconfig/capi-appfw-event.pc
%{_libdir}/libcapi-appfw-event.so
+%files -n rust-app-event
+%manifest %{name}.manifest
+%{_rust_dylibdir}/lib%{real_crate_name}.so
+
%if 0%{?gcov:1}
%files gcov
%{_datadir}/gcov/*
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
-SET(fw_name "capi-appfw-event")
-
-PROJECT(${fw_name})
-
-SET(CMAKE_INSTALL_PREFIX /usr)
-SET(PREFIX ${CMAKE_INSTALL_PREFIX})
-
-SET(INC_DIR ${CMAKE_SOURCE_DIR}/include)
-INCLUDE_DIRECTORIES(${INC_DIR})
-
-SET(requires "glib-2.0 dlog bundle eventsystem capi-base-common aul pkgmgr-info")
-SET(pc_requires "capi-base-common")
-
-INCLUDE(FindPkgConfig)
-pkg_check_modules(${fw_name} REQUIRED ${requires})
-FOREACH(flag ${${fw_name}_CFLAGS})
- SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
-ENDFOREACH(flag)
-
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC")
-SET(CMAKE_C_FLAGS_DEBUG "-O0 -g -Wall -Werror")
-
-IF("${ARCH}" STREQUAL "arm")
- ADD_DEFINITIONS("-DTARGET")
-ENDIF("${ARCH}" STREQUAL "arm")
-
-ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
-ADD_DEFINITIONS("-DSLP_DEBUG")
-
-SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}")
-
-add_library(${fw_name} SHARED
- event.c
- )
-
-TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS})
-
-SET_TARGET_PROPERTIES(${fw_name}
- PROPERTIES
- VERSION ${FULLVER}
- SOVERSION ${MAJORVER}
- CLEAN_DIRECT_OUTPUT 1
-)
-
-INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR})
-INSTALL(
- DIRECTORY ${INC_DIR}/ DESTINATION include/appfw
- FILES_MATCHING
- PATTERN "*_private.h" EXCLUDE
- PATTERN "${INC_DIR}/*.h"
- )
-
-SET(PC_NAME ${fw_name})
-SET(PC_REQUIRED ${pc_requires})
-SET(PC_LDFLAGS -l${fw_name})
-
-CONFIGURE_FILE(
- ${CMAKE_SOURCE_DIR}/${fw_name}.pc.in
- ${CMAKE_SOURCE_DIR}/${fw_name}.pc
- @ONLY
-)
-INSTALL(FILES ${CMAKE_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
-
-
+ADD_SUBDIRECTORY(app-event)
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+SET(fw_name "capi-appfw-event")
+
+PROJECT(${fw_name})
+
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+SET(INC_DIR ${CMAKE_SOURCE_DIR}/include)
+INCLUDE_DIRECTORIES(${INC_DIR})
+
+SET(requires "glib-2.0 dlog bundle eventsystem capi-base-common aul pkgmgr-info")
+SET(pc_requires "capi-base-common")
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${fw_name} REQUIRED ${requires})
+FOREACH(flag ${${fw_name}_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g -Wall -Werror")
+
+IF("${ARCH}" STREQUAL "arm")
+ ADD_DEFINITIONS("-DTARGET")
+ENDIF("${ARCH}" STREQUAL "arm")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}")
+
+add_library(${fw_name} SHARED
+ event.c
+ )
+
+TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS})
+
+SET_TARGET_PROPERTIES(${fw_name}
+ PROPERTIES
+ VERSION ${FULLVER}
+ SOVERSION ${MAJORVER}
+ CLEAN_DIRECT_OUTPUT 1
+)
+
+INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR})
+INSTALL(
+ DIRECTORY ${INC_DIR}/ DESTINATION include/appfw
+ FILES_MATCHING
+ PATTERN "*_private.h" EXCLUDE
+ PATTERN "${INC_DIR}/*.h"
+ )
+
+SET(PC_NAME ${fw_name})
+SET(PC_REQUIRED ${pc_requires})
+SET(PC_LDFLAGS -l${fw_name})
+
+CONFIGURE_FILE(
+ ${CMAKE_SOURCE_DIR}/${fw_name}.pc.in
+ ${CMAKE_SOURCE_DIR}/${fw_name}.pc
+ @ONLY
+)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+
+
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2018 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+#include <tizen.h>
+#include <dlog.h>
+#include <app_event.h>
+#include <eventsystem.h>
+#include <aul_svc.h>
+#include <aul.h>
+#include <pkgmgr-info.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "CAPI_APPFW_EVENT"
+#define MAX_SIZE 100
+#define MAX_APP_ID_LEN 256
+#define SYS_EVENT_NAME_PREFIX "tizen.system.event"
+
+enum alias_appid_mode {
+ ALIAS_APPID_MODE_UNKNOWN,
+ ALIAS_APPID_MODE_OFF,
+ ALIAS_APPID_MODE_ON
+};
+
+typedef struct event_handler {
+ char *event_name;
+ int event_type;
+ unsigned int reg_id;
+ event_cb cb;
+ void *user_data;
+} event_handler_s;
+
+static pthread_mutex_t __register_sync_lock = PTHREAD_MUTEX_INITIALIZER;
+static GHashTable *__event_table;
+static pthread_mutex_t __event_handle_lock = PTHREAD_MUTEX_INITIALIZER;
+static GList *__event_handle_list;
+
+#define KEY_ALIAS_APP_ID "http://tizen.org/metadata/app-event/alias-appid-mode"
+
+static int __check_alias_appid_mode(const char *real_appid)
+{
+ pkgmgrinfo_appinfo_h handle;
+ int ret;
+ char *on_off;
+ int alias_mode = ALIAS_APPID_MODE_OFF;
+
+ ret = pkgmgrinfo_appinfo_get_appinfo(real_appid, &handle);
+ if (ret != PMINFO_R_OK) {
+ LOGE("fail to get %s appinfo %d", real_appid, ret);
+ return ALIAS_APPID_MODE_UNKNOWN;
+ }
+
+ ret = pkgmgrinfo_appinfo_get_metadata_value(handle, KEY_ALIAS_APP_ID, &on_off);
+ if (ret == PMINFO_R_OK && strcmp(on_off, "yes") == 0)
+ alias_mode = ALIAS_APPID_MODE_ON;
+
+ pkgmgrinfo_appinfo_destroy_appinfo(handle);
+ LOGD("alias_appid_mode %d", alias_mode);
+
+ return alias_mode;
+}
+
+static int __get_publication_alias_appid_mode(void)
+{
+ static int alias_appid_mode = ALIAS_APPID_MODE_UNKNOWN;
+ int ret;
+ char buffer[MAX_APP_ID_LEN] = {0, };
+
+ if (alias_appid_mode != ALIAS_APPID_MODE_UNKNOWN)
+ return alias_appid_mode;
+
+ ret = aul_app_get_appid_bypid(getpid(), buffer, sizeof(buffer));
+ if(ret != AUL_R_OK) {
+ LOGE("Failed to get the application ID: %d", ret);
+ return alias_appid_mode;
+ }
+
+ alias_appid_mode = __check_alias_appid_mode(buffer);
+ return alias_appid_mode;
+}
+
+static bool __get_real_event_name(const char *event_name,
+ char **real_event_name, bool publish)
+{
+ char *prefix, *user_defined_name;
+ char *real_appid, *alias_appid, *real_event;
+ int ret, len;
+
+ /* event.{sender's appid}.{user-defined name} */
+ prefix = strchr(event_name, '.');
+ if (prefix == NULL)
+ return false;
+
+ user_defined_name = strrchr(event_name, '.');
+ if (user_defined_name == NULL)
+ return false;
+
+ if (prefix == user_defined_name)
+ return false;
+
+ len = strlen(user_defined_name);
+ if (len <= 1 || len > 128)
+ return false;
+
+ len = user_defined_name - prefix;
+ alias_appid = malloc(sizeof(char) * len + 1);
+ if (alias_appid == NULL) {
+ LOGE("out of memory");
+ return false;
+ }
+
+ prefix += 1;
+ snprintf(alias_appid, len, "%s", prefix);
+
+ ret = aul_svc_get_appid_by_alias_appid(alias_appid, &real_appid);
+ free(alias_appid);
+ if (ret < 0)
+ return false;
+
+ if (publish == false
+ && __check_alias_appid_mode(real_appid) != ALIAS_APPID_MODE_ON)
+ return false;
+
+ len = 6 /* event. */ + strlen(real_appid)
+ + 1 /* . */ + strlen(user_defined_name);
+ real_event = malloc(sizeof(char) * len + 1);
+ if (real_event == NULL) {
+ LOGE("out of memory");
+ free(real_appid);
+ return false;
+ }
+
+ snprintf(real_event, len, "event.%s%s", real_appid, user_defined_name);
+ free(real_appid);
+ *real_event_name = real_event;
+ LOGI("real_event (%s)->(%s)", event_name, real_event);
+
+ return true;
+
+}
+
+static int __set_real_event_info(const char *real_event, const char *event)
+{
+ char *key;
+ char *value;
+
+ if (g_hash_table_lookup(__event_table, real_event) != NULL)
+ return ES_R_OK;
+
+ key = strdup(real_event);
+ if (key == NULL)
+ return ES_R_ENOMEM;
+
+ value = strdup(event);
+ if (value == NULL) {
+ free(key);
+ return ES_R_ENOMEM;
+ }
+
+ g_hash_table_insert(__event_table, key, value);
+
+ return ES_R_OK;
+}
+
+/* LCOV_EXCL_START */
+static const char *__event_error_to_string(event_error_e error)
+{
+ switch (error) {
+ case EVENT_ERROR_NONE:
+ return "NONE";
+ case EVENT_ERROR_INVALID_PARAMETER:
+ return "INVALID_PARAMETER";
+ case EVENT_ERROR_OUT_OF_MEMORY:
+ return "OUT_OF_MEMORY";
+ case EVENT_ERROR_TIMED_OUT:
+ return "TIMED_OUT";
+ case EVENT_ERROR_IO_ERROR:
+ return "IO ERROR";
+ case EVENT_ERROR_PERMISSION_DENIED:
+ return "PERMISSION DENIED";
+ default:
+ return "UNKNOWN";
+ }
+}
+/* LCOV_EXCL_STOP */
+
+static int __event_error(event_error_e error,
+ const char *function, const char *description)
+{
+ if (description) {
+ LOGE("[%s] %s(0x%08x) : %s", function, __event_error_to_string(error),
+ error, description);
+ } else {
+ LOGE("[%s] %s(0x%08x)", function, __event_error_to_string(error), error);
+ }
+
+ return error;
+}
+
+static void __event_eventsystem_callback(const char *real_event_name,
+ bundle_raw *event_data, int len, void *user_data)
+{
+ event_handler_h handler = (event_handler_h)user_data;
+ bundle *b;
+ const char *registered_event_name;
+ GList *found;
+ event_cb handler_cb;
+ void *handler_user_data;
+
+ registered_event_name = g_hash_table_lookup(__event_table, real_event_name);
+ LOGD("real_event_name(%s , %s)", real_event_name, registered_event_name);
+ if (registered_event_name == NULL)
+ registered_event_name = real_event_name;
+
+ pthread_mutex_lock(&__event_handle_lock);
+ found = g_list_find(__event_handle_list, handler);
+ if (found == NULL) {
+ LOGW("%p doesn't exist", handler);
+ pthread_mutex_unlock(&__event_handle_lock);
+ return;
+ }
+
+ handler_cb = handler->cb;
+ handler_user_data = handler->user_data;
+ pthread_mutex_unlock(&__event_handle_lock);
+
+ if (handler_cb) {
+ b = bundle_decode(event_data, len);
+ if (b == NULL) {
+ LOGE("bundle_decode failed");
+ return;
+ }
+
+ handler_cb(registered_event_name, b, handler_user_data);
+ bundle_free(b);
+ }
+}
+
+int event_add_event_handler(const char *event_name, event_cb callback,
+ void *user_data, event_handler_h *event_handler)
+{
+ int ret = 0;
+ int event_type = 0;
+ unsigned int reg_id = 0;
+ event_handler_h handler = NULL;
+ char *real_event_name;
+
+ if (event_handler == NULL || event_name == NULL || callback == NULL) {
+ return __event_error(EVENT_ERROR_INVALID_PARAMETER
+ , __FUNCTION__, NULL);
+ }
+
+ if (__event_table == NULL)
+ __event_table = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
+
+ handler = calloc(1, sizeof(event_handler_s));
+ if (handler == NULL) {
+ return __event_error(EVENT_ERROR_OUT_OF_MEMORY,
+ __FUNCTION__, NULL);
+ }
+
+ if (__get_real_event_name(event_name, &real_event_name, false)) {
+ handler->event_name = real_event_name;
+ ret = __set_real_event_info(real_event_name, event_name);
+ if (ret != ES_R_OK)
+ goto error;
+ } else {
+ handler->event_name = strdup(event_name);
+ }
+
+ if (handler->event_name == NULL) {
+ ret = ES_R_ENOMEM;
+ goto error;
+ }
+
+ handler->cb = callback;
+ handler->user_data = user_data;
+
+ pthread_mutex_lock(&__event_handle_lock);
+ __event_handle_list = g_list_prepend(__event_handle_list, handler);
+ pthread_mutex_unlock(&__event_handle_lock);
+
+ pthread_mutex_lock(&__register_sync_lock);
+ ret = eventsystem_register_application_event(handler->event_name, ®_id,
+ &event_type, (eventsystem_cb)__event_eventsystem_callback,
+ handler);
+ pthread_mutex_unlock(&__register_sync_lock);
+
+ if (ret < 0)
+ goto error;
+
+ handler->reg_id = reg_id;
+ handler->event_type = event_type;
+ *event_handler = handler;
+
+ LOGW("event_add_event_handler(%p, %s)", handler, event_name);
+ return EVENT_ERROR_NONE;
+
+error:
+ pthread_mutex_lock(&__event_handle_lock);
+ __event_handle_list = g_list_remove(__event_handle_list, handler);
+ pthread_mutex_unlock(&__event_handle_lock);
+ if (handler) {
+ if (handler->event_name)
+ free(handler->event_name);
+ free(handler);
+ }
+
+ if (ret == ES_R_ENOTPERMITTED) {
+ return __event_error(EVENT_ERROR_PERMISSION_DENIED,
+ __FUNCTION__, NULL);
+
+ } else if (ret == ES_R_ENOMEM) {
+ return __event_error(EVENT_ERROR_OUT_OF_MEMORY,
+ __FUNCTION__, NULL);
+ } else {
+ return __event_error(EVENT_ERROR_IO_ERROR,
+ __FUNCTION__, NULL);
+ }
+
+}
+
+int event_remove_event_handler(event_handler_h event_handler)
+{
+ int ret;
+
+ if (event_handler == NULL) {
+ return __event_error(EVENT_ERROR_INVALID_PARAMETER,
+ __FUNCTION__, NULL);
+ }
+
+ ret = eventsystem_unregister_application_event(event_handler->reg_id);
+ if (ret < 0)
+ return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
+
+ pthread_mutex_lock(&__event_handle_lock);
+ __event_handle_list = g_list_remove(__event_handle_list, event_handler);
+ pthread_mutex_unlock(&__event_handle_lock);
+
+ LOGW("event_remove_event_handler(%p, %s)", event_handler, event_handler->event_name);
+
+ free(event_handler->event_name);
+ free(event_handler);
+
+ return EVENT_ERROR_NONE;
+}
+
+static bool __is_system_event(const char *event_name)
+{
+ int len = strlen(SYS_EVENT_NAME_PREFIX);
+
+ if (strncmp(event_name, SYS_EVENT_NAME_PREFIX, len) != 0)
+ return false;
+
+ return true;
+}
+
+int event_publish_app_event(const char *event_name, bundle *event_data)
+{
+ char *real_event_name;
+ int ret;
+
+ if (event_data == NULL || event_name == NULL)
+ return __event_error(EVENT_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+
+ if (__is_system_event(event_name)) {
+ ret = eventsystem_send_system_event(event_name, event_data);
+ if (ret < 0)
+ return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
+
+ return EVENT_ERROR_NONE;
+ }
+
+ ret = __get_publication_alias_appid_mode();
+
+ if (ret == ALIAS_APPID_MODE_ON
+ && __get_real_event_name(event_name, &real_event_name, true)) {
+ ret = eventsystem_send_user_event(real_event_name, event_data, false);
+ free(real_event_name);
+ } else {
+ ret = eventsystem_send_user_event(event_name, event_data, false);
+ }
+
+ if (ret < 0)
+ return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
+
+ return EVENT_ERROR_NONE;
+}
+
+int event_publish_trusted_app_event(const char *event_name, bundle *event_data)
+{
+ char *real_event_name;
+ int ret;
+
+ if (event_data == NULL || event_name == NULL)
+ return __event_error(EVENT_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+
+ ret = __get_publication_alias_appid_mode();
+
+ if (ret == ALIAS_APPID_MODE_ON
+ && __get_real_event_name(event_name, &real_event_name, true)) {
+ ret = eventsystem_send_user_event(real_event_name, event_data, true);
+ free(real_event_name);
+ } else {
+ ret = eventsystem_send_user_event(event_name, event_data, true);
+ }
+
+ if (ret < 0)
+ return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
+
+ return EVENT_ERROR_NONE;
+}
+
+int event_keep_last_event_data(const char *event_name)
+{
+ int ret;
+ char *real_event_name = NULL;
+
+ if (event_name == NULL)
+ return __event_error(EVENT_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+
+ if (__get_real_event_name(event_name, &real_event_name, false)) {
+ ret = __set_real_event_info(real_event_name, event_name);
+ if (ret != ES_R_OK)
+ goto out;
+ ret = eventsystem_keep_last_event_data(real_event_name);
+ } else {
+ ret = eventsystem_keep_last_event_data(event_name);
+ }
+
+
+out:
+ if (real_event_name)
+ free(real_event_name);
+
+ if (ret < 0) {
+ if (ret == ES_R_ENOMEM)
+ return __event_error(EVENT_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+ else
+ return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
+ }
+
+ return EVENT_ERROR_NONE;
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 - 2018 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.
- */
-
-#define _GNU_SOURCE
-#include <stdlib.h>
-#include <stdio.h>
-#include <glib.h>
-#include <tizen.h>
-#include <dlog.h>
-#include <app_event.h>
-#include <eventsystem.h>
-#include <aul_svc.h>
-#include <aul.h>
-#include <pkgmgr-info.h>
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-
-#define LOG_TAG "CAPI_APPFW_EVENT"
-#define MAX_SIZE 100
-#define MAX_APP_ID_LEN 256
-#define SYS_EVENT_NAME_PREFIX "tizen.system.event"
-
-enum alias_appid_mode {
- ALIAS_APPID_MODE_UNKNOWN,
- ALIAS_APPID_MODE_OFF,
- ALIAS_APPID_MODE_ON
-};
-
-typedef struct event_handler {
- char *event_name;
- int event_type;
- unsigned int reg_id;
- event_cb cb;
- void *user_data;
-} event_handler_s;
-
-static pthread_mutex_t __register_sync_lock = PTHREAD_MUTEX_INITIALIZER;
-static GHashTable *__event_table;
-static pthread_mutex_t __event_handle_lock = PTHREAD_MUTEX_INITIALIZER;
-static GList *__event_handle_list;
-
-#define KEY_ALIAS_APP_ID "http://tizen.org/metadata/app-event/alias-appid-mode"
-
-static int __check_alias_appid_mode(const char *real_appid)
-{
- pkgmgrinfo_appinfo_h handle;
- int ret;
- char *on_off;
- int alias_mode = ALIAS_APPID_MODE_OFF;
-
- ret = pkgmgrinfo_appinfo_get_appinfo(real_appid, &handle);
- if (ret != PMINFO_R_OK) {
- LOGE("fail to get %s appinfo %d", real_appid, ret);
- return ALIAS_APPID_MODE_UNKNOWN;
- }
-
- ret = pkgmgrinfo_appinfo_get_metadata_value(handle, KEY_ALIAS_APP_ID, &on_off);
- if (ret == PMINFO_R_OK && strcmp(on_off, "yes") == 0)
- alias_mode = ALIAS_APPID_MODE_ON;
-
- pkgmgrinfo_appinfo_destroy_appinfo(handle);
- LOGD("alias_appid_mode %d", alias_mode);
-
- return alias_mode;
-}
-
-static int __get_publication_alias_appid_mode(void)
-{
- static int alias_appid_mode = ALIAS_APPID_MODE_UNKNOWN;
- int ret;
- char buffer[MAX_APP_ID_LEN] = {0, };
-
- if (alias_appid_mode != ALIAS_APPID_MODE_UNKNOWN)
- return alias_appid_mode;
-
- ret = aul_app_get_appid_bypid(getpid(), buffer, sizeof(buffer));
- if(ret != AUL_R_OK) {
- LOGE("Failed to get the application ID: %d", ret);
- return alias_appid_mode;
- }
-
- alias_appid_mode = __check_alias_appid_mode(buffer);
- return alias_appid_mode;
-}
-
-static bool __get_real_event_name(const char *event_name,
- char **real_event_name, bool publish)
-{
- char *prefix, *user_defined_name;
- char *real_appid, *alias_appid, *real_event;
- int ret, len;
-
- /* event.{sender's appid}.{user-defined name} */
- prefix = strchr(event_name, '.');
- if (prefix == NULL)
- return false;
-
- user_defined_name = strrchr(event_name, '.');
- if (user_defined_name == NULL)
- return false;
-
- if (prefix == user_defined_name)
- return false;
-
- len = strlen(user_defined_name);
- if (len <= 1 || len > 128)
- return false;
-
- len = user_defined_name - prefix;
- alias_appid = malloc(sizeof(char) * len + 1);
- if (alias_appid == NULL) {
- LOGE("out of memory");
- return false;
- }
-
- prefix += 1;
- snprintf(alias_appid, len, "%s", prefix);
-
- ret = aul_svc_get_appid_by_alias_appid(alias_appid, &real_appid);
- free(alias_appid);
- if (ret < 0)
- return false;
-
- if (publish == false
- && __check_alias_appid_mode(real_appid) != ALIAS_APPID_MODE_ON)
- return false;
-
- len = 6 /* event. */ + strlen(real_appid)
- + 1 /* . */ + strlen(user_defined_name);
- real_event = malloc(sizeof(char) * len + 1);
- if (real_event == NULL) {
- LOGE("out of memory");
- free(real_appid);
- return false;
- }
-
- snprintf(real_event, len, "event.%s%s", real_appid, user_defined_name);
- free(real_appid);
- *real_event_name = real_event;
- LOGI("real_event (%s)->(%s)", event_name, real_event);
-
- return true;
-
-}
-
-static int __set_real_event_info(const char *real_event, const char *event)
-{
- char *key;
- char *value;
-
- if (g_hash_table_lookup(__event_table, real_event) != NULL)
- return ES_R_OK;
-
- key = strdup(real_event);
- if (key == NULL)
- return ES_R_ENOMEM;
-
- value = strdup(event);
- if (value == NULL) {
- free(key);
- return ES_R_ENOMEM;
- }
-
- g_hash_table_insert(__event_table, key, value);
-
- return ES_R_OK;
-}
-
-/* LCOV_EXCL_START */
-static const char *__event_error_to_string(event_error_e error)
-{
- switch (error) {
- case EVENT_ERROR_NONE:
- return "NONE";
- case EVENT_ERROR_INVALID_PARAMETER:
- return "INVALID_PARAMETER";
- case EVENT_ERROR_OUT_OF_MEMORY:
- return "OUT_OF_MEMORY";
- case EVENT_ERROR_TIMED_OUT:
- return "TIMED_OUT";
- case EVENT_ERROR_IO_ERROR:
- return "IO ERROR";
- case EVENT_ERROR_PERMISSION_DENIED:
- return "PERMISSION DENIED";
- default:
- return "UNKNOWN";
- }
-}
-/* LCOV_EXCL_STOP */
-
-static int __event_error(event_error_e error,
- const char *function, const char *description)
-{
- if (description) {
- LOGE("[%s] %s(0x%08x) : %s", function, __event_error_to_string(error),
- error, description);
- } else {
- LOGE("[%s] %s(0x%08x)", function, __event_error_to_string(error), error);
- }
-
- return error;
-}
-
-static void __event_eventsystem_callback(const char *real_event_name,
- bundle_raw *event_data, int len, void *user_data)
-{
- event_handler_h handler = (event_handler_h)user_data;
- bundle *b;
- const char *registered_event_name;
- GList *found;
- event_cb handler_cb;
- void *handler_user_data;
-
- registered_event_name = g_hash_table_lookup(__event_table, real_event_name);
- LOGD("real_event_name(%s , %s)", real_event_name, registered_event_name);
- if (registered_event_name == NULL)
- registered_event_name = real_event_name;
-
- pthread_mutex_lock(&__event_handle_lock);
- found = g_list_find(__event_handle_list, handler);
- if (found == NULL) {
- LOGW("%p doesn't exist", handler);
- pthread_mutex_unlock(&__event_handle_lock);
- return;
- }
-
- handler_cb = handler->cb;
- handler_user_data = handler->user_data;
- pthread_mutex_unlock(&__event_handle_lock);
-
- if (handler_cb) {
- b = bundle_decode(event_data, len);
- if (b == NULL) {
- LOGE("bundle_decode failed");
- return;
- }
-
- handler_cb(registered_event_name, b, handler_user_data);
- bundle_free(b);
- }
-}
-
-int event_add_event_handler(const char *event_name, event_cb callback,
- void *user_data, event_handler_h *event_handler)
-{
- int ret = 0;
- int event_type = 0;
- unsigned int reg_id = 0;
- event_handler_h handler = NULL;
- char *real_event_name;
-
- if (event_handler == NULL || event_name == NULL || callback == NULL) {
- return __event_error(EVENT_ERROR_INVALID_PARAMETER
- , __FUNCTION__, NULL);
- }
-
- if (__event_table == NULL)
- __event_table = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
-
- handler = calloc(1, sizeof(event_handler_s));
- if (handler == NULL) {
- return __event_error(EVENT_ERROR_OUT_OF_MEMORY,
- __FUNCTION__, NULL);
- }
-
- if (__get_real_event_name(event_name, &real_event_name, false)) {
- handler->event_name = real_event_name;
- ret = __set_real_event_info(real_event_name, event_name);
- if (ret != ES_R_OK)
- goto error;
- } else {
- handler->event_name = strdup(event_name);
- }
-
- if (handler->event_name == NULL) {
- ret = ES_R_ENOMEM;
- goto error;
- }
-
- handler->cb = callback;
- handler->user_data = user_data;
-
- pthread_mutex_lock(&__event_handle_lock);
- __event_handle_list = g_list_prepend(__event_handle_list, handler);
- pthread_mutex_unlock(&__event_handle_lock);
-
- pthread_mutex_lock(&__register_sync_lock);
- ret = eventsystem_register_application_event(handler->event_name, ®_id,
- &event_type, (eventsystem_cb)__event_eventsystem_callback,
- handler);
- pthread_mutex_unlock(&__register_sync_lock);
-
- if (ret < 0)
- goto error;
-
- handler->reg_id = reg_id;
- handler->event_type = event_type;
- *event_handler = handler;
-
- LOGW("event_add_event_handler(%p, %s)", handler, event_name);
- return EVENT_ERROR_NONE;
-
-error:
- pthread_mutex_lock(&__event_handle_lock);
- __event_handle_list = g_list_remove(__event_handle_list, handler);
- pthread_mutex_unlock(&__event_handle_lock);
- if (handler) {
- if (handler->event_name)
- free(handler->event_name);
- free(handler);
- }
-
- if (ret == ES_R_ENOTPERMITTED) {
- return __event_error(EVENT_ERROR_PERMISSION_DENIED,
- __FUNCTION__, NULL);
-
- } else if (ret == ES_R_ENOMEM) {
- return __event_error(EVENT_ERROR_OUT_OF_MEMORY,
- __FUNCTION__, NULL);
- } else {
- return __event_error(EVENT_ERROR_IO_ERROR,
- __FUNCTION__, NULL);
- }
-
-}
-
-int event_remove_event_handler(event_handler_h event_handler)
-{
- int ret;
-
- if (event_handler == NULL) {
- return __event_error(EVENT_ERROR_INVALID_PARAMETER,
- __FUNCTION__, NULL);
- }
-
- ret = eventsystem_unregister_application_event(event_handler->reg_id);
- if (ret < 0)
- return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
-
- pthread_mutex_lock(&__event_handle_lock);
- __event_handle_list = g_list_remove(__event_handle_list, event_handler);
- pthread_mutex_unlock(&__event_handle_lock);
-
- LOGW("event_remove_event_handler(%p, %s)", event_handler, event_handler->event_name);
-
- free(event_handler->event_name);
- free(event_handler);
-
- return EVENT_ERROR_NONE;
-}
-
-static bool __is_system_event(const char *event_name)
-{
- int len = strlen(SYS_EVENT_NAME_PREFIX);
-
- if (strncmp(event_name, SYS_EVENT_NAME_PREFIX, len) != 0)
- return false;
-
- return true;
-}
-
-int event_publish_app_event(const char *event_name, bundle *event_data)
-{
- char *real_event_name;
- int ret;
-
- if (event_data == NULL || event_name == NULL)
- return __event_error(EVENT_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
-
- if (__is_system_event(event_name)) {
- ret = eventsystem_send_system_event(event_name, event_data);
- if (ret < 0)
- return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
-
- return EVENT_ERROR_NONE;
- }
-
- ret = __get_publication_alias_appid_mode();
-
- if (ret == ALIAS_APPID_MODE_ON
- && __get_real_event_name(event_name, &real_event_name, true)) {
- ret = eventsystem_send_user_event(real_event_name, event_data, false);
- free(real_event_name);
- } else {
- ret = eventsystem_send_user_event(event_name, event_data, false);
- }
-
- if (ret < 0)
- return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
-
- return EVENT_ERROR_NONE;
-}
-
-int event_publish_trusted_app_event(const char *event_name, bundle *event_data)
-{
- char *real_event_name;
- int ret;
-
- if (event_data == NULL || event_name == NULL)
- return __event_error(EVENT_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
-
- ret = __get_publication_alias_appid_mode();
-
- if (ret == ALIAS_APPID_MODE_ON
- && __get_real_event_name(event_name, &real_event_name, true)) {
- ret = eventsystem_send_user_event(real_event_name, event_data, true);
- free(real_event_name);
- } else {
- ret = eventsystem_send_user_event(event_name, event_data, true);
- }
-
- if (ret < 0)
- return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
-
- return EVENT_ERROR_NONE;
-}
-
-int event_keep_last_event_data(const char *event_name)
-{
- int ret;
- char *real_event_name = NULL;
-
- if (event_name == NULL)
- return __event_error(EVENT_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
-
- if (__get_real_event_name(event_name, &real_event_name, false)) {
- ret = __set_real_event_info(real_event_name, event_name);
- if (ret != ES_R_OK)
- goto out;
- ret = eventsystem_keep_last_event_data(real_event_name);
- } else {
- ret = eventsystem_keep_last_event_data(event_name);
- }
-
-
-out:
- if (real_event_name)
- free(real_event_name);
-
- if (ret < 0) {
- if (ret == ES_R_ENOMEM)
- return __event_error(EVENT_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
- else
- return __event_error(EVENT_ERROR_IO_ERROR, __FUNCTION__, NULL);
- }
-
- return EVENT_ERROR_NONE;
-}
--- /dev/null
+[package]
+name = "rust-app-event"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
--- /dev/null
+extern crate tizen_bundle;
+
+use std::ffi::{c_void, CStr, CString};
+use std::os::raw::c_char;
+pub use std::sync::{Arc, Mutex};
+pub use tizen_bundle::tizen_bundle::Bundle;
+
+#[cfg(test)]
+pub mod tests;
+
+#[cfg_attr(test, mockall::automock)]
+pub mod ffi {
+ use std::ffi::{c_void, CStr, CString};
+ use std::os::raw::c_char;
+
+ #[link(name = "capi-appfw-event")]
+ extern "C" {
+ pub fn event_add_event_handler(
+ event_name: *const c_char,
+ cb: extern "C" fn(*const c_char, *mut c_void, *mut c_void),
+ user_data: *mut c_void,
+ h: *mut *mut c_void,
+ ) -> i32;
+
+ pub fn event_remove_event_handler(h: *mut c_void) -> i32;
+
+ pub fn event_publish_app_event(
+ event_name: *const c_char,
+ event_data: *mut c_void
+ ) -> i32;
+ }
+}
+
+#[cfg_attr(test, mockall_double::double)]
+use ffi as mffi;
+
+use std::slice;
+
+extern "C" fn received_cb_broker(
+ event_name_ptr: *const c_char,
+ event_data_ptr: *mut c_void,
+ user_data: *mut c_void,
+) {
+ let mut app_event: &mut AppEvent = unsafe { &mut *(user_data as *mut AppEvent) };
+ if let Some(on_received) = app_event.on_received.as_ref() {
+ let event_name = unsafe { CStr::from_ptr(event_name_ptr).to_str().unwrap() };
+ let mut event_data = Bundle::from_raw_handle(event_data_ptr, false);
+ on_received.lock().unwrap()(event_name, &mut event_data);
+ }
+}
+
+#[derive(PartialEq, Debug)]
+pub enum EventError {
+ IoError = -5,
+ OutOfMemory = -12,
+ PermissionDenied = -13,
+ InvalidParameter = -22,
+}
+
+fn convert_err(id: i32) -> EventError {
+ match id {
+ -5 => EventError::IoError,
+ -12 => EventError::OutOfMemory,
+ -13 => EventError::PermissionDenied,
+ -22 => EventError::InvalidParameter,
+ _ => EventError::IoError,
+ }
+}
+
+pub struct AppEvent {
+ event_name: String,
+ on_received: Option<Arc<Mutex<Box<FnMut(&str, &Bundle) + Send>>>>,
+ handle: *mut c_void,
+}
+
+unsafe impl Send for AppEvent {}
+unsafe impl Sync for AppEvent {}
+
+impl AppEvent {
+ pub fn new(event_name: String) -> Self {
+ AppEvent {
+ event_name,
+ on_received: None,
+ handle: std::ptr::null_mut(),
+ }
+ }
+
+ pub fn on_received(&mut self, cb: Arc<Mutex<Box<FnMut(&str, &Bundle) + Send>>>) -> Result<(), EventError> {
+ if self.handle.is_null() {
+ let mut handle = std::ptr::null_mut();
+ let event_name_ptr = CString::new(self.event_name.clone()).unwrap();
+ let data = self as *mut _ as *mut c_void;
+ let ret = unsafe {
+ mffi::event_add_event_handler(event_name_ptr.as_ptr(), received_cb_broker, data, &mut handle)
+ };
+
+ if ret != 0 {
+ return Err(convert_err(ret));
+ }
+
+ self.handle = handle;
+ }
+
+ self.on_received = Some(cb);
+ Ok(())
+ }
+
+ pub fn publish(event_name: &str, bundle: &mut Bundle) -> Result<(), EventError> {
+ let c_string = CString::new(event_name).unwrap();
+ let event_name_ptr = c_string.into_raw();
+ let mut bundle_ptr = bundle.get_raw_handle();
+ let ret = unsafe {
+ mffi::event_publish_app_event(event_name_ptr, bundle_ptr)
+ };
+
+ match ret {
+ 0 => Ok(()),
+ _ => Err(convert_err(ret)),
+ }
+ }
+}
+
+impl Drop for AppEvent {
+ fn drop(&mut self) {
+ if self.handle.is_null() {
+ return;
+ }
+
+ unsafe {
+ mffi::event_remove_event_handler(self.handle);
+ }
+ }
+}
--- /dev/null
+use super::*;
+
+#[test]
+fn test_app_event_new() {
+ let app_event = AppEvent::new("Test".to_string());
+}
+
+#[test]
+fn test_app_event_on_received() {
+ let ctx = mffi::event_add_event_handler_context();
+ ctx.expect().times(1).returning(|_, _, _, _| 0);
+
+ let mut app_event = AppEvent::new("Test".to_string());
+ app_event.on_received(Arc::new(Mutex::new(Box::new(|event_name: &str, bundle: &Bundle| {}))));
+}
+
+#[test]
+fn test_app_event_publish() {
+ let ctx = mffi::event_publish_app_event_context();
+ ctx.expect().times(1).returning(|_, _| 0);
+
+ let mut bundle = Bundle::new();
+ AppEvent::publish("Test", &mut bundle);
+}
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src/app-event)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../mock)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../)
-AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../src LIB_SOURCES)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../src/app-event LIB_SOURCES)
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../mock MOCK_SOURCES)
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../tests/unittests SOURCES)