Apply smack rule.
[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.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
7   *
8   *     http://floralicense.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 <errno.h>
24 #include <fcntl.h>
25 #include <pkgmgr-info.h>
26 #include <stdio.h>
27 #include <sysman.h>
28 #include <syspopup_caller.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32 #include <vconf.h>
33
34 #include "hw_key.h"
35 #include "pkg_event.h"
36 #include "util.h"
37 #include "xmonitor.h"
38
39
40 int errno;
41
42
43 #define QUERY_UPDATE_NAME "UPDATE app_info SET name='%s' where package='%s';"
44 #define SAT_DESKTOP_FILE "/opt/share/applications/org.tizen.sat-ui.desktop"
45 #define RELAUNCH_INTERVAL 100*1000
46 #define RETRY_MAXCOUNT 30
47
48 static struct info {
49         pid_t home_pid;
50         pid_t volume_pid;
51         int power_off;
52 } s_info = {
53         .home_pid = -1,
54         .volume_pid = -1,
55         .power_off = 0,
56 };
57
58
59
60 #define RETRY_COUNT 5
61 int menu_daemon_open_app(const char *pkgname)
62 {
63         register int i;
64         int r = AUL_R_ETIMEOUT;
65         for (i = 0; AUL_R_ETIMEOUT == r && i < RETRY_COUNT; i ++) {
66                 r = aul_open_app(pkgname);
67                 if (0 <= r) return r;
68                 else {
69                         _D("aul_open_app error(%d)", r);
70                         _F("cannot open an app(%s) by %d", pkgname, r);
71                 }
72                 usleep(500000);
73         }
74
75         return r;
76 }
77
78
79
80 int menu_daemon_launch_app(const char *pkgname, bundle *b)
81 {
82         register int i;
83         int r = AUL_R_ETIMEOUT;
84         for (i = 0; AUL_R_ETIMEOUT == r && i < RETRY_COUNT; i ++) {
85                 r = aul_launch_app(pkgname, b);
86                 if (0 <= r) return r;
87                 else {
88                         _D("aul_launch_app error(%d)", r);
89                         _F("cannot launch an app(%s) by %d", pkgname, r);
90                 }
91                 usleep(500000);
92         }
93
94         return r;
95 }
96
97
98
99 bool menu_daemon_is_homescreen(pid_t pid)
100 {
101         if (s_info.home_pid == pid) return true;
102         return false;
103 }
104
105
106
107 inline char *menu_daemon_get_selected_pkgname(void)
108 {
109         char *pkgname = NULL;
110
111         pkgname = vconf_get_str(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME);
112         retv_if(NULL == pkgname, NULL);
113
114         return pkgname;
115 }
116
117
118
119 static bool _exist_package(char *pkgid)
120 {
121         int ret = 0;
122         pkgmgrinfo_pkginfo_h handle = NULL;
123
124         ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &handle);
125         if (PMINFO_R_OK != ret || NULL == handle) {
126                 _D("%s doesn't exist in this binary", pkgid);
127                 return false;
128         }
129
130         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
131
132         return true;
133 }
134
135
136
137 inline void menu_daemon_open_homescreen(const char *pkgname)
138 {
139         char *homescreen = NULL;
140         char *tmp = NULL;
141
142         system("echo -e '[${_G}menu-daemon launches home-screen${C_}]' > /dev/kmsg");
143
144         if (NULL == pkgname) {
145                 tmp = menu_daemon_get_selected_pkgname();
146                 ret_if(NULL == tmp);
147                 homescreen = tmp;
148         } else {
149                 homescreen = (char *) pkgname;
150         }
151
152         syspopup_destroy_all();
153
154         int ret;
155         ret = menu_daemon_open_app(homescreen);
156         _D("can%s launch %s now. (%d)", ret < 0 ? "not" : "", homescreen, ret);
157         if (ret < 0 && strcmp(homescreen, HOME_SCREEN_PKG_NAME) && _exist_package(HOME_SCREEN_PKG_NAME)) {
158                 _E("cannot launch package %s", homescreen);
159
160                 if (0 != vconf_set_str(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, HOME_SCREEN_PKG_NAME)) {
161                         _E("Cannot set value(%s) into key(%s)", VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, HOME_SCREEN_PKG_NAME);
162                 }
163
164                 while (AUL_R_ETIMEOUT == ret) {
165                         _E("Failed to open a default home, %s", HOME_SCREEN_PKG_NAME);
166                         ret = menu_daemon_open_app(HOME_SCREEN_PKG_NAME);
167                 }
168         }
169
170         if (ret < 0) {
171                 _E("Critical! Starter cannot launch anymore[%d]", ret);
172                 _F("Critical! Starter cannot launch anymore[%d]", ret);
173         }
174
175         s_info.home_pid = ret;
176         if (ret > 0) {
177                 if (-1 == sysconf_set_mempolicy_bypid(ret, OOM_IGNORE)) {
178                         _E("Cannot set the memory policy for Home-screen(%d)", ret);
179                 } else {
180                         _D("Set the memory policy for Home-screen(%d)", ret);
181                 }
182         }
183
184         if (tmp) free(tmp);
185 }
186
187
188
189 static void _show_cb(keynode_t* node, void *data)
190 {
191         int seq;
192
193         _D("[MENU_DAEMON] _show_cb is invoked");
194
195         if (node) {
196                 seq = vconf_keynode_get_int(node);
197         } else {
198                 if (vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &seq) < 0) {
199                         _E("Failed to get sequence info");
200                         return;
201                 }
202         }
203
204         switch (seq) {
205                 case 0:
206                         if (s_info.home_pid > 0) {
207                                 int pid;
208                                 _D("pid[%d] is terminated.", s_info.home_pid);
209                                 pid = s_info.home_pid;
210                                 s_info.home_pid = -1;
211
212                                 if (aul_terminate_pid(pid) != AUL_R_OK)
213                                         _E("Failed to terminate %d", s_info.home_pid);
214                         }
215                         break;
216                 case 1:
217                         menu_daemon_open_homescreen(NULL);
218                         break;
219                 default:
220                         _E("False sequence [%d]", seq);
221                         break;
222         }
223
224         return;
225 }
226
227
228
229 static void _pkg_changed(keynode_t* node, void *data)
230 {
231         char *pkgname;
232         int seq;
233
234         if (vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &seq) < 0) {
235                 _E("Do nothing, there is no sequence info yet");
236                 return;
237         }
238
239         if (seq < 1) {
240                 _E("Sequence is not ready yet, do nothing");
241                 return;
242         }
243
244         _D("_pkg_changed is invoked");
245
246         pkgname = menu_daemon_get_selected_pkgname();
247         if (!pkgname)
248                 return;
249
250         _D("pkg_name : %s", pkgname);
251
252         if (s_info.home_pid > 0) {
253                 char old_pkgname[256];
254
255                 if (aul_app_get_pkgname_bypid(s_info.home_pid, old_pkgname, sizeof(old_pkgname)) == AUL_R_OK) {
256                         if (!strcmp(pkgname, old_pkgname)) {
257                                 _D("Package is changed but same package is selected");
258                                 free(pkgname);
259                                 return;
260                         }
261                 }
262
263                 if (AUL_R_OK != aul_terminate_pid(s_info.home_pid))
264                         _D("Failed to terminate pid %d", s_info.home_pid);
265         } else {
266                 /* If there is no running home */
267                 menu_daemon_open_homescreen(pkgname);
268         }
269
270         free(pkgname);
271         return;
272 }
273
274
275
276 static void _launch_volume(void)
277 {
278         int pid;
279         int i;
280         _D("_launch_volume");
281
282         for (i=0; i<RETRY_MAXCOUNT; i++)
283         {
284                 pid = syspopup_launch("volume", NULL);
285
286                 _D("syspopup_launch(volume), pid = %d", pid);
287
288                 if (pid <0) {
289                         _D("syspopup_launch(volume)is failed [%d]times", i);
290                         usleep(RELAUNCH_INTERVAL);
291                 } else {
292                         s_info.volume_pid = pid;
293                         return;
294                 }
295         }
296 }
297
298 int menu_daemon_check_dead_signal(int pid)
299 {
300         if (s_info.power_off) {
301                 _D("Power off. ignore dead cb\n");
302                 return 0;
303         }
304
305         _D("Process %d is termianted", pid);
306
307         if (pid < 0)
308                 return 0;
309
310         if (pid == s_info.home_pid) {
311                 char *pkgname = NULL;
312                 pkgname = menu_daemon_get_selected_pkgname();
313                 retv_if(NULL == pkgname, 0);
314
315                 _D("pkg_name : %s", pkgname);
316                 menu_daemon_open_homescreen(pkgname);
317                 free(pkgname);
318         } else if (pid == s_info.volume_pid) {
319                 _launch_volume();
320         } else {
321                 _D("Unknown process, ignore it (pid %d, home pid %d)",
322                                 pid, s_info.home_pid);
323         }
324
325
326         return 0;
327 }
328
329
330
331 void menu_daemon_init(void *data)
332 {
333         _D( "[MENU_DAEMON]menu_daemon_init is invoked");
334
335         aul_launch_init(NULL,NULL);
336
337         create_key_window();
338         if (xmonitor_init() < 0) _E("cannot init xmonitor");
339
340         pkg_event_init();
341         _launch_volume();
342
343         if (unlink(SAT_DESKTOP_FILE) != 0)
344                 _E("cannot remove sat-ui desktop.");
345
346         if (vconf_notify_key_changed(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, _pkg_changed, NULL) < 0)
347                 _E("Failed to add the callback for package change event");
348
349         if (vconf_notify_key_changed(VCONFKEY_STARTER_SEQUENCE, _show_cb, NULL) < 0)
350                 _E("Failed to add the callback for show event");
351
352         _pkg_changed(NULL, NULL);
353         vconf_set_int(VCONFKEY_IDLE_SCREEN_LAUNCHED, VCONFKEY_IDLE_SCREEN_LAUNCHED_TRUE);
354 }
355
356
357
358 void menu_daemon_fini(void)
359 {
360         if (vconf_ignore_key_changed(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, _pkg_changed) < 0)
361                 _E("Failed to ignore the callback for package change event");
362
363         if (vconf_ignore_key_changed(VCONFKEY_STARTER_SEQUENCE, _show_cb) < 0)
364                 _E("Failed to ignore the callback for show event");
365
366         xmonitor_fini();
367         pkg_event_fini();
368         destroy_key_window();
369 }
370
371
372
373 // End of a file