2 * Copyright 2013 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.1 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include <livebox-errno.h>
26 #include <sys/smack.h>
28 #include "critical_log.h"
29 #include "service_common.h"
30 #include "utility_service.h"
36 #define SVC_PKG "com.samsung.data-provider-slave.icon"
39 #ifndef LAUNCH_TIMEOUT
40 #define LAUNCH_TIMEOUT 10.0f
44 #define TTL_TIMEOUT 30.0f
48 Eina_List *pending_list;
49 Eina_List *context_list;
50 struct service_context *svc_ctx;
52 struct tcb *svc_daemon;
53 int svc_daemon_is_launched;
56 struct service_event_item *launch_timer;
57 struct service_event_item *delay_launcher;
58 struct service_event_item *ttl_timer;
61 .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
62 .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
65 .svc_daemon_is_launched = 0,
69 .delay_launcher = NULL,
75 struct packet *packet;
83 static int lazy_launcher_cb(struct service_context *svc_ctx, void *data);
85 static int put_reply_tcb(struct tcb *tcb, double seq)
89 ctx = malloc(sizeof(*ctx));
91 ErrPrint("Heap: %s\n", strerror(errno));
92 return LB_STATUS_ERROR_MEMORY;
98 s_info.context_list = eina_list_append(s_info.context_list, ctx);
100 return LB_STATUS_SUCCESS;
103 static inline struct tcb *get_reply_tcb(double seq)
110 EINA_LIST_FOREACH_SAFE(s_info.context_list, l, n, ctx) {
111 if (ctx->seq != seq) {
115 s_info.context_list = eina_list_remove(s_info.context_list, ctx);
124 static inline int flush_pended_request(void)
127 * Flush all pended requests
129 struct pending_item *item;
132 EINA_LIST_FREE(s_info.pending_list, item) {
133 if (tcb_is_valid(s_info.svc_ctx, s_info.svc_daemon) >= 0) {
134 ret = service_common_unicast_packet(s_info.svc_daemon, item->packet);
140 if (tcb_is_valid(s_info.svc_ctx, item->tcb) >= 0) {
141 struct packet *reply;
142 reply = packet_create_reply(item->packet, "i", ret);
143 if (service_common_unicast_packet(item->tcb, reply) < 0) {
144 ErrPrint("Unable to send packet\n");
146 packet_destroy(reply);
149 put_reply_tcb(item->tcb, packet_seq(item->packet));
151 packet_unref(item->packet);
158 static inline int put_pended_request(struct tcb *tcb, struct packet *packet)
160 struct pending_item *item;
162 item = malloc(sizeof(*item));
164 ErrPrint("Heap: %s\n", strerror(errno));
165 return LB_STATUS_ERROR_MEMORY;
169 item->packet = packet_ref(packet);
172 ErrPrint("Unable to ref packet\n");
173 return LB_STATUS_ERROR_FAULT;
176 s_info.pending_list = eina_list_append(s_info.pending_list, item);
180 static int launch_timeout_cb(struct service_context *svc_ctx, void *data)
182 struct pending_item *item;
183 struct packet *reply;
185 EINA_LIST_FREE(s_info.pending_list, item) {
186 if (tcb_is_valid(s_info.svc_ctx, item->tcb) >= 0) {
187 reply = packet_create_reply(item->packet, "i", -EFAULT);
189 ErrPrint("Unable to create a packet\n");
193 ret = service_common_unicast_packet(item->tcb, reply);
195 ErrPrint("Failed to send reply packet: %d\n", ret);
198 packet_destroy(reply);
201 ErrPrint("TCB is already terminated\n");
204 packet_unref(item->packet);
208 s_info.launch_timer = NULL;
209 s_info.svc_daemon_is_launched = 0;
210 s_info.svc_daemon_pid = -1;
211 return -ECANCELED; /* Delete this timer */
214 static int launch_svc(struct service_context *svc_ctx)
217 int ret = LB_STATUS_SUCCESS;
219 pid = aul_launch_app(SVC_PKG, NULL);
221 //case AUL_R_EHIDDENFORGUEST: /**< App hidden for guest mode */
222 case AUL_R_ENOLAUNCHPAD: /**< no launchpad */
223 case AUL_R_EILLACC: /**< Illegal Access */
224 case AUL_R_EINVAL: /**< Invalid argument */
225 case AUL_R_ENOINIT: /**< AUL handler NOT initialized */
226 case AUL_R_ERROR: /**< General error */
227 ErrPrint("Failed to launch an app: %s(%d)\n", SVC_PKG, pid);
228 ret = LB_STATUS_ERROR_FAULT;
230 case AUL_R_ETIMEOUT: /**< Timeout */
231 case AUL_R_ECOMM: /**< Comunication Error */
232 case AUL_R_ETERMINATING: /**< application terminating */
233 case AUL_R_ECANCELED: /**< Operation canceled */
234 /* Need time to launch app again */
235 ErrPrint("Terminating now, try to launch this after few sec later: %s(%d)\n", SVC_PKG, pid);
236 s_info.svc_daemon_is_launched = 1;
237 s_info.delay_launcher = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, lazy_launcher_cb, NULL);
238 if (!s_info.delay_launcher) {
239 ErrPrint("Unable to add delay launcher\n");
240 ret = LB_STATUS_ERROR_FAULT;
243 case AUL_R_LOCAL: /**< Launch by himself */
244 case AUL_R_OK: /**< General success */
246 DbgPrint("Launched: %s(%d)\n", SVC_PKG, pid);
247 s_info.svc_daemon_is_launched = 1;
248 s_info.svc_daemon_pid = pid;
249 s_info.launch_timer = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, launch_timeout_cb, NULL);
250 if (!s_info.launch_timer) {
251 ErrPrint("Unable to create launch timer\n");
258 static int lazy_launcher_cb(struct service_context *svc_ctx, void *data)
260 s_info.delay_launcher = NULL;
262 (void)launch_svc(svc_ctx);
266 static int ttl_timer_cb(struct service_context *svc_ctx, void *data)
268 DbgPrint("TTL Timer is expired: PID(%d)\n", s_info.svc_daemon_pid);
269 (void)aul_terminate_pid(s_info.svc_daemon_pid);
271 s_info.ttl_timer = NULL;
272 s_info.svc_daemon_is_launched = 0;
273 s_info.svc_daemon_pid = -1;
274 s_info.svc_daemon = NULL;
278 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
280 struct packet *reply;
285 DbgPrint("TCB %p is terminated (NIL packet), %d\n", tcb, s_info.svc_daemon_pid);
287 if (tcb == s_info.svc_daemon) {
288 s_info.svc_daemon = NULL;
289 s_info.svc_daemon_is_launched = 0;
290 s_info.svc_daemon_pid = -1;
292 if (s_info.ttl_timer) {
293 service_common_del_timer(tcb_svc_ctx(tcb), s_info.ttl_timer);
294 s_info.ttl_timer = NULL;
298 return LB_STATUS_SUCCESS;
301 cmd = packet_command(packet);
303 ErrPrint("Invalid packet\n");
304 return LB_STATUS_ERROR_INVALID;
307 switch (packet_type(packet)) {
309 if (!s_info.svc_daemon_is_launched) {
310 ret = launch_svc(tcb_svc_ctx(tcb));
311 if (ret != LB_STATUS_SUCCESS) {
316 if (!s_info.svc_daemon) {
317 ret = put_pended_request(tcb, packet);
321 } else if (tcb_is_valid(s_info.svc_ctx, s_info.svc_daemon) >= 0) {
322 ret = service_common_unicast_packet(s_info.svc_daemon, packet);
327 put_reply_tcb(tcb, packet_seq(packet));
329 if (s_info.ttl_timer && service_common_update_timer(s_info.ttl_timer, TTL_TIMEOUT) < 0) {
330 ErrPrint("Failed to update timer\n");
335 case PACKET_REQ_NOACK:
336 if (!strcmp(cmd, "service_register")) {
337 if (!s_info.svc_daemon_is_launched) {
338 ErrPrint("Service daemon is not launched. but something tries to register a service\n");
339 return LB_STATUS_ERROR_INVALID;
342 if (s_info.svc_daemon) {
343 ErrPrint("Service daemon is already prepared\n");
344 return LB_STATUS_ERROR_INVALID;
347 if (s_info.launch_timer) {
348 service_common_del_timer(tcb_svc_ctx(tcb), s_info.launch_timer);
349 s_info.launch_timer = NULL;
352 s_info.ttl_timer = service_common_add_timer(tcb_svc_ctx(tcb), TTL_TIMEOUT, ttl_timer_cb, NULL);
353 if (!s_info.ttl_timer) {
354 ErrPrint("Failed to add TTL timer\n");
355 if (s_info.svc_daemon_pid > 0) {
356 ret = aul_terminate_pid(s_info.svc_daemon_pid);
357 ErrPrint("Terminate: %d\n", ret);
358 s_info.svc_daemon_pid = -1;
360 s_info.svc_daemon_is_launched = 0;
361 return LB_STATUS_ERROR_FAULT;
363 DbgPrint("TTL Timer is added: %p\n", s_info.ttl_timer);
365 s_info.svc_daemon = tcb;
366 flush_pended_request();
370 tcb = get_reply_tcb(packet_seq(packet));
372 ErrPrint("Unable to find reply tcb\n");
376 if (tcb_is_valid(s_info.svc_ctx, tcb) < 0) {
377 ErrPrint("TCB is not valid\n");
381 ret = service_common_unicast_packet(tcb, packet);
383 ErrPrint("Unable to forward the reply packet\n");
387 ErrPrint("Packet type is not valid[%s]\n", cmd);
388 return LB_STATUS_ERROR_INVALID;
391 return LB_STATUS_SUCCESS;
394 ErrPrint("Error: %d\n", ret);
395 reply = packet_create_reply(packet, "i", ret);
396 if (service_common_unicast_packet(tcb, reply) < 0) {
397 ErrPrint("Unable to send reply packet\n");
399 packet_destroy(reply);
403 int utility_service_init(void)
405 if (s_info.svc_ctx) {
406 ErrPrint("Already initialized\n");
407 return LB_STATUS_ERROR_ALREADY;
410 s_info.svc_ctx = service_common_create(UTILITY_SOCKET, service_thread_main, NULL);
411 if (!s_info.svc_ctx) {
412 ErrPrint("Unable to activate service thread\n");
413 return LB_STATUS_ERROR_FAULT;
416 if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), UTILITY_SMACK_LABEL, SMACK_LABEL_IPOUT) != 0) {
417 if (errno != EOPNOTSUPP) {
418 ErrPrint("Unable to set SMACK label(%d)\n", errno);
419 service_common_destroy(s_info.svc_ctx);
420 s_info.svc_ctx = NULL;
421 return LB_STATUS_ERROR_FAULT;
425 if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), UTILITY_SMACK_LABEL, SMACK_LABEL_IPIN) != 0) {
426 if (errno != EOPNOTSUPP) {
427 ErrPrint("Unable to set SMACK label(%d)\n", errno);
428 service_common_destroy(s_info.svc_ctx);
429 s_info.svc_ctx = NULL;
430 return LB_STATUS_ERROR_FAULT;
434 DbgPrint("Successfully initiated\n");
435 return LB_STATUS_SUCCESS;
438 int utility_service_fini(void)
440 if (!s_info.svc_ctx) {
441 return LB_STATUS_ERROR_INVALID;
444 service_common_destroy(s_info.svc_ctx);
445 s_info.svc_ctx = NULL;
446 DbgPrint("Successfully Finalized\n");
447 return LB_STATUS_SUCCESS;