summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSung-jae Park <nicesj.park@samsung.com>2013-05-15 01:39:49 (GMT)
committerSung-jae Park <nicesj.park@samsung.com>2013-05-15 02:15:49 (GMT)
commit091d1a58b29d011c70afd67065f93877910593f8 (patch)
tree14fb14149da390da5b0266d9a9bb64716edc0aac
parentd6efe2dfba7a14c72847b5926cdf9d99f68d16d1 (diff)
downloaddata-provider-master-submit/tizen_2.1/20130516.041934.zip
data-provider-master-submit/tizen_2.1/20130516.041934.tar.gz
data-provider-master-submit/tizen_2.1/20130516.041934.tar.bz2
Patch 8/8 Update language change event handling code. Change the env value too. Region & Language is handles separately. So I separate them using VCONFKEY like app-core. Region & Lang. Patch 7/8 Care the language change notification. Patch 6/8 Handling the reply packet correctly. Patch 5/8 Define smack rule for vconf key. Patch 4/8 Don't terminate the provider even if it gets SIGTERM. Patch 3/8 Remove printf and update systemd service file. Patch 2/8 Update systemd service file. Patch 1/8 Implement the utility service. 1. Service routine updated. If a client is disconnected, service routine will be called with packet NULL. 2. Utility service is implemented. For generating the shortcut icon image, this utility service is prepared. Master just route the request & event for generating shortcut icon. Then the service daemon will be launched. and it will start generating icon image file. The image file is created in specified folder & name by client. So the client has to manage the created image file. 3. service_common_timer API is implemented. Using timerfd. Now the timer event can be handled in a separated thread. Change-Id: I9ce2546aea86c324ea9846d9dc673d6475b706c3
-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 */