summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--data-provider-master.manifest9
-rw-r--r--data/CMakeLists.txt2
-rw-r--r--data/data-provider-master.service6
-rw-r--r--include/instance.h6
-rw-r--r--include/service_common.h4
-rw-r--r--include/utility_service.h21
-rw-r--r--packaging/data-provider-master.spec13
-rw-r--r--src/badge_service.c4
-rw-r--r--src/instance.c93
-rw-r--r--src/main.c7
-rw-r--r--src/notification_service.c4
-rw-r--r--src/server.c12
-rw-r--r--src/service_common.c178
-rw-r--r--src/setting.c73
-rw-r--r--src/shortcut_service.c4
-rw-r--r--src/util.c2
-rw-r--r--src/utility_service.c298
18 files changed, 712 insertions, 25 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d0732e5..a907636 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,6 +82,7 @@ ADD_EXECUTABLE(${PROJECT_NAME}
src/shortcut_service.c
src/badge_service.c
src/notification_service.c
+ src/utility_service.c
src/service_common.c
)
diff --git a/data-provider-master.manifest b/data-provider-master.manifest
index b3b7af7..89ceb02 100644
--- a/data-provider-master.manifest
+++ b/data-provider-master.manifest
@@ -10,6 +10,10 @@
</provide>
<request>
<smack request="sys-assert::core" type="rwxat" />
+ <!--
+ <smack request="notification::db" type="rw" />
+ <smack request="badge::db" type="rw" />
+ -->
</request>
<permit>
<smack permit="dbus" type="rx" />
@@ -47,8 +51,9 @@
<!-- Init script -->
<filesystem path="/etc/rc.d/init.d/data-provider-master" label="_" exec_label="none" />
<filesystem path="/etc/rc.d/rc3.d/S99data-provider-master" label="_" exec_label="none" />
- <filesystem path="/usr/lib/systemd/user/data-provider-master.service" label="_" />
- <filesystem path="/usr/lib/systemd/user/tizen-middleware.target.wants/data-provider-master.service" label="_" />
+
+ <filesystem path="/usr/lib/systemd/system/data-provider-master.service" label="_" />
+ <filesystem path="/usr/lib/systemd/system/multi-user.target.wants/data-provider-master.service" label="_" />
<!-- Package manager plugin -->
<filesystem path="/usr/etc/package-manager/parserlib/liblivebox.so" label="_" />
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
index 772eac6..ade7015 100644
--- a/data/CMakeLists.txt
+++ b/data/CMakeLists.txt
@@ -1,2 +1,2 @@
INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/data-provider-master DESTINATION /etc/rc.d/init.d/ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
-INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/data-provider-master.service DESTINATION /usr/lib/systemd/user/ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/data-provider-master.service DESTINATION /usr/lib/systemd/system/ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
diff --git a/data/data-provider-master.service b/data/data-provider-master.service
index fb3ab4f..b9c9e51 100644
--- a/data/data-provider-master.service
+++ b/data/data-provider-master.service
@@ -16,7 +16,8 @@
[Unit]
Description=Data Provider daemon
-After=xorg.target
+After=rc-sdlevelinit.service
+Requires=rc-sdlevelinit.service
[Service]
Environment=BUFMGR_LOCK_TYPE="once"
@@ -24,6 +25,7 @@ Environment=BUFMGR_MAP_CACHE="true"
Type=simple
ExecStart=/usr/bin/data-provider-master
RestartSec=1
+Restart=restart-always
[Install]
-WantedBy=tizen-middleware.target
+WantedBy=multi-user.target
diff --git a/include/instance.h b/include/instance.h
index a68dbcb..c21e58c 100644
--- a/include/instance.h
+++ b/include/instance.h
@@ -235,4 +235,10 @@ extern void instance_fini(void);
extern int instance_event_callback_add(struct inst_info *inst, enum instance_event type, int (*event_cb)(struct inst_info *inst, void *data), void *data);
extern int instance_event_callback_del(struct inst_info *inst, enum instance_event type, int (*event_cb)(struct inst_info *inst, void *data));
+/*!
+ */
+extern int instance_set_data(struct inst_info *inst, const char *tag, void *data);
+extern void *instance_del_data(struct inst_info *inst, const char *tag);
+extern void *instance_get_data(struct inst_info *inst, const char *tag);
+
/* End of a file */
diff --git a/include/service_common.h b/include/service_common.h
index 981d6dd..eb6e385 100644
--- a/include/service_common.h
+++ b/include/service_common.h
@@ -21,6 +21,7 @@ enum tcb_type {
struct tcb;
struct service_context;
+struct service_event_item;
extern int tcb_fd(struct tcb *tcb);
extern struct service_context *tcb_svc_ctx(struct tcb *tcb);
@@ -33,4 +34,7 @@ extern int service_common_destroy(struct service_context *svc_ctx);
extern int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type);
extern int service_common_unicast_packet(struct tcb *tcb, struct packet *packet);
+extern struct service_event_item *service_common_add_timer(struct service_context *svc_ctx, double timer, int (*timer_cb)(struct service_context *svc_cx, void *data), void *data);
+extern int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item);
+
/* End of a file */
diff --git a/include/utility_service.h b/include/utility_service.h
new file mode 100644
index 0000000..db80cd0
--- /dev/null
+++ b/include/utility_service.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+extern int utility_service_init(void);
+extern int utility_service_fini(void);
+
+/* End of a file */
+
diff --git a/packaging/data-provider-master.spec b/packaging/data-provider-master.spec
index 6f9d269..15241ce 100644
--- a/packaging/data-provider-master.spec
+++ b/packaging/data-provider-master.spec
@@ -1,6 +1,6 @@
Name: data-provider-master
Summary: Master service provider for liveboxes.
-Version: 0.23.0
+Version: 0.23.2
Release: 1
Group: HomeTF/Livebox
License: Flora License
@@ -57,11 +57,12 @@ mkdir -p %{buildroot}/opt/usr/share/live_magazine/reader
mkdir -p %{buildroot}/opt/usr/share/live_magazine/always
mkdir -p %{buildroot}/opt/dbspace
mkdir -p %{buildroot}/%{_sysconfdir}/rc.d/rc3.d
-mkdir -p %{buildroot}/%{_libdir}/systemd/user/tizen-middleware.target.wants
+mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants
touch %{buildroot}/opt/dbspace/.livebox.db
touch %{buildroot}/opt/dbspace/.livebox.db-journal
ln -sf %{_sysconfdir}/rc.d/init.d/data-provider-master %{buildroot}/%{_sysconfdir}/rc.d/rc3.d/S99data-provider-master
-ln -sf %{_libdir}/systemd/user/data-provider-master.service %{buildroot}/%{_libdir}/systemd/user/tizen-middleware.target.wants/data-provider-master.service
+ln -sf ../data-provider-master.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/data-provider-master.service
+
%pre
# Executing the stop script for stopping the service of installed provider (old version)
@@ -82,7 +83,7 @@ chown 0:5000 /opt/dbspace/.livebox.db
chmod 640 /opt/dbspace/.livebox.db
chown 0:5000 /opt/dbspace/.livebox.db-journal
chmod 640 /opt/dbspace/.livebox.db-journal
-vconftool set -t bool "memory/data-provider-master/started" 0 -i -u 5000 -f
+vconftool set -t bool "memory/data-provider-master/started" 0 -i -u 5000 -f -s system::vconf_system
echo "Successfully installed. Please start a daemon again manually"
echo "%{_sysconfdir}/init.d/data-provider-master start"
@@ -95,8 +96,8 @@ echo "%{_sysconfdir}/init.d/data-provider-master start"
%{_bindir}/liveinfo
%{_prefix}/etc/package-manager/parserlib/*
%{_datarootdir}/data-provider-master/*
-%{_libdir}/systemd/user/data-provider-master.service
-%{_libdir}/systemd/user/tizen-middleware.target.wants/data-provider-master.service
+%{_libdir}/systemd/system/multi-user.target.wants/data-provider-master.service
+%{_libdir}/systemd/system/data-provider-master.service
%{_datarootdir}/license/*
/opt/usr/share/live_magazine
/opt/usr/share/live_magazine/log
diff --git a/src/badge_service.c b/src/badge_service.c
index db3e090..9b39e94 100644
--- a/src/badge_service.c
+++ b/src/badge_service.c
@@ -269,6 +269,10 @@ static int service_thread_main(struct tcb *tcb, struct packet *packet, void *dat
};
DbgPrint("TCB: %p, Packet: %p\n", tcb, packet);
+ if (!packet) {
+ DbgPrint("TCB: %p is terminated\n", tcb);
+ return 0;
+ }
command = packet_command(packet);
if (!command) {
diff --git a/src/instance.c b/src/instance.c
index 32d18cc..1005fdc 100644
--- a/src/instance.c
+++ b/src/instance.c
@@ -83,6 +83,11 @@ struct event_item {
void *data;
};
+struct tag_item {
+ char *tag;
+ void *data;
+};
+
struct inst_info {
struct pkg_info *info;
@@ -144,6 +149,8 @@ struct inst_info {
Ecore_Timer *update_timer; /*!< Only used for secured livebox */
Eina_List *delete_event_list;
+
+ Eina_List *data_list;
};
#define CLIENT_SEND_EVENT(instance, packet) ((instance)->client ? client_rpc_async_request((instance)->client, (packet)) : client_broadcast((instance), (packet)))
@@ -595,6 +602,7 @@ static inline void destroy_instance(struct inst_info *inst)
enum pd_type pd_type;
struct slave_node *slave;
struct event_item *item;
+ struct tag_item *tag_item;
invoke_delete_callbacks(inst);
@@ -633,6 +641,12 @@ static inline void destroy_instance(struct inst_info *inst)
if (inst->update_timer)
ecore_timer_del(inst->update_timer);
+ EINA_LIST_FREE(inst->data_list, tag_item) {
+ DbgPrint("Tagged item[%s] %p\n", tag_item->tag, tag_item->data);
+ free(tag_item->tag);
+ free(tag_item);
+ }
+
/*!
* \note
*
@@ -1301,6 +1315,9 @@ static int pd_buffer_close_cb(struct client_node *client, void *inst)
ret = instance_slave_close_pd(inst, client);
DbgPrint("Forcely close the PD ret: %d\n", ret);
+
+ instance_unref(inst);
+
return -1; /* Delete this callback */
}
@@ -1315,6 +1332,8 @@ static int pd_script_close_cb(struct client_node *client, void *inst)
ret = instance_slave_close_pd(inst, client);
DbgPrint("Forcely close the PD ret: %d\n", ret);
+ instance_unref(inst);
+
return -1; /* Delete this callback */
}
@@ -3038,4 +3057,78 @@ HAPI void instance_fini(void)
{
}
+static inline struct tag_item *find_tag_item(struct inst_info *inst, const char *tag)
+{
+ struct tag_item *item;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(inst->data_list, l, item) {
+ if (!strcmp(item->tag, tag))
+ return item;
+ }
+
+ return NULL;
+}
+
+HAPI int instance_set_data(struct inst_info *inst, const char *tag, void *data)
+{
+ struct tag_item *item;
+
+ item = find_tag_item(inst, tag);
+ if (!item) {
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->tag = strdup(tag);
+ if (!item->tag) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ free(item);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ inst->data_list = eina_list_append(inst->data_list, item);
+ }
+
+ if (!data) {
+ inst->data_list = eina_list_remove(inst->data_list, item);
+ free(item->tag);
+ free(item);
+ } else {
+ item->data = data;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void *instance_del_data(struct inst_info *inst, const char *tag)
+{
+ struct tag_item *item;
+ void *data;
+
+ item = find_tag_item(inst, tag);
+ if (!item)
+ return NULL;
+
+ inst->data_list = eina_list_remove(inst->data_list, item);
+ data = item->data;
+ free(item->tag);
+ free(item);
+
+ return data;
+}
+
+HAPI void *instance_get_data(struct inst_info *inst, const char *tag)
+{
+ struct tag_item *item;
+
+ item = find_tag_item(inst, tag);
+ if (!item)
+ return NULL;
+
+ return item->data;
+}
+
/* End of a file */
diff --git a/src/main.c b/src/main.c
index 63a16e0..3816703 100644
--- a/src/main.c
+++ b/src/main.c
@@ -53,6 +53,7 @@
#include "event.h"
#include "shortcut_service.h"
#include "notification_service.h"
+#include "utility_service.h"
#include "badge_service.h"
#if defined(FLOG)
@@ -156,11 +157,11 @@ static inline int app_terminate(void)
static void signal_handler(int signum, siginfo_t *info, void *unused)
{
int fd;
+
CRITICAL_LOG("Terminated(SIGTERM)\n");
fd = creat("/tmp/.stop.provider", 0644);
if (fd > 0)
close(fd);
- exit(0);
}
int main(int argc, char *argv[])
@@ -174,7 +175,7 @@ int main(int argc, char *argv[])
*/
ret = critical_log_init(util_basename(argv[0]));
if (ret < 0)
- fprintf(stderr, "Failed to init the critical log\n");
+ ErrPrint("Failed to init the critical log\n");
#if defined(FLOG)
__file_log_fp = fopen("/tmp/live.log", "w+t");
@@ -245,6 +246,7 @@ int main(int argc, char *argv[])
shortcut_service_init();
notification_service_init();
badge_service_init();
+ utility_service_init();
script_init();
app_create();
@@ -256,6 +258,7 @@ int main(int argc, char *argv[])
app_terminate();
script_fini();
+ utility_service_fini();
badge_service_fini();
notification_service_fini();
shortcut_service_fini();
diff --git a/src/notification_service.c b/src/notification_service.c
index 2c2bcea..40f3b91 100644
--- a/src/notification_service.c
+++ b/src/notification_service.c
@@ -329,6 +329,10 @@ static int service_thread_main(struct tcb *tcb, struct packet *packet, void *dat
};
DbgPrint("TCB: %p, Packet: %p\n", tcb, packet);
+ if (!packet) {
+ DbgPrint("TCB: %p is terminated\n", tcb);
+ return 0;
+ }
command = packet_command(packet);
if (!command) {
diff --git a/src/server.c b/src/server.c
index fea14c9..d7ab848 100644
--- a/src/server.c
+++ b/src/server.c
@@ -5645,6 +5645,10 @@ out:
static Eina_Bool lazy_pd_created_cb(void *data)
{
+ /*!
+ * After unref instance first,
+ * if the instance is not destroyed, try to notify the created PD event to the client.
+ */
if (instance_unref(data)) {
int ret;
ret = instance_client_pd_created(data, LB_STATUS_SUCCESS);
@@ -5807,6 +5811,14 @@ static struct packet *client_create_pd(pid_t pid, int handle, const struct packe
* the event correctly.
*/
inst = instance_ref(inst); /* To guarantee the inst */
+
+ /*!
+ * \note
+ * At here, we don't need to rememeber the timer object.
+ * Even if the timer callback is called, after the instance is destroyed.
+ * lazy_pd_created_cb will decrease the instance refcnt first.
+ * At that time, if the instance is released, the timer callback will do nothing.
+ */
if (!ecore_timer_add(DELAY_TIME, lazy_pd_created_cb, inst)) {
instance_unref(inst);
script_handler_unload(instance_pd_script(inst), 1);
diff --git a/src/service_common.c b/src/service_common.c
index 6a32976..0190bf6 100644
--- a/src/service_common.c
+++ b/src/service_common.c
@@ -21,6 +21,7 @@
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/timerfd.h>
#include <unistd.h>
#include <fcntl.h>
@@ -37,11 +38,25 @@
int errno;
+struct service_event_item {
+ enum {
+ SERVICE_EVENT_TIMER,
+ } type;
+
+ union {
+ struct {
+ int fd;
+ } timer;
+ } info;
+
+ int (*event_cb)(struct service_context *svc_cx, void *data);
+ void *cbdata;
+};
+
/*!
* \note
* Server information and global (only in this file-scope) variables are defined
*/
-
struct service_context {
pthread_t server_thid; /*!< Server thread Id */
int fd; /*!< Server socket handle */
@@ -55,6 +70,8 @@ struct service_context {
int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data);
void *service_thread_data;
+
+ Eina_List *event_list;
};
struct packet_info {
@@ -380,6 +397,88 @@ static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb)
}
/*!
+ * \note
+ * SERVER THREAD
+ */
+static inline int find_max_fd(struct service_context *svc_ctx)
+{
+ int fd;
+ Eina_List *l;
+ struct service_event_item *item;
+
+ fd = svc_ctx->fd > svc_ctx->tcb_pipe[PIPE_READ] ? svc_ctx->fd : svc_ctx->tcb_pipe[PIPE_READ];
+ fd = fd > svc_ctx->evt_pipe[PIPE_READ] ? fd : svc_ctx->evt_pipe[PIPE_READ];
+
+ EINA_LIST_FOREACH(svc_ctx->event_list, l, item) {
+ if (item->type == SERVICE_EVENT_TIMER && fd < item->info.timer.fd)
+ fd = item->info.timer.fd;
+ }
+
+ fd += 1;
+ return fd;
+}
+
+/*!
+ * \note
+ * SERVER THREAD
+ */
+static inline void update_fdset(struct service_context *svc_ctx, fd_set *set)
+{
+ Eina_List *l;
+ struct service_event_item *item;
+
+ FD_ZERO(set);
+ FD_SET(svc_ctx->fd, set);
+ FD_SET(svc_ctx->tcb_pipe[PIPE_READ], set);
+ FD_SET(svc_ctx->evt_pipe[PIPE_READ], set);
+
+ EINA_LIST_FOREACH(svc_ctx->event_list, l, item) {
+ if (item->type == SERVICE_EVENT_TIMER)
+ FD_SET(item->info.timer.fd, set);
+ }
+}
+
+/*!
+ * \note
+ * SERVER THREAD
+ */
+static inline void processing_timer_event(struct service_context *svc_ctx, fd_set *set)
+{
+ uint64_t expired_count;
+ Eina_List *l;
+ Eina_List *n;
+ struct service_event_item *item;
+
+ EINA_LIST_FOREACH_SAFE(svc_ctx->event_list, l, n, item) {
+ switch (item->type) {
+ case SERVICE_EVENT_TIMER:
+ if (!FD_ISSET(item->info.timer.fd, set))
+ break;
+
+ if (read(item->info.timer.fd, &expired_count, sizeof(expired_count)) == sizeof(expired_count)) {
+ DbgPrint("Expired %d times\n", expired_count);
+ if (item->event_cb(svc_ctx, item->cbdata) >= 0)
+ break;
+ } else {
+ ErrPrint("read: %s\n", strerror(errno));
+ }
+
+ if (!eina_list_data_find(svc_ctx->event_list, item))
+ break;
+
+ svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
+ if (close(item->info.timer.fd) < 0)
+ ErrPrint("close: %s\n", strerror(errno));
+ free(item);
+ break;
+ default:
+ ErrPrint("Unknown event: %d\n", item->type);
+ break;
+ }
+ }
+}
+
+/*!
* Accept new client connections
* And create a new thread for service.
*
@@ -398,15 +497,9 @@ static void *server_main(void *data)
struct packet_info *packet_info;
DbgPrint("Server thread is activated\n");
- fd = svc_ctx->fd > svc_ctx->tcb_pipe[PIPE_READ] ? svc_ctx->fd : svc_ctx->tcb_pipe[PIPE_READ];
- fd = fd > svc_ctx->evt_pipe[PIPE_READ] ? fd : svc_ctx->evt_pipe[PIPE_READ];
- fd += 1;
-
while (1) {
- FD_ZERO(&set);
- FD_SET(svc_ctx->fd, &set);
- FD_SET(svc_ctx->tcb_pipe[PIPE_READ], &set);
- FD_SET(svc_ctx->evt_pipe[PIPE_READ], &set);
+ fd = find_max_fd(svc_ctx);
+ update_fdset(svc_ctx, &set);
ret = select(fd, &set, NULL, NULL, NULL);
if (ret < 0) {
@@ -446,6 +539,12 @@ static void *server_main(void *data)
break;
}
+ /*!
+ * \note
+ * Invoke the service thread main, to notify the termination of a TCB
+ */
+ ret = svc_ctx->service_thread_main(tcb, NULL, svc_ctx->service_thread_data);
+
DbgPrint("Destroying TCB[%p]\n", tcb);
/*!
* at this time, the client thread can access this tcb.
@@ -481,6 +580,7 @@ static void *server_main(void *data)
free(packet_info);
}
+ processing_timer_event(svc_ctx, &set);
/* If there is no such triggered FD? */
}
@@ -721,4 +821,64 @@ HAPI int service_common_multicast_packet(struct tcb *tcb, struct packet *packet,
return 0;
}
+/*!
+ * \note
+ * SERVER THREAD
+ */
+HAPI struct service_event_item *service_common_add_timer(struct service_context *svc_ctx, double timer, int (*timer_cb)(struct service_context *svc_cx, void *data), void *data)
+{
+ struct service_event_item *item;
+ struct itimerspec spec;
+
+ item = calloc(1, sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ item->type = SERVICE_EVENT_TIMER;
+ item->info.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
+ if (item->info.timer.fd < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ free(item);
+ return NULL;
+ }
+
+ spec.it_interval.tv_sec = (time_t)timer;
+ spec.it_interval.tv_nsec = (timer - spec.it_interval.tv_sec) * 1000000000;
+ spec.it_value.tv_sec = 0;
+ spec.it_value.tv_nsec = 0;
+
+ if (timerfd_settime(item->info.timer.fd, 0, &spec, NULL) < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ close(item->info.timer.fd);
+ free(item);
+ return NULL;
+ }
+
+ item->event_cb = timer_cb;
+ item->cbdata = data;
+
+ svc_ctx->event_list = eina_list_append(svc_ctx->event_list, item);
+ return item;
+}
+
+/*!
+ * \note
+ * SERVER THREAD
+ */
+HAPI int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item)
+{
+ if (!eina_list_data_find(svc_ctx->event_list, item)) {
+ ErrPrint("Invalid event item\n");
+ return -EINVAL;
+ }
+
+ svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
+
+ close(item->info.timer.fd);
+ free(item);
+ return 0;
+}
+
/* End of a file */
diff --git a/src/setting.c b/src/setting.c
index 94b103a..5f6bdaf 100644
--- a/src/setting.c
+++ b/src/setting.c
@@ -22,6 +22,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
+#include <locale.h>
#include <vconf.h>
#include <dlog.h>
@@ -80,24 +81,91 @@ static void power_off_cb(keynode_t *node, void *user_data)
}
}
+static void region_changed_cb(keynode_t *node, void *user_data)
+{
+ char *region;
+ char *r;
+
+ region = vconf_get_str(VCONFKEY_REGIONFORMAT);
+ if (!region)
+ return;
+
+ setenv("LC_CTYPE", region, 1);
+ setenv("LC_NUMERIC", region, 1);
+ setenv("LC_TIME", region, 1);
+ setenv("LC_COLLATE", region, 1);
+ setenv("LC_MONETARY", region, 1);
+ setenv("LC_PAPER", region, 1);
+ setenv("LC_NAME", region, 1);
+ setenv("LC_ADDRESS", region, 1);
+ setenv("LC_TELEPHONE", region, 1);
+ setenv("LC_MEASUREMENT", region, 1);
+ setenv("LC_IDENTIFICATION", region, 1);
+
+ r = setlocale(LC_ALL, "");
+ if (r == NULL)
+ ErrPrint("Failed to change region\n");
+
+ free(region);
+}
+
+static void lang_changed_cb(keynode_t *node, void *user_data)
+{
+ char *lang;
+ char *r;
+
+ lang = vconf_get_str(VCONFKEY_LANGSET);
+ if (!lang)
+ return;
+
+ setenv("LANG", lang, 1);
+ setenv("LC_MESSAGES", lang, 1);
+
+ r = setlocale(LC_ALL, "");
+ if (!r)
+ ErrPrint("Failed to change locale\n");
+
+ DbgPrint("Locale: %s\n", setlocale(LC_ALL, NULL));
+ free(lang);
+}
+
HAPI int setting_init(void)
{
int ret;
ret = vconf_notify_key_changed(VCONFKEY_PM_STATE, lcd_state_cb, NULL);
if (ret < 0)
- ErrPrint("Failed to add vconf for lock state\n");
+ ErrPrint("Failed to add vconf for lock state: %d\n", ret);
ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, power_off_cb, NULL);
if (ret < 0)
- ErrPrint("Failed to add vconf for power state\n");
+ ErrPrint("Failed to add vconf for power state: %d \n", ret);
+
+ ret = vconf_notify_key_changed(VCONFKEY_LANGSET, lang_changed_cb, NULL);
+ if (ret < 0)
+ ErrPrint("Failed to add vconf for lang change: %d\n", ret);
+ ret = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, region_changed_cb, NULL);
+ if (ret < 0)
+ ErrPrint("Failed to add vconf for region change: %d\n", ret);
+
+ lang_changed_cb(NULL, NULL);
+ region_changed_cb(NULL, NULL);
return ret;
}
HAPI int setting_fini(void)
{
int ret;
+
+ ret = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, region_changed_cb);
+ if (ret < 0)
+ ErrPrint("Failed to ignore vconf key (%d)\n", ret);
+
+ ret = vconf_ignore_key_changed(VCONFKEY_LANGSET, lang_changed_cb);
+ if (ret < 0)
+ ErrPrint("Failed to ignore vconf key (%d)\n", ret);
+
ret = vconf_ignore_key_changed(VCONFKEY_PM_STATE, lcd_state_cb);
if (ret < 0)
ErrPrint("Failed to ignore vconf key (%d)\n", ret);
@@ -105,6 +173,7 @@ HAPI int setting_fini(void)
ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, power_off_cb);
if (ret < 0)
ErrPrint("Failed to ignore vconf key (%d)\n", ret);
+
return ret;
}
diff --git a/src/shortcut_service.c b/src/shortcut_service.c
index 73e6999..81b9005 100644
--- a/src/shortcut_service.c
+++ b/src/shortcut_service.c
@@ -95,6 +95,10 @@ static int service_thread_main(struct tcb *tcb, struct packet *packet, void *dat
const char *command;
DbgPrint("TCB: %p, Packet: %p\n", tcb, packet);
+ if (!packet) {
+ DbgPrint("TCB: %p is terminated\n", tcb);
+ return 0;
+ }
command = packet_command(packet);
if (!command) {
diff --git a/src/util.c b/src/util.c
index a95eb37..5f0674c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -249,7 +249,7 @@ HAPI char *util_replace_string(const char *src, const char *pattern, const char
out_sz = strlen(src);
ret = strdup(src);
if (!ret) {
- printf("Heap: %s\n", strerror(errno));
+ ErrPrint("Heap: %s\n", strerror(errno));
return NULL;
}
diff --git a/src/utility_service.c b/src/utility_service.c
new file mode 100644
index 0000000..0b7367d
--- /dev/null
+++ b/src/utility_service.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * 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 <stdio.h>
+
+#include <Eina.h>
+
+#include <dlog.h>
+#include <aul.h>
+
+#include <livebox-errno.h>
+#include <packet.h>
+
+#include "service_common.h"
+#include "utility_service.h"
+#include "debug.h"
+#include "util.h"
+#include "conf.h"
+
+#define UTILITY_ADDR "/tmp/.utility.service"
+#define SVC_PKG "org.tizen.data-provider-slave.icon"
+#define LAUNCH_TIMEOUT 10.0f
+
+static struct info {
+ Eina_List *pending_list;
+ Eina_List *context_list;
+ struct service_context *svc_ctx;
+
+ struct tcb *svc_daemon;
+ pid_t svc_pid;
+
+ struct service_event_item *launch_timer;
+} s_info = {
+ .pending_list = NULL,
+ .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
+ .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
+
+ .svc_daemon = NULL,
+ .svc_pid = -1,
+
+ .launch_timer = NULL,
+};
+
+struct pending_item {
+ struct tcb *tcb;
+ struct packet *packet;
+};
+
+struct context {
+ struct tcb *tcb;
+ double seq;
+};
+
+static inline int put_reply_tcb(struct tcb *tcb, double seq)
+{
+ struct context *ctx;
+
+ ctx = malloc(sizeof(*ctx));
+ if (!ctx) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ ctx->tcb = tcb;
+ ctx->seq = seq;
+
+ s_info.context_list = eina_list_append(s_info.context_list, ctx);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline struct tcb *get_reply_tcb(double seq)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct context *ctx;
+ struct tcb *tcb;
+
+ EINA_LIST_FOREACH_SAFE(s_info.context_list, l, n, ctx) {
+ if (ctx->seq != seq)
+ continue;
+
+ s_info.context_list = eina_list_remove(s_info.context_list, ctx);
+ tcb = ctx->tcb;
+ free(ctx);
+ return tcb;
+ }
+
+ return NULL;
+}
+
+static inline int flush_pended_request(void)
+{
+ /*!
+ * Flush all pended requests
+ */
+ struct pending_item *item;
+ int ret;
+
+ EINA_LIST_FREE(s_info.pending_list, item) {
+ ret = service_common_unicast_packet(s_info.svc_daemon, item->packet);
+ if (ret < 0) {
+ struct packet *reply;
+ reply = packet_create_reply(item->packet, "i", ret);
+ if (service_common_unicast_packet(item->tcb, reply) < 0)
+ ErrPrint("Unable to send packet\n");
+ packet_destroy(reply);
+ } else {
+ put_reply_tcb(item->tcb, packet_seq(item->packet));
+ }
+ packet_unref(item->packet);
+ free(item);
+ }
+
+ return 0;
+}
+
+static inline int put_pended_request(struct tcb *tcb, struct packet *packet)
+{
+ struct pending_item *item;
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->tcb = tcb;
+ item->packet = packet_ref(packet);
+ if (!item->packet) {
+ free(item);
+ ErrPrint("Unable to ref packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ s_info.pending_list = eina_list_append(s_info.pending_list, item);
+ return 0;
+}
+
+static int launch_timeout_cb(struct service_context *svc_ctx, void *data)
+{
+ struct pending_item *item;
+ struct packet *reply;
+
+ EINA_LIST_FREE(s_info.pending_list, item) {
+ reply = packet_create_reply(item->packet, "i", -EFAULT);
+ if (!reply) {
+ ErrPrint("Unable to create a packet\n");
+ } else {
+ int ret;
+
+ ret = service_common_unicast_packet(item->tcb, reply);
+ if (ret < 0)
+ ErrPrint("Failed to send reply packet: %d\n", ret);
+
+ packet_destroy(reply);
+ }
+
+ packet_unref(item->packet);
+ free(item);
+ }
+
+ s_info.launch_timer = NULL;
+ return -ECANCELED; /* Delete this timer */
+}
+
+static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
+{
+ struct packet *reply;
+ const char *cmd;
+ int ret;
+
+ if (!packet) {
+ DbgPrint("TCB %p is terminated\n", tcb);
+
+ if (tcb == s_info.svc_daemon) {
+ s_info.svc_daemon = NULL;
+ s_info.svc_pid = -1;
+ }
+
+ return 0;
+ }
+
+ cmd = packet_command(packet);
+ if (!cmd) {
+ ErrPrint("Invalid packet\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (packet_type(packet)) {
+ case PACKET_REQ:
+ if (s_info.svc_pid < 0) {
+ s_info.svc_pid = aul_launch_app(SVC_PKG, NULL);
+ if (s_info.svc_pid > 0) {
+ s_info.launch_timer = service_common_add_timer(tcb_svc_ctx(tcb), LAUNCH_TIMEOUT, launch_timeout_cb, NULL);
+ if (!s_info.launch_timer)
+ ErrPrint("Unable to create launch timer\n");
+ }
+ }
+
+ if (s_info.svc_pid < 0) {
+ ErrPrint("Failed to launch an app: %s(%d)\n", SVC_PKG, s_info.svc_pid);
+ ret = LB_STATUS_ERROR_FAULT;
+ goto reply_out;
+ } else if (!s_info.svc_daemon) {
+ ret = put_pended_request(tcb, packet);
+ if (ret < 0)
+ goto reply_out;
+ } else {
+ ret = service_common_unicast_packet(s_info.svc_daemon, packet);
+ if (ret <0)
+ goto reply_out;
+
+ put_reply_tcb(tcb, packet_seq(packet));
+ }
+
+ break;
+ case PACKET_REQ_NOACK:
+ if (!strcmp(cmd, "service_register")) {
+ if (s_info.svc_daemon) {
+ ErrPrint("Service daemon is already prepared\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (s_info.launch_timer) {
+ service_common_del_timer(tcb_svc_ctx(tcb), s_info.launch_timer);
+ s_info.launch_timer = NULL;
+ }
+
+ s_info.svc_daemon = tcb;
+ flush_pended_request();
+ }
+ break;
+ case PACKET_ACK:
+ tcb = get_reply_tcb(packet_seq(packet));
+ if (!tcb) {
+ ErrPrint("Unable to find reply tcb\n");
+ } else {
+ ret = service_common_unicast_packet(tcb, packet);
+ if (ret < 0)
+ ErrPrint("Unable to forward the reply packet\n");
+ }
+ break;
+ default:
+ ErrPrint("Packet type is not valid[%s]\n", cmd);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return LB_STATUS_SUCCESS;
+
+reply_out:
+ ErrPrint("Error: %d\n", ret);
+ reply = packet_create_reply(packet, "i", ret);
+ if (service_common_unicast_packet(tcb, reply) < 0)
+ ErrPrint("Unable to send reply packet\n");
+ packet_destroy(reply);
+ return ret;
+}
+
+int utility_service_init(void)
+{
+ if (s_info.svc_ctx) {
+ ErrPrint("Already initialized\n");
+ return LB_STATUS_ERROR_ALREADY;
+ }
+
+ s_info.svc_ctx = service_common_create(UTILITY_ADDR, service_thread_main, NULL);
+ if (!s_info.svc_ctx) {
+ ErrPrint("Unable to activate service thread\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ DbgPrint("Successfully initiated\n");
+ return LB_STATUS_SUCCESS;
+}
+
+int utility_service_fini(void)
+{
+ if (!s_info.svc_ctx)
+ return LB_STATUS_ERROR_INVALID;
+
+ service_common_destroy(s_info.svc_ctx);
+ DbgPrint("Successfully Finalized\n");
+ return LB_STATUS_SUCCESS;
+}
+
+/* End of a file */