Code sync
[apps/native/starter.git] / src / menu_daemon.c
1  /*
2   * Copyright 2012  Samsung Electronics Co., Ltd
3   *
4   * Licensed under the Flora License, Version 1.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.tizenopensource.org/license
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
18
19 #include <ail.h>
20 #include <aul.h>
21 #include <db-util.h>
22 #include <Elementary.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <sysman.h>
26 #include <syspopup_caller.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <vconf.h>
30 #include <errno.h>
31
32 #include "hw_key.h"
33 #include "pkg_event.h"
34 #include "util.h"
35 #include "xmonitor.h"
36
37
38 int errno;
39
40
41 #define QUERY_UPDATE_NAME "UPDATE app_info SET name='%s' where package='%s';"
42 #define SAT_DESKTOP_FILE "/opt/share/applications/org.tizen.sat-ui.desktop"
43 #define RELAUNCH_INTERVAL 100*1000
44 #define RETRY_MAXCOUNT 30
45
46
47
48 // Define prototype of the "hidden API of AUL"
49 //extern int aul_listen_app_dead_signal(int (*func)(int signal, void *data), void *data);
50
51
52
53 static struct info {
54         pid_t home_pid;
55         pid_t volume_pid;
56         int power_off;
57 } s_info = {
58         .home_pid = -1,
59         .volume_pid = -1,
60         .power_off = 0,
61 };
62
63
64
65 bool menu_daemon_is_homescreen(pid_t pid)
66 {
67         if (s_info.home_pid == pid) return true;
68         return false;
69 }
70
71
72
73 static inline char *_get_selected_pkgname(void)
74 {
75         char *pkgname;
76
77         pkgname = vconf_get_str(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME);
78         if (!pkgname) {
79                 _E("Cannot get pkgname from vconf.");
80
81                 pkgname = strdup(HOME_SCREEN_PKG_NAME);
82                 if (!pkgname) {
83                         _E("strdup error for pkgname, %s", strerror(errno));
84                         return NULL;
85                 }
86         }
87
88         return pkgname;
89 }
90
91
92
93 static inline void _open_homescreen(const char *pkgname)
94 {
95         int ret;
96         char *homescreen = (char *) pkgname;
97
98         system("echo -e '[${_G}menu-daemon launches home-screen${C_}]' > /dev/kmsg");
99         ret = aul_open_app(homescreen);
100         _D("can%s launch %s now. (%d)", ret < 0 ? "not" : "", homescreen, ret);
101         if (ret < 0 && strcmp(homescreen, HOME_SCREEN_PKG_NAME)) {
102                 _E("cannot launch package %s", homescreen);
103
104                 if (-1 == ret) { // -1 : AUL returns '-1' when there is no package name in DB.
105                         ret = aul_open_app(HOME_SCREEN_PKG_NAME);
106                         if (ret < 0) {
107                                 _E("Failed to open a default home, %s(err:%d)", HOME_SCREEN_PKG_NAME, ret);
108                         }
109                 }
110         }
111
112         s_info.home_pid = ret;
113         if (ret > 0) {
114                 if (-1 == sysconf_set_mempolicy_bypid(ret, OOM_IGNORE)) {
115                         _E("Cannot set the memory policy for Home-screen(%d)", ret);
116                 } else {
117                         _E("Set the memory policy for Home-screen(%d)", ret);
118                 }
119         }
120 }
121
122
123
124 static void _show_cb(keynode_t* node, void *data)
125 {
126         int seq;
127         char *pkgname;
128
129         _D("[MENU_DAEMON] _show_cb is invoked");
130
131         pkgname = _get_selected_pkgname();
132         if (!pkgname)
133                 return;
134
135         if (node) {
136                 seq = vconf_keynode_get_int(node);
137         } else {
138                 if (vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &seq) < 0) {
139                         _E("Failed to get sequence info");
140                         free(pkgname);
141                         return;
142                 }
143         }
144
145         switch (seq) {
146                 case 0:
147                         if (s_info.home_pid > 0) {
148                                 int pid;
149                                 _D("pid[%d] is terminated.", s_info.home_pid);
150
151                                 pid = s_info.home_pid;
152                                 s_info.home_pid = -1; /* to freeze the dead_cb */
153
154                                 if (aul_terminate_pid(pid) != AUL_R_OK)
155                                         _E("Failed to terminate %d", s_info.home_pid);
156                         }
157                         break;
158                 case 1:
159                         _open_homescreen(pkgname);
160                         break;
161                 default:
162                         _E("False sequence [%d]", seq);
163                         break;
164         }
165
166         free(pkgname);
167         return;
168
169 }
170
171
172
173 static void _pkg_changed(keynode_t* node, void *data)
174 {
175         char *pkgname;
176         int seq;
177
178         if (vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &seq) < 0) {
179                 _E("Do nothing, there is no sequence info yet");
180                 return;
181         }
182
183         if (seq < 1) {
184                 _E("Sequence is not ready yet, do nothing");
185                 return;
186         }
187
188         _D("_pkg_changed is invoked");
189
190         pkgname = _get_selected_pkgname();
191         if (!pkgname)
192                 return;
193
194         _D("pkg_name : %s", pkgname);
195
196         if (s_info.home_pid > 0) {
197                 char old_pkgname[256];
198
199                 if (aul_app_get_pkgname_bypid(s_info.home_pid, old_pkgname, sizeof(old_pkgname)) == AUL_R_OK) {
200                         if (!strcmp(pkgname, old_pkgname)) {
201                                 _D("Package is changed but same package is selected");
202                                 free(pkgname);
203                                 return;
204                         }
205                 }
206
207                 if (aul_terminate_pid(s_info.home_pid) != AUL_R_OK)
208                         _D("Failed to terminate pid %d", s_info.home_pid);
209         } else {
210                 /* If there is no running home */
211                 _open_homescreen(pkgname);
212         }
213
214         /* NOTE: Dead callback will catch the termination of a current menuscreen 
215          * _open_homescreen(pkgname);
216          */
217         free(pkgname);
218         return;
219 }
220
221 static void _launch_volume(void)
222 {
223         int pid;
224         int i;
225         _D("_launch_volume");
226
227         for (i=0; i<RETRY_MAXCOUNT; i++)
228         {
229                 pid = syspopup_launch("volume", NULL);
230
231                 _D("syspopup_launch(volume), pid = %d", pid);
232
233                 if (pid <0) {
234                         _D("syspopup_launch(volume)is failed [%d]times", i);
235                         usleep(RELAUNCH_INTERVAL);
236                 } else {
237                         s_info.volume_pid = pid;
238                         return;
239                 }
240         }
241 }
242
243 int menu_daemon_check_dead_signal(int pid)
244 {
245         char *pkgname;
246
247         if (s_info.power_off) {
248                 _D("Power off. ignore dead cb\n");
249                 return 0;
250         }
251
252         _D("Process %d is termianted", pid);
253
254         if (pid < 0)
255                 return 0;
256
257         pkgname = _get_selected_pkgname();
258         if (!pkgname)
259                 return 0;
260
261         if (pid == s_info.home_pid) {
262                 /* Relaunch */
263                 _D("pkg_name : %s", pkgname);
264                 _open_homescreen(pkgname);
265         } else if (pid == s_info.volume_pid) {
266                 /* Relaunch */
267                 _launch_volume();
268         } else {
269                 _D("Unknown process, ignore it (pid %d, home pid %d)",
270                                 pid, s_info.home_pid);
271         }
272
273         free(pkgname);
274
275         return 0;
276 }
277
278
279
280 void menu_daemon_init(void *data)
281 {
282         _D( "[MENU_DAEMON]menu_daemon_init is invoked");
283
284         aul_launch_init(NULL,NULL);
285
286         create_key_window();
287         if (xmonitor_init() < 0) _E("cannot init xmonitor");
288
289         pkg_event_init();
290         _launch_volume();
291
292         if (unlink(SAT_DESKTOP_FILE) != 0)
293                 _E("cannot remove sat-ui desktop.");
294
295         if (vconf_notify_key_changed(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, _pkg_changed, NULL) < 0)
296                 _E("Failed to add callback for package change event");
297
298         if (vconf_notify_key_changed(VCONFKEY_STARTER_SEQUENCE, _show_cb, NULL) < 0)
299                 _E("Failed to add callback for show event");
300
301         _pkg_changed(NULL, NULL);
302         // THIS ROUTINE IS FOR SAT.
303         vconf_set_int(VCONFKEY_IDLE_SCREEN_LAUNCHED, VCONFKEY_IDLE_SCREEN_LAUNCHED_TRUE);
304 }
305
306
307
308 void menu_daemon_fini(void)
309 {
310         vconf_ignore_key_changed(VCONFKEY_STARTER_SEQUENCE, _show_cb);
311         vconf_ignore_key_changed(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, _pkg_changed);
312
313         xmonitor_fini();
314         pkg_event_fini();
315         destroy_key_window();
316 }
317
318
319
320 // End of a file