libtzplatform-config
glib-2.0
gio-2.0
+ gio-unix-2.0
iniparser
security-manager
libsmack
int notification_ipc_request_load_noti_by_tag(notification_h noti,
const char *app_id, const char *tag, uid_t uid);
int notification_ipc_request_load_noti_grouping_list(notification_type_e type,
- int count,
- notification_list_h *list, uid_t uid);
+ int count, int count_per_page, notification_list_h *list, uid_t uid);
int notification_ipc_request_get_setting_array(
notification_setting_h *setting_array, int *count, uid_t uid);
int notification_ipc_request_get_setting_by_app_id(
int notification_ipc_check_event_receiver(int priv_id, bool *available);
void notification_ipc_reset_event_handler(int priv_id);
int notification_ipc_request_get_all_count(notification_type_e type, int *count, uid_t uid);
+
+/* Functions related with socket */
+int notification_ipc_socket_pair(int *fd);
+int notification_ipc_socket_get_read_buf_size(int fd, unsigned int *size);
+int notification_ipc_socket_get_write_buf_size(int fd, unsigned int *size);
+int notification_ipc_socket_write(int fd, const char *buffer, unsigned int nbytes);
+int notification_ipc_socket_write_string(int fd, const char *buffer, unsigned int string_len);
+int notification_ipc_socket_read(int fd, char *buffer, unsigned int nbytes);
#ifdef __cplusplus
}
#endif
/**
* @internal
+ * @brief Gets the notification list associated with the partition into pages.
+ * @since_tizen 4.0
+ * @privlevel public
+ * @privilege %http://tizen.org/privilege/notification
+ * @param[in] type The notification type
+ * @param[in] page_number The page number of the value set \n
+ * It starts from @c 1.
+ * @param[in] count_per_page The desired maximum count of the data items per page
+ * The maximum value is 100, If the value is set more than 100, \n
+ * it is automatically set 100.
+ * @param[out] list The notification list handle
+ * @return #NOTIFICATION_ERROR_NONE on success,
+ * otherwise any other value on failure
+ * @retval #NOTIFICATION_ERROR_NONE Success
+ * @retval #NOTIFICATION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #NOTIFICATION_ERROR_PERMISSION_DENIED The application does not have the privilege to call this method
+ * @see #notification_list_h
+ */
+int notification_get_list_by_page(notification_type_e type,
+ int page_number, int count_per_page, notification_list_h *list);
+
+int notification_get_list_by_page_for_uid(notification_type_e type,
+ int page_number, int count_per_page, notification_list_h *list, uid_t uid);
+/**
+ * @internal
* @brief Returns the notification detail list handle of grouping data.
* @details If count is equal to c -1, all notifications are returned.
* @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
int notification_noti_get_all_count(notification_type_e type, int *count, uid_t uid);
int notification_noti_get_grouping_list(notification_type_e type,
- int count,
+ int page_number,
+ int count_per_page,
notification_list_h *list,
+ int *list_count,
uid_t uid);
int notification_noti_get_detail_list(const char *app_id,
BuildRequires: pkgconfig(pkgmgr-info)
BuildRequires: pkgconfig(libtzplatform-config)
BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(gio-unix-2.0)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(iniparser)
BuildRequires: pkgconfig(security-manager)
if (list == NULL)
return NOTIFICATION_ERROR_INVALID_PARAMETER;
- ret = notification_noti_get_grouping_list(type, count, &get_list, uid);
+ ret = notification_noti_get_grouping_list(type, 1, count, &get_list, NULL, uid);
if (ret != NOTIFICATION_ERROR_NONE)
return ret;
#include <notification_internal.h>
#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
#define PROVIDER_BUS_NAME "org.tizen.data_provider_service"
#define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service"
return ret;
}
-static int _send_sync_noti(GVariant *body, GDBusMessage **reply, char *cmd)
+static GDBusMessage *__get_new_msg(GVariant *body, const char *cmd)
{
- int ret = NOTIFICATION_ERROR_NONE;
- GError *err = NULL;
- GDBusMessage *msg;
+ GDBusMessage *msg = NULL;
msg = g_dbus_message_new_method_call(
PROVIDER_BUS_NAME,
ERR("Failed to alloc new method call");
if (body)
g_variant_unref(body);
- return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+ return NULL;
/* LCOV_EXCL_STOP */
}
if (body != NULL)
g_dbus_message_set_body(msg, body);
+ return msg;
+}
+
+static int __send_message(GDBusMessage *msg, GDBusMessage **reply, const char *cmd)
+{
+ int ret = NOTIFICATION_ERROR_NONE;
+ GError *g_err = NULL;
+
*reply = g_dbus_connection_send_message_with_reply_sync(
_gdbus_conn,
msg,
-1,
NULL,
NULL,
- &err);
-
- g_object_unref(msg);
+ &g_err);
if (!*reply) {
/* LCOV_EXCL_START */
ret = NOTIFICATION_ERROR_SERVICE_NOT_READY;
- if (err != NULL) {
- ERR("No reply. cmd[%s] err[%s]", cmd, err->message);
- if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
+ if (g_err != NULL) {
+ ERR("No reply. cmd[%s] err[%s]", cmd, g_err->message);
+ if (g_err->code == G_DBUS_ERROR_ACCESS_DENIED)
ret = NOTIFICATION_ERROR_PERMISSION_DENIED;
- g_error_free(err);
+ g_error_free(g_err);
}
return ret;
/* LCOV_EXCL_STOP */
}
- if (g_dbus_message_to_gerror(*reply, &err)) {
- if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
+ if (g_dbus_message_to_gerror(*reply, &g_err)) {
+ if (g_err->code == G_DBUS_ERROR_ACCESS_DENIED)
ret = NOTIFICATION_ERROR_PERMISSION_DENIED;
else
- ret = err->code;
-
- ERR("Failed to send message[%s] err[%d]", cmd, ret);
- g_error_free(err);
+ ret = g_err->code;
+ g_error_free(g_err);
return ret;
}
- DBG("Success to send sync message");
+ INFO("Success to send message[%s]", cmd);
return NOTIFICATION_ERROR_NONE;
}
+static int _send_sync_noti_with_fd(int fd, GVariant *body, GDBusMessage **reply, char *cmd)
+{
+ int ret = NOTIFICATION_ERROR_NONE;
+ GDBusMessage *msg = NULL;
+ GUnixFDList *fd_list = NULL;
+ GError *g_err = NULL;
+
+ fd_list = g_unix_fd_list_new();
+ g_unix_fd_list_append(fd_list, fd, &g_err);
+ if (g_err != NULL) {
+ ERR("g_unix_fd_list_append [%s]", g_err->message);
+ g_object_unref(fd_list);
+ g_error_free(g_err);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+
+ msg = __get_new_msg(body, cmd);
+ if (msg == NULL) {
+ g_object_unref(fd_list);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+
+ g_dbus_message_set_unix_fd_list(msg, fd_list);
+
+ ret = __send_message(msg, reply, cmd);
+
+ g_object_unref(msg);
+ g_object_unref(fd_list);
+
+ INFO("Done - send sync message with fd list [%d]", ret);
+ return ret;
+}
+
+static int _send_sync_noti(GVariant *body, GDBusMessage **reply, char *cmd)
+{
+ int ret = NOTIFICATION_ERROR_NONE;
+ GDBusMessage *msg = NULL;
+
+ msg = __get_new_msg(body, cmd);
+ if (msg == NULL)
+ return NOTIFICATION_ERROR_IO_ERROR;
+
+ ret = __send_message(msg, reply, cmd);
+
+ if (msg)
+ g_object_unref(msg);
+
+ INFO("Done - send sync message [%d]", ret);
+ return ret;
+}
+
static void _send_message_with_reply_async_cb(GDBusConnection *connection,
GAsyncResult *res,
gpointer user_data)
}
/* LCOV_EXCL_STOP */
-int notification_ipc_request_load_noti_grouping_list(notification_type_e type, int count,
- notification_list_h *list, uid_t uid)
+static int __receive_list_from_socket(int fd, notification_list_h *list, int list_count)
+{
+ int ret = NOTIFICATION_ERROR_NONE;
+ char *data = NULL;
+ unsigned int data_size = 0;
+ unsigned int buf_size = 0;
+ notification_h noti;
+ GVariant *noti_body;
+ GVariant *reply_body;
+
+ ret = notification_ipc_socket_get_read_buf_size(fd, &buf_size);
+ if (ret != NOTIFICATION_ERROR_NONE) {
+ ERR("get read buf size");
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+
+ data = (char *)calloc(buf_size, sizeof(char));
+ if (data == NULL) {
+ ERR("OOM - socket buffer");
+ return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+ }
+
+ while (list_count > 0) {
+ ret = notification_ipc_socket_read(fd, (char *)&data_size, sizeof(data_size));
+ if (ret != NOTIFICATION_ERROR_NONE) {
+ ERR("socket read buf [%d]", ret);
+ goto out;
+ }
+
+ if (data_size > buf_size) {
+ buf_size = data_size;
+ if (data)
+ free(data);
+ data = (char *)calloc(data_size, sizeof(char));
+ if (data == NULL) {
+ ret = NOTIFICATION_ERROR_OUT_OF_MEMORY;
+ ERR("OOM - socket bulk buffer");
+ goto out;
+ }
+ }
+
+ ret = notification_ipc_socket_read(fd, data, data_size);
+ if (ret != NOTIFICATION_ERROR_NONE) {
+ ERR("socket read buf [%d]", ret);
+ goto out;
+ }
+
+ noti = (notification_h)calloc(1, sizeof(struct _notification));
+ if (noti == NULL) {
+ ret = NOTIFICATION_ERROR_OUT_OF_MEMORY;
+ ERR("OOM - notification handle");
+ goto out;
+ }
+
+ reply_body = g_variant_new_from_data(G_VARIANT_TYPE("(v)"),
+ data, data_size, TRUE, NULL, NULL);
+ g_variant_get(reply_body, "(v)", ¬i_body);
+ notification_ipc_make_noti_from_gvariant(noti, noti_body);
+ *list = notification_list_append(*list, noti);
+ g_variant_unref(noti_body);
+ g_variant_unref(reply_body);
+ list_count--;
+ }
+
+out:
+ if (ret != NOTIFICATION_ERROR_NONE)
+ notification_free_list(*list);
+ if (data)
+ free(data);
+
+ return ret;
+}
+
+int notification_ipc_request_load_noti_grouping_list(notification_type_e type,
+ int count, int count_per_page, notification_list_h *list, uid_t uid)
{
+#define RCV_SOCK 0
+#define SND_SOCK 1
int result;
+ int sockfd[2] = { 0, };
+ int list_count;
GDBusMessage *reply = NULL;
GVariant *body;
GVariant *reply_body;
- GVariant *iter_body;
- GVariantIter *iter;
- notification_h noti;
- GVariant *noti_body;
result = _dbus_init();
if (result != NOTIFICATION_ERROR_NONE) {
/* LCOV_EXCL_STOP */
}
- body = g_variant_new("(iii)", type, count, uid);
- result = _send_sync_noti(body, &reply, "load_noti_grouping_list");
+ result = notification_ipc_socket_pair(sockfd);
+ if (result != NOTIFICATION_ERROR_NONE)
+ return result;
+ INFO("socket receive[%d] send[%d]", sockfd[RCV_SOCK], sockfd[SND_SOCK]);
+ body = g_variant_new("(iiii)", type, count, count_per_page, uid);
+ result = _send_sync_noti_with_fd(sockfd[SND_SOCK], body, &reply, "load_noti_grouping_list");
if (result == NOTIFICATION_ERROR_NONE) {
reply_body = g_dbus_message_get_body(reply);
- g_variant_get(reply_body, "(a(v))", &iter);
-
- while (g_variant_iter_loop(iter, "(v)", &iter_body)) {
- noti = notification_create(NOTIFICATION_TYPE_NOTI);
- if (!noti) {
- /* LCOV_EXCL_START */
- result = NOTIFICATION_ERROR_OUT_OF_MEMORY;
- ERR("failed to create a notification");
- notification_free_list(*list);
- break;
- /* LCOV_EXCL_STOP */
- }
- g_variant_get(iter_body, "(v)", ¬i_body);
- notification_ipc_make_noti_from_gvariant(noti, noti_body);
- *list = notification_list_append(*list, noti);
- g_variant_unref(noti_body);
- }
- g_variant_iter_free(iter);
+ g_variant_get(reply_body, "(i)", &list_count);
+ result = __receive_list_from_socket(sockfd[RCV_SOCK], list, list_count);
}
if (reply)
g_object_unref(reply);
+ if (sockfd[RCV_SOCK])
+ close(sockfd[RCV_SOCK]);
+ if (sockfd[SND_SOCK])
+ close(sockfd[SND_SOCK]);
- DBG("result[%d]", result);
+ INFO("result [%d]", result);
return result;
}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "notification_ipc.h"
+#include "notification_debug.h"
+
+#define RCV_SOCK 0
+#define SND_SOCK 1
+
+#define MAX_RETRY_CNT 10
+#define WRITE_TIMEOUT 20 /* milliseconds*/
+
+EXPORT_API int notification_ipc_socket_pair(int *fd)
+{
+ int ret_fd[2];
+ int err;
+
+ if (fd == NULL)
+ return NOTIFICATION_ERROR_INVALID_PARAMETER;
+
+ errno = 0;
+ err = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, ret_fd);
+ if (err < 0) {
+ ERR("socketpair [%d]", errno);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+
+ fd[RCV_SOCK] = ret_fd[RCV_SOCK];
+ fd[SND_SOCK] = ret_fd[SND_SOCK];
+
+ return NOTIFICATION_ERROR_NONE;
+}
+
+static int __get_socket_buffer_size(int fd, unsigned int *size, int optname)
+{
+ unsigned int ret_size = 0;
+ socklen_t len = sizeof(ret_size);
+
+ errno = 0;
+ if (getsockopt(fd, SOL_SOCKET, optname, &ret_size, &len) < 0) {
+ ERR("read socket size [%d]", errno);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+
+ *size = ret_size;
+
+ return NOTIFICATION_ERROR_NONE;
+}
+
+EXPORT_API int notification_ipc_socket_get_read_buf_size(int fd, unsigned int *size)
+{
+ return __get_socket_buffer_size(fd, size, SO_RCVBUF);
+}
+
+EXPORT_API int notification_ipc_get_socket_write_buf_size(int fd, unsigned int *size)
+{
+ return __get_socket_buffer_size(fd, size, SO_SNDBUF);
+}
+
+
+EXPORT_API int notification_ipc_socket_write(int fd, const char *buffer, unsigned int nbytes)
+{
+ int retry_cnt = 0;
+ unsigned int left = nbytes;
+ ssize_t nb;
+ const struct timespec SLEEP_TIME = { 0, 20 * 1000 * 1000 };
+
+ while (left && (retry_cnt < MAX_RETRY_CNT)) {
+ errno = 0;
+ nb = write(fd, buffer, left);
+ if (nb == -1) {
+ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
+ ERR("continue..");
+ retry_cnt++;
+ nanosleep(&SLEEP_TIME, 0);
+ continue;
+ }
+ ERR("error fd [%d] errno [%d]", fd, errno);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+
+ left -= nb;
+ buffer += nb;
+ retry_cnt = 0;
+ }
+
+ if (left != 0) {
+ ERR("error fd [%d], retry_cnt [%d]", fd, retry_cnt);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+
+ return NOTIFICATION_ERROR_NONE;
+}
+
+EXPORT_API int notification_ipc_socket_write_string(int fd, const char *buffer, unsigned int string_len)
+{
+ int ret;
+
+ ret = notification_ipc_socket_write(fd, (char *)&string_len, sizeof(string_len));
+ if (ret != NOTIFICATION_ERROR_NONE) {
+ ERR("write string_len fail");
+ return ret;
+ }
+
+ if (string_len > 0) {
+ ret = notification_ipc_socket_write(fd, buffer, string_len);
+ if (ret != NOTIFICATION_ERROR_NONE) {
+ ERR("write string fail");
+ return ret;
+ }
+ }
+
+ return NOTIFICATION_ERROR_NONE;
+}
+
+EXPORT_API int notification_ipc_socket_read(int fd, char *buffer, unsigned int nbytes)
+{
+ unsigned int left = nbytes;
+ ssize_t nb;
+ int retry_cnt = 0;
+ const struct timespec SLEEP_TIME = { 0, 20 * 1000 * 1000 };
+
+ while (left && (retry_cnt < MAX_RETRY_CNT)) {
+ errno = 0;
+ nb = read(fd, buffer, left);
+ if (nb == 0) {
+ ERR("read socket - EOF, fd close [%d]", fd);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ } else if (nb == -1) {
+ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
+ ERR("errno [%d], sleep and retry", errno);
+ retry_cnt++;
+ nanosleep(&SLEEP_TIME, 0);
+ continue;
+ }
+ ERR("errno [%d] fd [%d]", errno, fd);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+ left -= nb;
+ buffer += nb;
+ retry_cnt = 0;
+ }
+
+ if (left != 0) {
+ ERR("error fd [%d] retry_cnt [%d]", fd, retry_cnt);
+ return NOTIFICATION_ERROR_IO_ERROR;
+ }
+
+ return NOTIFICATION_ERROR_NONE;
+}
if (list == NULL)
return NOTIFICATION_ERROR_INVALID_PARAMETER;
- ret = notification_ipc_request_load_noti_grouping_list(type, count, &get_list, uid);
+ ret = notification_ipc_request_load_noti_grouping_list(type, 1, count, &get_list, uid);
if (ret != NOTIFICATION_ERROR_NONE)
return ret;
return notification_get_list_for_uid(type, count, list, getuid());
}
+EXPORT_API int notification_get_list_by_page_for_uid(notification_type_e type,
+ int page_number,
+ int count_per_page,
+ notification_list_h *list,
+ uid_t uid)
+{
+#define COUNT_PER_PAGE_MAX 100
+
+ int ret;
+ notification_list_h get_list = NULL;
+
+ if (list == NULL) {
+ ERR("Invalid parameter - list is null");
+ return NOTIFICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (page_number <= 0) {
+ ERR("Invalid parameter - page_number [%d]", page_number);
+ return NOTIFICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (count_per_page > COUNT_PER_PAGE_MAX) {
+ WARN("count_per_page exceeds max value, max must be set %d",
+ COUNT_PER_PAGE_MAX);
+ count_per_page = COUNT_PER_PAGE_MAX;
+ }
+
+ ret = notification_ipc_request_load_noti_grouping_list(type,
+ page_number, count_per_page, &get_list, uid);
+ if (ret != NOTIFICATION_ERROR_NONE) {
+ ERR("fail request load noti grouping list");
+ return ret;
+ }
+
+ *list = notification_list_get_head(get_list);
+
+ return ret;
+}
+
+EXPORT_API int notification_get_list_by_page(notification_type_e type,
+ int page_number, int count_per_page, notification_list_h *list)
+{
+ return notification_get_list_by_page_for_uid(type,
+ page_number, count_per_page, list, getuid());
+}
+
EXPORT_API int notification_get_detail_list_for_uid(const char *app_id,
int group_id,
int priv_id,
notification_list_h *list,
uid_t uid)
{
- notification_list_h get_list = NULL;
int ret = 0;
+ notification_list_h get_list = NULL;
if (list == NULL || app_id == NULL)
return NOTIFICATION_ERROR_INVALID_PARAMETER;
return ret;
}
-static int _get_notification_list(char *query_where, notification_list_h *list, int count)
+static int _get_notification_list(char *query_where, notification_list_h *list, int *list_count, int count)
{
int ret;
int internal_count = 0;
__notification_noti_populate_from_stmt(stmt, noti);
if (noti != NULL) {
internal_count++;
-
get_list = notification_list_append(get_list, noti);
-
if (count != -1 && internal_count >= count) {
INFO("internal count[%d] count[%d]",
internal_count, count);
if (db != NULL)
notification_db_close(&db);
- if (get_list != NULL)
+ if (get_list != NULL) {
*list = notification_list_get_head(get_list);
+ *list_count = internal_count;
+ }
return ret;
}
}
EXPORT_API int notification_noti_get_grouping_list(notification_type_e type,
- int count,
+ int page_number,
+ int count_per_page,
notification_list_h *list,
+ int *list_count,
uid_t uid)
{
char *query = NULL;
char *query_where = NULL;
int ret = NOTIFICATION_ERROR_NONE;
int status;
+ int start_index;
/* Check current sim status */
ret = vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT, &status);
}
}
- query = sqlite3_mprintf("noti_list WHERE 1 > 0 %s %s "
- "ORDER BY rowid DESC, time DESC", query_where, query_uid);
+ if (count_per_page > 0) {
+ start_index = (page_number - 1) * count_per_page;
+ query = sqlite3_mprintf("noti_list WHERE 1 > 0 %s %s "
+ "ORDER BY rowid DESC, time DESC LIMIT %d,%d",
+ query_where, query_uid, start_index, count_per_page);
+ } else {
+ query = sqlite3_mprintf("noti_list WHERE 1 > 0 %s %s "
+ "ORDER BY rowid DESC, time DESC",
+ query_where, query_uid);
+ count_per_page = -1;
+ }
+
if (query == NULL) {
/* LCOV_EXCL_START */
ret = NOTIFICATION_ERROR_OUT_OF_MEMORY;
/* LCOV_EXCL_STOP */
}
- ret = _get_notification_list(query, list, count);
+ ret = _get_notification_list(query, list, list_count, count_per_page);
err:
if (query_where)
/* LCOV_EXCL_STOP */
}
- ret = _get_notification_list(query, list, count);
+ ret = _get_notification_list(query, list, NULL, count);
err:
if (query_where)