[mobile] In 64bit binary, menu-screen will be launched first.
[apps/native/starter.git] / src / mobile / home_mgr.c
1 /*
2  * Copyright (c) 2000 - 2015 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 <aul.h>
18 #include <app.h>
19 #include <db-util.h>
20 #include <Elementary.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <pkgmgr-info.h>
24 #include <stdio.h>
25 #include <dd-deviced.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <unistd.h>
29 #include <vconf.h>
30
31 #include "util.h"
32 #include "dbus_util.h"
33 #include "status.h"
34 #include "process_mgr.h"
35 #include "popup.h"
36
37 #define HOME_TERMINATED "home_terminated"
38 #define ISTRUE "TRUE"
39 #define SYSPOPUPID_VOLUME "volume"
40 #define APPID_INDICATOR "org.tizen.indicator"
41 #define APPID_QUICKPANEL "org.tizen.quickpanel"
42
43 #define DEAD_TIMER_SEC 10.0
44 #define DEAD_TIMER_COUNT_MAX 2
45
46
47
48 int errno;
49 static struct {
50         pid_t home_pid;
51         pid_t volume_pid;
52         pid_t indicator_pid;
53         pid_t quickpanel_pid;
54         int power_off;
55
56         Ecore_Timer *dead_timer;
57         int dead_count;
58
59         Evas_Object *popup;
60 } s_home_mgr = {
61         .home_pid = (pid_t)-1,
62         .volume_pid = (pid_t)-1,
63         .indicator_pid = (pid_t)-1,
64         .quickpanel_pid = (pid_t)-1,
65         .power_off = 0,
66
67         .dead_timer = NULL,
68         .dead_count = 0,
69
70         .popup = NULL,
71 };
72
73
74 int home_mgr_get_home_pid(void)
75 {
76         return s_home_mgr.home_pid;
77 }
78
79
80
81 int home_mgr_get_volume_pid(void)
82 {
83         return s_home_mgr.volume_pid;
84 }
85
86
87
88 int home_mgr_get_indicator_pid(void)
89 {
90         return s_home_mgr.indicator_pid;
91 }
92
93
94
95 int home_mgr_get_quickpanel_pid(void)
96 {
97         return s_home_mgr.quickpanel_pid;
98 }
99
100
101
102 static void _after_launch_home(int pid)
103 {
104         if (dbus_util_send_oomadj(pid, OOM_ADJ_VALUE_HOMESCREEN) < 0){
105                 _E("failed to send oom dbus signal");
106         }
107         s_home_mgr.home_pid = pid;
108 }
109
110
111
112 static int _change_home_cb(const char *appid, const char *key, const char *value, void *cfn, void *afn)
113 {
114         if (!strcmp(appid, MENU_SCREEN_PKG_NAME)) {
115                 _E("We cannot do anything anymore.");
116         } else if (!strcmp(appid, status_active_get()->setappl_selected_package_name)) {
117                 if (vconf_set_str(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, MENU_SCREEN_PKG_NAME) != 0) {
118                         _E("cannot set the vconf key as %s", MENU_SCREEN_PKG_NAME);
119                 }
120                 /* change_home func will be called by changing the home */
121                 return 0;
122         }
123         _E("cannot change home");
124         return -1;
125 }
126
127
128
129 #define SERVICE_OPERATION_MAIN_KEY "__APP_SVC_OP_TYPE__"
130 #define SERVICE_OPERATION_MAIN_VALUE "http://tizen.org/appcontrol/operation/main"
131 void home_mgr_open_home(const char *appid)
132 {
133         char *home_appid = NULL;
134
135 #ifndef TIZEN_BUILD_TARGET_64
136         if (!appid) {
137                 home_appid = status_active_get()->setappl_selected_package_name;
138         } else {
139                 home_appid = (char *) appid;
140         }
141         ret_if(!home_appid);
142 #else
143         /*
144          * If the architecture is 64bit,
145          * starter will launch menu-screen only.
146          */
147         _D("64bit binary : menu-screen will be launched.");
148         home_appid = MENU_SCREEN_PKG_NAME;
149 #endif
150
151         process_mgr_must_launch(home_appid, SERVICE_OPERATION_MAIN_KEY, SERVICE_OPERATION_MAIN_VALUE, _change_home_cb, _after_launch_home);
152 }
153
154
155
156 static int _show_home_cb(status_active_key_e key, void *data)
157 {
158         int seq = status_active_get()->starter_sequence;
159         int is_fallback = 0;
160
161         _D("[MENU_DAEMON] _show_home_cb is invoked(%d)", seq);
162
163         switch (seq) {
164         case 0:
165                 if (s_home_mgr.home_pid > 0) {
166                         _D("Home[%d] has to be terminated.", s_home_mgr.home_pid);
167                         if (aul_terminate_pid(s_home_mgr.home_pid) != AUL_R_OK) {
168                                 _E("Failed to terminate %d", s_home_mgr.home_pid);
169                         }
170                         s_home_mgr.home_pid = -1; /* to freeze the dead_cb */
171                 }
172                 break;
173         case 1:
174                 if (vconf_get_int(VCONFKEY_STARTER_IS_FALLBACK, &is_fallback) < 0) {
175                         _E("Failed to get vconfkey : %s", VCONFKEY_STARTER_IS_FALLBACK);
176                 }
177
178                 if (is_fallback) {
179                         if (vconf_set_int(VCONFKEY_STARTER_IS_FALLBACK, 0)) {
180                                 _E("Failed to set vconfkey : %s", VCONFKEY_STARTER_IS_FALLBACK);
181                         }
182
183                         if (!strcmp(status_active_get()->setappl_selected_package_name, MENU_SCREEN_PKG_NAME)) {
184                                 char *fallback_pkg;
185
186                                 fallback_pkg = vconf_get_str(VCONFKEY_STARTER_FALLBACK_PKG);
187                                 _D("fallback pkg : %s", fallback_pkg);
188                                 if (fallback_pkg) {
189                                         int status;
190
191                                         status = vconf_set_str(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, fallback_pkg);
192                                         free(fallback_pkg);
193                                         if (status == 0) {
194                                                 break;
195                                         }
196                                         _E("Failed to set vconfkey : %s (%d)", VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, status);
197                                 } else {
198                                         _E("Failed to get vconfkey : %s", VCONFKEY_STARTER_FALLBACK_PKG);
199                                 }
200                         }
201                 }
202
203                 home_mgr_open_home(NULL);
204                 break;
205         default:
206                 _E("False sequence [%d]", seq);
207                 break;
208         }
209
210         return 1;
211 }
212
213
214
215 static int _change_selected_package_name(status_active_key_e key, void *data)
216 {
217         char *appid = NULL;
218         int seq = status_active_get()->starter_sequence;
219
220         if (seq < 1) {
221                 _E("Sequence is not ready yet, do nothing");
222                 return 1;
223         }
224
225         _D("_change_selected_package_name is invoked");
226
227         appid = status_active_get()->setappl_selected_package_name;
228         if (!appid) {
229                 return 1;
230         }
231         _SECURE_D("pkg_name : %s", appid);
232
233         if (s_home_mgr.home_pid > 0) {
234                 char old_appid[BUF_SIZE_512] = { 0 , };
235
236                 if (aul_app_get_pkgname_bypid(s_home_mgr.home_pid, old_appid, sizeof(old_appid)) == AUL_R_OK) {
237                         if (!strcmp(appid, old_appid)) {
238                                 _D("Package is changed but same package is selected");
239                                 return 1;
240                         }
241                 }
242
243                 if (AUL_R_OK != aul_terminate_pid(s_home_mgr.home_pid)) {
244                         _D("Failed to terminate pid %d", s_home_mgr.home_pid);
245                 }
246                 s_home_mgr.home_pid = -1;
247                 s_home_mgr.dead_count = 0;
248                 if (s_home_mgr.dead_timer) {
249                         ecore_timer_del(s_home_mgr.dead_timer);
250                         s_home_mgr.dead_timer = NULL;
251                 }
252         }
253
254         home_mgr_open_home(appid);
255
256         return 1;
257 }
258
259
260
261 static void _after_launch_volume(int pid)
262 {
263         if (dbus_util_send_oomadj(pid, OOM_ADJ_VALUE_DEFAULT) < 0){
264                 _E("failed to send oom dbus signal");
265         }
266         s_home_mgr.volume_pid = pid;
267 }
268
269
270
271 static void _after_launch_indicator(int pid)
272 {
273         s_home_mgr.indicator_pid = pid;
274 }
275
276
277
278 static void _after_launch_quickpanel(int pid)
279 {
280         s_home_mgr.quickpanel_pid = pid;
281 }
282
283
284
285 static void _launch_after_home(int pid)
286 {
287         if (pid > 0) {
288                 if(dbus_util_send_oomadj(pid, OOM_ADJ_VALUE_HOMESCREEN) < 0){
289                         _E("failed to send oom dbus signal");
290                 }
291         }
292         s_home_mgr.home_pid = pid;
293 }
294
295
296
297 static void _launch_home(const char *appid)
298 {
299         const char *home_appid = NULL;
300
301         if (!appid) {
302                 home_appid = status_active_get()->setappl_selected_package_name;
303         } else {
304                 home_appid = (char *) appid;
305         }
306         ret_if(!home_appid);
307
308         process_mgr_must_launch(home_appid, HOME_TERMINATED, ISTRUE, _change_home_cb, _launch_after_home);
309 }
310
311
312
313 static void _popup_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
314 {
315         _D("popup is deleted");
316
317         s_home_mgr.popup = NULL;
318 }
319
320
321
322 static Eina_Bool _dead_timer_cb(void *data)
323 {
324         Evas_Object *popup = NULL;
325         char title[BUF_SIZE_128] = { 0, };
326         char text[BUF_SIZE_1024] = { 0, };
327         char *appid = NULL;
328
329         appid = status_active_get()->setappl_selected_package_name;
330         if (!appid) {
331                 _E("appid is NULL");
332                 return ECORE_CALLBACK_CANCEL;
333         }
334
335         _D("dead count : %s(%d)", appid, s_home_mgr.dead_count);
336
337         if (s_home_mgr.dead_count >= DEAD_TIMER_COUNT_MAX) {
338                 _D("Change homescreen package to default");
339
340                 /* set fallback status */
341                 if (vconf_set_int(VCONFKEY_STARTER_IS_FALLBACK, 1) < 0) {
342                         _E("Failed to set vconfkey : %s", VCONFKEY_STARTER_IS_FALLBACK);
343                 }
344
345                 if (vconf_set_str(VCONFKEY_STARTER_FALLBACK_PKG, appid) < 0) {
346                         _E("Failed to set vconfkey : %s", VCONFKEY_STARTER_FALLBACK_PKG);
347                 }
348
349                 strncpy(title, _("IDS_COM_POP_WARNING"), sizeof(title));
350                 title[sizeof(title) - 1] = '\0';
351
352                 snprintf(text, sizeof(text), _("IDS_IDLE_POP_UNABLE_TO_LAUNCH_PS"), appid);
353                 _D("title : %s / text : %s", title, text);
354
355                 if (!s_home_mgr.popup) {
356                         popup = popup_create(title, text);
357                         if (!popup) {
358                                 _E("Failed to create popup");
359                         } else {
360                                 s_home_mgr.popup = popup;
361                                 evas_object_event_callback_add(popup, EVAS_CALLBACK_DEL, _popup_del_cb, NULL);
362                         }
363                 }
364
365                 if (vconf_set_str(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME, MENU_SCREEN_PKG_NAME) != 0) {
366                         _E("cannot set the vconf key as %s", MENU_SCREEN_PKG_NAME);
367                         return ECORE_CALLBACK_RENEW;
368                 }
369         }
370
371         s_home_mgr.dead_timer = NULL;
372         s_home_mgr.dead_count = 0;
373
374         return ECORE_CALLBACK_CANCEL;
375 }
376
377
378
379 void home_mgr_relaunch_homescreen(void)
380 {
381         char *appid = NULL;
382
383         if (s_home_mgr.power_off) {
384                 _E("power off");
385                 return;
386         }
387
388         appid = status_active_get()->setappl_selected_package_name;
389         if (!appid) {
390                 _E("appid is NULL");
391                 return;
392         }
393
394         s_home_mgr.dead_count++;
395         _D("home dead count : %d", s_home_mgr.dead_count);
396
397         if (!s_home_mgr.dead_timer) {
398                 _D("Add dead timer");
399                 s_home_mgr.dead_timer = ecore_timer_add(DEAD_TIMER_SEC, _dead_timer_cb, NULL);
400                 if (!s_home_mgr.dead_timer) {
401                         _E("Failed to add a dead timer");
402                 }
403         }
404
405         _launch_home(appid);
406 }
407
408
409
410 void home_mgr_relaunch_volume(void)
411 {
412         process_mgr_must_syspopup_launch(SYSPOPUPID_VOLUME, NULL, NULL, NULL, _after_launch_volume);
413 }
414
415
416
417 void home_mgr_relaunch_indicator(void)
418 {
419         process_mgr_must_launch(APPID_INDICATOR, NULL, NULL, NULL, _after_launch_indicator);
420 }
421
422
423
424 void home_mgr_relaunch_quickpanel(void)
425 {
426         process_mgr_must_launch(APPID_QUICKPANEL, NULL, NULL, NULL, _after_launch_quickpanel);
427 }
428
429
430
431 static int _power_off_cb(status_active_key_e key, void *data)
432 {
433         int val = status_active_get()->sysman_power_off_status;
434
435         if (val == VCONFKEY_SYSMAN_POWER_OFF_DIRECT || val == VCONFKEY_SYSMAN_POWER_OFF_RESTART) {
436                 s_home_mgr.power_off = 1;
437         } else {
438                 s_home_mgr.power_off = 0;
439         }
440
441         _D("power off status : %d", s_home_mgr.power_off);
442
443         return 1;
444 }
445
446
447
448 static Eina_Bool _launch_apps_idler_cb(void *data)
449 {
450 #ifndef TIZEN_BUILD_TARGET_64
451         process_mgr_must_syspopup_launch(SYSPOPUPID_VOLUME, NULL, NULL, NULL, _after_launch_volume);
452         process_mgr_must_launch(APPID_INDICATOR, NULL, NULL, NULL, _after_launch_indicator);
453         process_mgr_must_launch(APPID_QUICKPANEL, NULL, NULL, NULL, _after_launch_quickpanel);
454 #endif
455
456         return ECORE_CALLBACK_CANCEL;
457 }
458
459
460
461 void home_mgr_init(void *data)
462 {
463         _D( "[MENU_DAEMON]home_mgr_init is invoked");
464
465         status_active_register_cb(STATUS_ACTIVE_KEY_STARTER_SEQUENCE, _show_home_cb, NULL);
466         status_active_register_cb(STATUS_ACTIVE_KEY_SYSMAN_POWER_OFF_STATUS, _power_off_cb, NULL);
467         status_active_register_cb(STATUS_ACTIVE_KEY_SETAPPL_SELECTED_PACKAGE_NAME, _change_selected_package_name, NULL);
468         _change_selected_package_name(STATUS_ACTIVE_KEY_SETAPPL_SELECTED_PACKAGE_NAME, NULL);
469
470         ecore_idler_add(_launch_apps_idler_cb, NULL);
471 }
472
473
474
475 void home_mgr_fini(void)
476 {
477         if (s_home_mgr.volume_pid > 0) {
478                 process_mgr_terminate_app(s_home_mgr.volume_pid, 1);
479                 s_home_mgr.volume_pid = -1;
480         }
481
482         status_active_unregister_cb(STATUS_ACTIVE_KEY_STARTER_SEQUENCE, _show_home_cb);
483         status_active_unregister_cb(STATUS_ACTIVE_KEY_SYSMAN_POWER_OFF_STATUS, _power_off_cb);
484         status_active_unregister_cb(STATUS_ACTIVE_KEY_SETAPPL_SELECTED_PACKAGE_NAME, _change_selected_package_name);
485 }
486
487
488
489 // End of a file