2c0a8a5cbc65724bda5d3c4d611e864c6dd2c2f8
[platform/core/appfw/app-core.git] / src / appcore-efl.c
1 /*
2  * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <sys/un.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <stdlib.h>
26
27 #include <Ecore_Wayland.h>
28 #include <wayland-client.h>
29 #include <wayland-tbm-client.h>
30 #include <tizen-extension-client-protocol.h>
31
32 #include <Ecore.h>
33 #include <Ecore_Evas.h>
34 #include <Ecore_Input_Evas.h>
35 #include <Elementary.h>
36 #include <glib-object.h>
37 #include <malloc.h>
38 #include <glib.h>
39 #include <gio/gio.h>
40 #include <stdbool.h>
41 #include <aul.h>
42 #include <aul_svc.h>
43 #include <bundle_internal.h>
44 #include <ttrace.h>
45
46 #include "appcore-internal.h"
47 #include "appcore-efl.h"
48 #include <system_info.h>
49
50 static pid_t _pid;
51 static bool resource_reclaiming = TRUE;
52 static int tmp_val = 0;
53
54 struct ui_priv {
55         const char *name;
56         enum app_state state;
57
58         Ecore_Event_Handler *hshow;
59         Ecore_Event_Handler *hhide;
60         Ecore_Event_Handler *hvchange;
61         Ecore_Event_Handler *hlower;
62         Ecore_Event_Handler *hcmsg; /* WM_ROTATE */
63
64         Ecore_Timer *mftimer; /* Ecore Timer for memory flushing */
65
66         struct appcore *app_core;
67         void (*prepare_to_suspend) (void *data);
68         void (*exit_from_suspend) (void *data);
69         struct appcore_ops *ops;
70         void (*mfcb) (void); /* Memory Flushing Callback */
71
72         /* WM_ROTATE */
73         int wm_rot_supported;
74         int rot_started;
75         int (*rot_cb) (void *event_info, enum appcore_rm, void *);
76         void *rot_cb_data;
77         enum appcore_rm rot_mode;
78         bundle *pending_data;
79         char *below_app;
80 };
81
82 static struct ui_priv priv;
83
84 static const char *_ae_name[AE_MAX] = {
85         [AE_UNKNOWN] = "UNKNOWN",
86         [AE_CREATE] = "CREATE",
87         [AE_TERMINATE] = "TERMINATE",
88         [AE_PAUSE] = "PAUSE",
89         [AE_RESUME] = "RESUME",
90         [AE_RESET] = "RESET",
91         [AE_LOWMEM_POST] = "LOWMEM_POST",
92         [AE_MEM_FLUSH] = "MEM_FLUSH",
93         [AE_UPDATE_REQUESTED] = "UPDATE_REQUESTED",
94 };
95
96 static const char *_as_name[] = {
97         [AS_NONE] = "NONE",
98         [AS_CREATED] = "CREATED",
99         [AS_RUNNING] = "RUNNING",
100         [AS_PAUSED] = "PAUSED",
101         [AS_DYING] = "DYING",
102 };
103
104 static bool b_active = FALSE;
105 static bool first_launch = TRUE;
106
107 struct win_node {
108         unsigned int win;
109         unsigned int surf;
110         bool bfobscured;
111 };
112
113 static Eina_Bool __visibility_cb(void *data, int type, void *event);
114 static GSList *g_winnode_list;
115
116 static struct wl_display *dsp;
117 static struct wl_registry *reg;
118 static struct tizen_policy *tz_policy;
119 static bool bg_state = false;
120
121 static void __wl_listener_cb(void *data, struct wl_registry *reg,
122                 uint32_t id, const char *interface, uint32_t ver)
123 {
124         if (interface && !strcmp(interface, "tizen_policy")) {
125                 if (!tz_policy)
126                         tz_policy = wl_registry_bind(reg, id,
127                                         &tizen_policy_interface, 1);
128         }
129 }
130
131 static void __wl_listener_remove_cb(void *data, struct wl_registry *reg,
132                 unsigned int id)
133 {
134         /* do nothing */
135 }
136
137 static const struct wl_registry_listener reg_listener = {
138         __wl_listener_cb,
139         __wl_listener_remove_cb
140 };
141
142 static int __init_wl(void)
143 {
144         _DBG("initialize wayland");
145         dsp = wl_display_connect(NULL);
146         if (dsp == NULL) {
147                 _ERR("Failed to connect wl display");
148                 return -1;
149         }
150
151         reg = wl_display_get_registry(dsp);
152         if (reg == NULL) {
153                 _ERR("Failed to get registry");
154                 wl_display_disconnect(dsp);
155                 return -1;
156         }
157
158         wl_registry_add_listener(reg, &reg_listener, NULL);
159         wl_display_roundtrip(dsp);
160
161         if (!tz_policy) {
162                 _ERR("Failed to get tizen policy interface");
163                 wl_registry_destroy(reg);
164                 wl_display_disconnect(dsp);
165                 return -1;
166         }
167
168         return 0;
169 }
170
171 static void __finish_wl(void)
172 {
173         if (tz_policy) {
174                 tizen_policy_destroy(tz_policy);
175                 tz_policy = NULL;
176         }
177
178         if (reg) {
179                 wl_registry_destroy(reg);
180                 reg = NULL;
181         }
182
183         if (dsp) {
184                 wl_display_disconnect(dsp);
185                 dsp = NULL;
186         }
187 }
188
189 static void __set_bg_state(void)
190 {
191         if (__init_wl() < 0)
192                 return;
193
194         tizen_policy_set_background_state(tz_policy, getpid());
195         wl_display_roundtrip(dsp);
196         bg_state = true;
197         _DBG("bg state: %d", bg_state);
198 }
199
200 static void __unset_bg_state(void)
201 {
202         if (!tz_policy)
203                 return;
204
205         tizen_policy_unset_background_state(tz_policy, getpid());
206         wl_display_roundtrip(dsp);
207         bg_state = false;
208         _DBG("bg state: %d", bg_state);
209         __finish_wl();
210 }
211
212 static void __appcore_efl_prepare_to_suspend(void *data)
213 {
214         struct ui_priv *ui = (struct ui_priv *)data;
215         struct sys_op *op = NULL;
216         int suspend = APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
217
218         if (ui->app_core && !ui->app_core->allowed_bg && !ui->app_core->suspended_state) {
219                 op = &ui->app_core->sops[SE_SUSPENDED_STATE];
220                 if (op && op->func)
221                         op->func((void *)&suspend, op->data); /* calls c-api handler */
222
223                 ui->app_core->suspended_state = true;
224         }
225         _DBG("[__SUSPEND__]");
226 }
227
228 static void __appcore_efl_exit_from_suspend(void *data)
229 {
230         struct ui_priv *ui = (struct ui_priv *)data;
231         struct sys_op *op = NULL;
232         int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
233
234         if (ui->app_core && !ui->app_core->allowed_bg && ui->app_core->suspended_state) {
235                 op = &ui->app_core->sops[SE_SUSPENDED_STATE];
236                 if (op && op->func)
237                         op->func((void *)&suspend, op->data); /* calls c-api handler */
238
239                 ui->app_core->suspended_state = false;
240         }
241         _DBG("[__SUSPEND__]");
242 }
243
244 static void __appcore_efl_update_requested(void *data)
245 {
246         struct ui_priv *ui = (struct ui_priv *)data;
247         struct sys_op *op;
248         int dummy = 0;
249
250         if (ui->app_core) {
251                 op = &ui->app_core->sops[SE_UPDATE_REQUESTED];
252                 if (op && op->func)
253                         op->func((void *)&dummy, op->data);
254         }
255         _DBG("[__UPDATE_REQUESTED__]");
256 }
257
258 #if defined(MEMORY_FLUSH_ACTIVATE)
259 static Eina_Bool __appcore_memory_flush_cb(void *data)
260 {
261         struct ui_priv *ui = (struct ui_priv *)data;
262
263         appcore_flush_memory();
264         if (ui)
265                 ui->mftimer = NULL;
266
267         if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT && ui && ui->prepare_to_suspend) {
268                 _DBG("[__SUSPEND__] flush case");
269                 ui->prepare_to_suspend(ui);
270         }
271
272         return ECORE_CALLBACK_CANCEL;
273 }
274
275 static int __appcore_low_memory_post_cb(struct ui_priv *ui)
276 {
277         if (ui->state == AS_PAUSED)
278                 appcore_flush_memory();
279         else
280                 malloc_trim(0);
281
282         return 0;
283 }
284
285 static void __appcore_timer_add(struct ui_priv *ui)
286 {
287         ui->mftimer = ecore_timer_add(5, __appcore_memory_flush_cb, ui);
288 }
289
290 static void __appcore_timer_del(struct ui_priv *ui)
291 {
292         if (ui->mftimer) {
293                 ecore_timer_del(ui->mftimer);
294                 ui->mftimer = NULL;
295         }
296 }
297
298 #else
299
300 static int __appcore_low_memory_post_cb(ui_priv *ui)
301 {
302         return -1;
303 }
304
305 #define __appcore_timer_add(ui) 0
306 #define __appcore_timer_del(ui) 0
307
308 #endif
309
310 static void __appcore_efl_memory_flush_cb(void)
311 {
312         _DBG("[APP %d]   __appcore_efl_memory_flush_cb()", _pid);
313         elm_cache_all_flush();
314 }
315 static void wl_raise_win(void)
316 {
317         Ecore_Wl_Window *win;
318         unsigned int win_id = appcore_get_main_window();
319
320         _DBG("Raise window: %d", win_id);
321         win = ecore_wl_window_find(win_id);
322         ecore_wl_window_activate(win);
323 }
324
325 static void wl_pause_win(void)
326 {
327         Ecore_Wl_Window *win;
328         GSList *wlist = g_winnode_list;
329         struct win_node *entry = NULL;
330
331         _DBG("Pause window");
332
333         while (wlist) {
334                 entry = wlist->data;
335
336                 _DBG("Pause window: %d", entry->win);
337                 win = ecore_wl_window_find(entry->win);
338                 ecore_wl_window_iconified_set(win, EINA_TRUE);
339
340                 wlist = wlist->next;
341         }
342 }
343
344
345 static void __do_app(enum app_event event, void *data, bundle * b)
346 {
347         int r = -1;
348         struct ui_priv *ui = data;
349         const char *below_app;
350         const char *bg_launch;
351
352         _DBG("[APP %d] Event: %d", _pid, event);
353         _ret_if(ui == NULL || event >= AE_MAX);
354         _DBG("[APP %d] Event: %s State: %s", _pid, _ae_name[event],
355              _as_name[ui->state]);
356
357         if (event == AE_MEM_FLUSH) {
358                 ui->mfcb();
359                 return;
360         }
361
362         if (event == AE_LOWMEM_POST) {
363                 if (__appcore_low_memory_post_cb(ui) == 0)
364                         return;
365         }
366
367         if (!(ui->state == AS_PAUSED && event == AE_PAUSE))
368                 __appcore_timer_del(ui);
369
370         if (ui->state == AS_DYING) {
371                 _ERR("Skip the event in dying state");
372                 return;
373         }
374
375         if (event == AE_TERMINATE) {
376                 _DBG("[APP %d] TERMINATE", _pid);
377                 elm_exit();
378                 aul_status_update(STATUS_DYING);
379                 return;
380         }
381
382         if (event == AE_RAISE) {
383                 wl_raise_win();
384                 return;
385         }
386
387         if (event == AE_LOWER) {
388                 wl_pause_win();
389                 return;
390         }
391
392         _ret_if(ui->ops == NULL);
393
394         switch (event) {
395         case AE_RESET:
396                 _DBG("[APP %d] RESET", _pid);
397                 if (ui->pending_data)
398                         bundle_free(ui->pending_data);
399                 ui->pending_data = bundle_dup(b);
400                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", ui->name);
401
402                 if (ui->below_app) {
403                         free(ui->below_app);
404                         ui->below_app = NULL;
405                 }
406
407                 below_app = bundle_get_val(b, AUL_SVC_K_RELOCATE_BELOW);
408                 if (below_app)
409                         ui->below_app = strdup(below_app);
410                 if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT && ui->exit_from_suspend) {
411                         _DBG("[__SUSPEND__] reset case");
412                         ui->exit_from_suspend(ui);
413                 }
414
415                 if (ui->ops->reset) {
416                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
417                                         "APPCORE:RESET");
418                         r = ui->ops->reset(b, ui->ops->data);
419                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
420                 }
421                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", ui->name);
422
423                 if (first_launch) {
424                         if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT && ui->app_core->allowed_bg)
425                                 __appcore_timer_add(ui);
426                         first_launch = FALSE;
427                 } else {
428                         _INFO("[APP %d] App already running, raise the window", _pid);
429                         if (bg_state) {
430                                 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
431                                 if (!bg_launch || strcmp(bg_launch, "enable"))
432                                         __unset_bg_state();
433                         }
434                         wl_raise_win();
435                 }
436                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]",
437                     ui->name);
438                 break;
439         case AE_PAUSE:
440                 if (ui->state == AS_RUNNING) {
441                         _DBG("[APP %d] PAUSE", _pid);
442                         if (ui->ops->pause) {
443                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
444                                                 "APPCORE:PAUSE");
445                                 r = ui->ops->pause(ui->ops->data);
446                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
447                         }
448                         ui->state = AS_PAUSED;
449                         if (r >= 0 && resource_reclaiming == TRUE)
450                                 __appcore_timer_add(ui);
451                         else if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT && r >= 0 && resource_reclaiming == FALSE
452                                         && ui->prepare_to_suspend) {
453                                 _DBG("[__SUSPEND__] pause case");
454                                 ui->prepare_to_suspend(ui);
455                         }
456                 }
457                 /* TODO : rotation stop */
458                 /* r = appcore_pause_rotation_cb(); */
459                 aul_status_update(STATUS_BG);
460                 break;
461         case AE_RESUME:
462                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]",
463                                 ui->name);
464                 if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT) {
465                         if (ui->exit_from_suspend) {
466                                 _DBG("[__SUSPEND__] resume case");
467                                 ui->exit_from_suspend(ui);
468                         }
469                         if (ui->app_core->allowed_bg)
470                                 __appcore_timer_del(ui);
471                 }
472
473                 if (ui->state == AS_PAUSED || ui->state == AS_CREATED) {
474                         _DBG("[APP %d] RESUME", _pid);
475
476                         if (ui->state == AS_CREATED) {
477                                 bundle_free(ui->pending_data);
478                                 ui->pending_data = NULL;
479                         }
480
481                         if (ui->ops->resume) {
482                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
483                                         "APPCORE:RESUME");
484                                 ui->ops->resume(ui->ops->data);
485                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
486                         }
487                         ui->state = AS_RUNNING;
488
489                         if (ui->below_app) {
490                                 aul_app_group_activate_below(ui->below_app);
491                                 free(ui->below_app);
492                                 ui->below_app = NULL;
493                         }
494                 }
495                 /*TODO : rotation start*/
496                 /* r = appcore_resume_rotation_cb(); */
497                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]",
498                     ui->name);
499                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]",
500                     ui->name);
501                 aul_status_update(STATUS_VISIBLE);
502                 break;
503         case AE_TERMINATE_BGAPP:
504                 if (ui->state == AS_PAUSED) {
505                         _DBG("[APP %d] is paused. TERMINATE", _pid);
506                         ui->state = AS_DYING;
507                         aul_status_update(STATUS_DYING);
508                         elm_exit();
509                 } else if (ui->state == AS_RUNNING) {
510                         _DBG("[APP %d] is running.", _pid);
511                 } else {
512                         _DBG("[APP %d] is another state", _pid);
513                 }
514                 break;
515         case AE_UPDATE_REQUESTED:
516                 __appcore_efl_update_requested(ui);
517                 break;
518         default:
519                 /* do nothing */
520                 break;
521         }
522 }
523
524 static struct ui_ops efl_ops = {
525         .data = &priv,
526         .cb_app = __do_app,
527 };
528
529 static bool __check_visible(void)
530 {
531         GSList *iter = NULL;
532         struct win_node *entry = NULL;
533
534         _DBG("[EVENT_TEST][EVENT] __check_visible\n");
535
536         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
537                 entry = iter->data;
538                 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
539                 if (entry->bfobscured == FALSE)
540                         return TRUE;
541         }
542
543         return FALSE;
544 }
545
546 static GSList *__find_win(unsigned int win)
547 {
548         GSList *iter;
549         struct win_node *t;
550
551         for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
552                 t = iter->data;
553                 if (t && t->win == win)
554                         return iter;
555         }
556
557         return NULL;
558 }
559
560 static bool __add_win(unsigned int win, unsigned int surf)
561 {
562         struct win_node *t;
563         GSList *f;
564
565         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
566
567         f = __find_win(win);
568         if (f) {
569                 errno = ENOENT;
570                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
571                 return FALSE;
572         }
573
574         t = calloc(1, sizeof(struct win_node));
575         if (t == NULL)
576                 return FALSE;
577
578         t->win = win;
579         t->surf = surf;
580         t->bfobscured = FALSE;
581
582         g_winnode_list = g_slist_append(g_winnode_list, t);
583
584         return TRUE;
585 }
586
587 static bool __delete_win(unsigned int win)
588 {
589         GSList *f;
590
591         f = __find_win(win);
592         if (!f) {
593                 errno = ENOENT;
594                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
595                                 win);
596                 return FALSE;
597         }
598
599         free(f->data);
600         g_winnode_list = g_slist_delete_link(g_winnode_list, f);
601
602         return TRUE;
603 }
604
605 static bool __update_win(unsigned int win, unsigned int surf, bool bfobscured)
606 {
607         GSList *f;
608         struct win_node *t;
609
610         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
611              bfobscured);
612
613         f = __find_win(win);
614         if (!f) {
615                 errno = ENOENT;
616                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
617                 return FALSE;
618         }
619
620         t = (struct win_node *)f->data;
621         t->win = win;
622         if (surf != 0)
623                 t->surf = surf;
624         t->bfobscured = bfobscured;
625
626         return TRUE;
627 }
628
629 static Eina_Bool __show_cb(void *data, int type, void *event)
630 {
631         Ecore_Wl_Event_Window_Show *ev;
632
633         ev = event;
634         if (ev->parent_win != 0) {
635                 /* This is child window. Skip!!! */
636                 return ECORE_CALLBACK_PASS_ON;
637         }
638
639         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n", ev->win, ev->data[0]);
640
641         if (!__find_win((unsigned int)ev->win))
642                 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
643         else
644                 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0], FALSE);
645
646
647         appcore_group_attach();
648         return ECORE_CALLBACK_RENEW;
649 }
650
651 static Eina_Bool __hide_cb(void *data, int type, void *event)
652 {
653         Ecore_Wl_Event_Window_Hide *ev;
654         int bvisibility = 0;
655
656         ev = event;
657
658         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
659
660         if (__find_win((unsigned int)ev->win)) {
661                 __delete_win((unsigned int)ev->win);
662                 bvisibility = __check_visible();
663                 if (!bvisibility && b_active == TRUE) {
664                         _DBG(" Go to Pasue state \n");
665                         b_active = FALSE;
666                         __do_app(AE_PAUSE, data, NULL);
667                 }
668         }
669
670         return ECORE_CALLBACK_RENEW;
671 }
672
673 static Eina_Bool __lower_cb(void *data, int type, void *event)
674 {
675         Ecore_Wl_Event_Window_Lower *ev;
676         ev = event;
677         if (!ev) return ECORE_CALLBACK_RENEW;
678         _DBG("ECORE_WL_EVENT_WINDOW_LOWER window id:%u\n", ev->win);
679         appcore_group_lower();
680         return ECORE_CALLBACK_RENEW;
681 }
682
683 static Eina_Bool __visibility_cb(void *data, int type, void *event)
684 {
685         Ecore_Wl_Event_Window_Visibility_Change *ev;
686         int bvisibility = 0;
687         ev = event;
688         __update_win((unsigned int)ev->win, 0, ev->fully_obscured);
689         bvisibility = __check_visible();
690
691         _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
692
693         if (bvisibility && b_active == FALSE) {
694                 _DBG(" Go to Resume state\n");
695                 b_active = TRUE;
696                 __do_app(AE_RESUME, data, NULL);
697
698         } else if (!bvisibility && b_active == TRUE) {
699                 _DBG(" Go to Pasue state \n");
700                 b_active = FALSE;
701                 __do_app(AE_PAUSE, data, NULL);
702         } else
703                 _DBG(" No change state \n");
704
705         return ECORE_CALLBACK_RENEW;
706
707 }
708
709 static void __add_climsg_cb(struct ui_priv *ui)
710 {
711         _ret_if(ui == NULL);
712         ui->hshow =
713                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW, __show_cb, ui);
714         ui->hhide =
715                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE, __hide_cb, ui);
716         ui->hvchange =
717                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
718                                 __visibility_cb, ui);
719         ui->hlower =
720                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER,
721                                 __lower_cb, ui);
722 }
723
724 static int __before_loop(struct ui_priv *ui, int *argc, char ***argv)
725 {
726         int r;
727         char *hwacc = NULL;
728         struct appcore *ac = NULL;
729         bundle *b;
730         const char *bg_launch;
731
732         if (argc == NULL || argv == NULL) {
733                 _ERR("argc/argv is NULL");
734                 errno = EINVAL;
735                 return -1;
736         }
737
738 #if !(GLIB_CHECK_VERSION(2, 36, 0))
739         g_type_init();
740 #endif
741         elm_init(*argc, *argv);
742
743         hwacc = getenv("HWACC");
744         if (hwacc == NULL) {
745                 _DBG("elm_config_accel_preference_set is not called");
746         } else if (strcmp(hwacc, "USE") == 0) {
747                 elm_config_accel_preference_set("hw");
748                 _DBG("elm_config_accel_preference_set : hw");
749         } else if (strcmp(hwacc, "NOT_USE") == 0) {
750                 elm_config_accel_preference_set("none");
751                 _DBG("elm_config_accel_preference_set : none");
752         } else {
753                 _DBG("elm_config_accel_preference_set is not called");
754         }
755
756         r = appcore_init(ui->name, &efl_ops, *argc, *argv);
757         _retv_if(r == -1, -1);
758
759         if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT) {
760                 appcore_get_app_core(&ac);
761                 ui->app_core = ac;
762                 SECURE_LOGD("[__SUSPEND__] appcore initialized, appcore addr: #%x", ac);
763         }
764
765         b = bundle_import_from_argv(*argc, *argv);
766         if (b) {
767                 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
768                 if (bg_launch && strcmp(bg_launch, "enable") == 0)
769                         __set_bg_state();
770
771                 bundle_free(b);
772         }
773
774         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:appcore_init:done]", ui->name);
775         if (ui->ops && ui->ops->create) {
776                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
777                 r = ui->ops->create(ui->ops->data);
778                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
779                 if (r < 0) {
780                         _ERR("create() return error");
781                         appcore_exit();
782                         if (ui->ops && ui->ops->terminate) {
783                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
784                                         "APPCORE:TERMINATE");
785                                 ui->ops->terminate(ui->ops->data);
786                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
787                         }
788                         errno = ECANCELED;
789                         return -1;
790                 }
791                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]",
792                     ui->name);
793         }
794         ui->state = AS_CREATED;
795
796         __add_climsg_cb(ui);
797
798         return 0;
799 }
800
801 static void __after_loop(struct ui_priv *ui)
802 {
803         appcore_unset_rotation_cb();
804         appcore_exit();
805
806         if (ui->state == AS_RUNNING) {
807                 _DBG("[APP %d] PAUSE before termination", _pid);
808                 if (ui->ops && ui->ops->pause) {
809                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
810                                         "APPCORE:PAUSE");
811                         ui->ops->pause(ui->ops->data);
812                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
813                 }
814         }
815
816         if (ui->ops && ui->ops->terminate) {
817                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
818                 ui->ops->terminate(ui->ops->data);
819                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
820         }
821
822         ui->state = AS_DYING;
823
824         if (ui->hshow)
825                 ecore_event_handler_del(ui->hshow);
826         if (ui->hhide)
827                 ecore_event_handler_del(ui->hhide);
828         if (ui->hvchange)
829                 ecore_event_handler_del(ui->hvchange);
830         if (ui->hlower)
831                 ecore_event_handler_del(ui->hlower);
832
833         __appcore_timer_del(ui);
834
835         elm_shutdown();
836
837         /* Check loader case */
838         if (getenv("AUL_LOADER_INIT")) {
839                 unsetenv("AUL_LOADER_INIT");
840                 elm_shutdown();
841         }
842 }
843
844 static int __set_data(struct ui_priv *ui, const char *name,
845                     struct appcore_ops *ops)
846 {
847         if (ui->name) {
848                 _ERR("Mainloop already started");
849                 errno = EINPROGRESS;
850                 return -1;
851         }
852
853         if (name == NULL || name[0] == '\0') {
854                 _ERR("Invalid name");
855                 errno = EINVAL;
856                 return -1;
857         }
858
859         if (ops == NULL) {
860                 _ERR("ops is NULL");
861                 errno = EINVAL;
862                 return -1;
863         }
864
865         ui->name = strdup(name);
866         _retv_if(ui->name == NULL, -1);
867
868         ui->ops = ops;
869         ui->mfcb = __appcore_efl_memory_flush_cb;
870         _pid = getpid();
871
872         /* WM_ROTATE */
873         ui->wm_rot_supported = 0;
874         ui->rot_started = 0;
875         ui->rot_cb = NULL;
876         ui->rot_cb_data = NULL;
877         ui->rot_mode = APPCORE_RM_UNKNOWN;
878
879         if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT) {
880                 ui->app_core = NULL;
881                 ui->prepare_to_suspend = __appcore_efl_prepare_to_suspend;
882                 ui->exit_from_suspend = __appcore_efl_exit_from_suspend;
883         }
884
885         return 0;
886 }
887
888 static void __unset_data(struct ui_priv *ui)
889 {
890         if (ui->name)
891                 free((void *)ui->name);
892
893         memset(ui, 0, sizeof(struct ui_priv));
894 }
895
896 EXPORT_API int appcore_efl_init(const char *name, int *argc, char ***argv,
897                      struct appcore_ops *ops)
898 {
899         int r;
900
901         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", name);
902
903         r = __set_data(&priv, name, ops);
904         _retv_if(r == -1, -1);
905
906         r = __before_loop(&priv, argc, argv);
907         if (r == -1) {
908                 aul_status_update(STATUS_DYING);
909                 __unset_data(&priv);
910                 return -1;
911         }
912
913         return 0;
914 }
915
916 EXPORT_API void appcore_efl_fini(void)
917 {
918         aul_status_update(STATUS_DYING);
919
920         __after_loop(&priv);
921
922         __unset_data(&priv);
923 }
924
925 EXPORT_API int appcore_efl_main(const char *name, int *argc, char ***argv,
926                                 struct appcore_ops *ops)
927 {
928         int r;
929
930         r = appcore_efl_init(name, argc, argv, ops);
931         _retv_if(r == -1, -1);
932
933         elm_run();
934
935         appcore_efl_fini();
936
937         return 0;
938 }
939
940 EXPORT_API int appcore_set_system_resource_reclaiming(bool enable)
941 {
942         resource_reclaiming = enable;
943
944         return 0;
945 }
946
947 EXPORT_API int appcore_set_app_state(int state)
948 {
949         priv.state = state;
950
951         tmp_val = 1;
952
953         return 0;
954 }
955
956 EXPORT_API int appcore_set_preinit_window_name(const char *win_name)
957 {
958         int ret = -1;
959         void *preinit_window = NULL;
960         const Evas *e = NULL;
961
962         if (!win_name) {
963                 _ERR("invalid parameter");
964                 return ret;
965         }
966
967         preinit_window = elm_win_precreated_object_get();
968         if (!preinit_window) {
969                 _ERR("Failed to get preinit window");
970                 return ret;
971         }
972
973         e = evas_object_evas_get((const Evas_Object *)preinit_window);
974         if (e) {
975                 Ecore_Evas *ee = ecore_evas_ecore_evas_get(e);
976                 if (ee) {
977                         ecore_evas_name_class_set(ee, win_name, win_name);
978                         ret = 0;
979                 }
980         }
981
982         return ret;
983 }
984
985 EXPORT_API unsigned int appcore_get_main_window(void)
986 {
987         struct win_node *entry = NULL;
988
989         if (g_winnode_list != NULL) {
990                 entry = g_winnode_list->data;
991                 return (unsigned int) entry->win;
992         }
993
994         return 0;
995 }
996
997 EXPORT_API unsigned int appcore_get_main_surface(void)
998 {
999         struct win_node *entry = NULL;
1000
1001         if (g_winnode_list != NULL) {
1002                 entry = g_winnode_list->data;
1003                 return (unsigned int) entry->surf;
1004         }
1005
1006         return 0;
1007 }
1008
1009 tizen_profile_t _get_tizen_profile()
1010 {
1011         static tizen_profile_t profile = TIZEN_PROFILE_UNKNOWN;
1012         if (__builtin_expect(profile != TIZEN_PROFILE_UNKNOWN, 1))
1013                 return profile;
1014
1015         char *profileName;
1016         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
1017         switch (*profileName) {
1018         case 'm':
1019         case 'M':
1020                 profile = TIZEN_PROFILE_MOBILE;
1021                 break;
1022         case 'w':
1023         case 'W':
1024                 profile = TIZEN_PROFILE_WEARABLE;
1025                 break;
1026         case 't':
1027         case 'T':
1028                 profile = TIZEN_PROFILE_TV;
1029                 break;
1030         case 'i':
1031         case 'I':
1032                 profile = TIZEN_PROFILE_IVI;
1033                 break;
1034         default: // common or unTIZEN_nown ==> ALL ARE COMMON.
1035                 profile = TIZEN_PROFILE_COMMON;
1036         }
1037         free(profileName);
1038
1039         return profile;
1040 }