apply FSL(Flora Software License)
[framework/system/system-server.git] / ss_predefine.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 #include <unistd.h>
19 #include <time.h>
20 #include <limits.h>
21 #include <fcntl.h>
22 #include <dirent.h>
23 #include <sysman.h>
24 #include <vconf.h>
25 #include <pmapi.h>
26 #include <ITapiPower.h>
27 #include <TelPower.h>
28 #include <TapiEvent.h>
29 #include <TapiCommon.h>
30 #include <syspopup_caller.h>
31 #include <sys/reboot.h>
32 #include <sys/time.h>
33
34 #include "ss_log.h"
35 #include "ss_launch.h"
36 #include "ss_queue.h"
37 #include "ss_device_handler.h"
38 #include "ss_device_plugin.h"
39 #include "ss_predefine.h"
40 #include "ss_procmgr.h"
41 #include "include/ss_data.h"
42
43 #define PREDEFINE_SO_DIR        PREFIX"/lib/ss_predefine/"
44
45 #define CALL_EXEC_PATH          PREFIX"/bin/call"
46 #define LOWMEM_EXEC_PATH        PREFIX"/bin/lowmem-popup"
47 #define LOWBAT_EXEC_PATH        PREFIX"/bin/lowbatt-popup"
48 #define USBCON_EXEC_PATH        PREFIX"/bin/usb_setting"
49 #define TVOUT_EXEC_PATH         PREFIX"/bin/tvout-selector"
50 #define PWROFF_EXEC_PATH        PREFIX"/bin/poweroff-popup"
51 #define MEMPS_EXEC_PATH PREFIX"/bin/memps"
52
53 /* wait for 5 sec as victim process be dead */
54 #define WAITING_INTERVAL        5
55
56 #define TVOUT_X_BIN             "/usr/bin/xberc"
57 #define TVOUT_FLAG              0x00000001
58 #define MEMPS_LOG_FILE          "/var/log/memps"
59 #define MAX_RETRY               2
60
61 #define POWEROFF_DURATION               2
62 #define POWEROFF_ANIMATION_PATH         "/usr/bin/boot-animation"
63 #define POWEROFF_NOTI_NAME                     "power_off_start"
64
65 #define VCONFKEY_TESTMODE_LOW_BATT_POPUP       "db/testmode/low_batt_popup"
66  
67 #define LOWBAT_OPT_WARNING              1
68 #define LOWBAT_OPT_POWEROFF             2
69 #define LOWBAT_OPT_CHARGEERR    3
70 #define LOWBAT_OPT_CHECK                4
71
72 static Ecore_Timer *lowbat_popup_id = NULL;
73 static int lowbat_popup_option = 0;
74
75 static struct timeval tv_start_poweroff;
76 static void powerdown_ap(TelTapiEvent_t *event, void *data);
77
78 static int ss_flags = 0;
79
80 static unsigned int power_subscription_id = 0;
81
82 static void make_memps_log(char *file, pid_t pid, char *victim_name)
83 {
84         time_t now;
85         struct tm *cur_tm;
86         char params[4096];
87         char new_log[NAME_MAX];
88         static pid_t old_pid = 0;
89         int ret=-1;
90
91         if (old_pid == pid)
92                 return;
93         old_pid = pid;
94
95         now = time(NULL);
96         cur_tm = (struct tm *)malloc(sizeof(struct tm));
97         if (cur_tm == NULL) {
98                 PRT_TRACE_ERR("Fail to memory allocation");
99                 return;
100         }
101
102         if (localtime_r(&now, cur_tm) == NULL) {
103                 PRT_TRACE_ERR("Fail to get localtime");
104                 return;
105         }
106
107         PRT_TRACE("%s_%s_%d_%.4d%.2d%.2d_%.2d%.2d%.2d.log", file, victim_name,
108                  pid, (1900 + cur_tm->tm_year), 1 + cur_tm->tm_mon,
109                  cur_tm->tm_mday, cur_tm->tm_hour, cur_tm->tm_min,
110                  cur_tm->tm_sec);
111         snprintf(new_log, sizeof(new_log),
112                  "%s_%s_%d_%.4d%.2d%.2d_%.2d%.2d%.2d.log", file, victim_name,
113                  pid, (1900 + cur_tm->tm_year), 1 + cur_tm->tm_mon,
114                  cur_tm->tm_mday, cur_tm->tm_hour, cur_tm->tm_min,
115                  cur_tm->tm_sec);
116
117         snprintf(params, sizeof(params), "-f %s", new_log);
118         ret = ss_launch_evenif_exist(MEMPS_EXEC_PATH, params);
119
120         if(ret > 0) {
121                 char buf[PATH_MAX];
122                 FILE *fp;
123                 snprintf(buf, sizeof(buf), "/proc/%d/oom_adj", ret);
124                 fp = fopen(buf, "w");
125                 if (fp != NULL) {
126                         fprintf(fp, "%d", (-17));
127                         fclose(fp);
128                 }
129         }
130         free(cur_tm);
131 }
132
133 static int lowmem_get_victim_pid()
134 {
135         pid_t pid;
136         int fd;
137
138         if (0 > plugin_intf->OEM_sys_get_memnotify_victim_task(&pid)) {
139                 PRT_TRACE_ERR("Get victim task failed");
140                 return -1;
141         }
142
143         return pid;
144 }
145
146 int lowmem_def_predefine_action(int argc, char **argv)
147 {
148         int pid, ret, oom_adj;
149         char appname[PATH_MAX];
150
151         if (argc < 1)
152                 return -1;
153
154         if (!strcmp(argv[0], OOM_MEM_ACT)) {
155                 pid = lowmem_get_victim_pid();
156                 if (pid > 0 && pid != sysman_get_pid(LOWMEM_EXEC_PATH) && pid != sysman_get_pid(MEMPS_EXEC_PATH)) {
157                         if ((sysman_get_cmdline_name(pid, appname, PATH_MAX)) ==
158                             0) {
159                                 PRT_TRACE_EM
160                                     ("we will kill, lowmem lv2 = %d (%s)\n",
161                                      pid, appname);
162         
163                                 make_memps_log(MEMPS_LOG_FILE, pid, appname);
164
165                                 if(get_app_oomadj(pid, &oom_adj) < 0) {
166                                         PRT_TRACE_ERR("Failed to get oom_adj");
167                                 }
168                                 PRT_TRACE("%d will be killed with %d oom_adj value", pid, oom_adj);
169
170                                 kill(pid, SIGTERM);
171
172                                 if (oom_adj >= OOMADJ_BACKGRD_UNLOCKED) {       
173                                         return 0;
174                                 }
175
176                                 bundle *b = NULL;
177
178                                 b = bundle_create();
179                                 bundle_add(b, "_APP_NAME_", appname);
180                                 ret = syspopup_launch("lowmem-syspopup", b);
181                                 bundle_free(b);
182                                 if (ret < 0) {
183                                         PRT_TRACE_EM("popup lauch failed\n");
184                                         return -1;
185                                 }
186                                 
187                                 if (set_app_oomadj(ret, OOMADJ_SU) < 0) {       
188                                         PRT_TRACE_ERR("Failed to set oom_adj");
189                                 }
190                         }
191                 }
192         } else {
193                 PRT_TRACE_EM("making memps log for low memory\n");
194                 make_memps_log(MEMPS_LOG_FILE, 1, "LOWMEM_WARNING");
195         }
196
197         return 0;
198 }
199
200 int usbcon_def_predefine_action(int argc, char **argv)
201 {
202         int pid;
203         int val = -1;
204         int ret = -1;
205         int bat_state = VCONFKEY_SYSMAN_BAT_NORMAL;
206
207         if (plugin_intf->OEM_sys_get_jack_usb_online(&val) == 0) {
208                 if (val == 0) {
209                         vconf_set_int(VCONFKEY_SYSMAN_USB_STATUS,
210                                       VCONFKEY_SYSMAN_USB_DISCONNECTED);
211                         pm_unlock_state(LCD_OFF, STAY_CUR_STATE);
212
213                         vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state);
214                         if(bat_state < VCONFKEY_SYSMAN_BAT_NORMAL) {
215                                 bundle *b = NULL;
216                                 b = bundle_create();
217                                 bundle_add(b, "_SYSPOPUP_CONTENT_", "warning");
218
219                                 ret = syspopup_launch("lowbat-syspopup", b);
220                                 if (ret < 0) {
221                                         PRT_TRACE_EM("popup lauch failed\n");
222                                 }
223                                 bundle_free(b);
224                         }
225                         return 0;
226                 }
227
228                 vconf_set_int(VCONFKEY_SYSMAN_USB_STATUS,
229                               VCONFKEY_SYSMAN_USB_AVAILABLE);
230                 pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0);
231                 pid = ss_launch_if_noexist(USBCON_EXEC_PATH, NULL);
232                 if (pid < 0) {
233                         PRT_TRACE_ERR("usb predefine action failed\n");
234                         return -1;
235                 }
236                 return pid;
237         }
238         PRT_TRACE_ERR("failed to get usb status\n");
239         return -1;
240 }
241
242 int earjackcon_def_predefine_action(int argc, char **argv)
243 {
244         int val;
245
246         PRT_TRACE_EM("earjack_normal predefine action\n");
247         if (plugin_intf->OEM_sys_get_jack_earjack_online(&val) == 0) {
248                 return vconf_set_int(VCONFKEY_SYSMAN_EARJACK, val);
249         }
250
251         return -1;
252 }
253
254 int lowbat_popup(void *data)
255 {
256         int ret = -1, state = 0;
257         ret = vconf_get_int("memory/boot-animation/finished", &state);
258         if (state == 1 || ret != 0) {
259                 bundle *b = NULL;
260                 b = bundle_create();
261                 if(lowbat_popup_option == LOWBAT_OPT_WARNING) {
262                         bundle_add(b, "_SYSPOPUP_CONTENT_", "warning");
263                 } else if(lowbat_popup_option == LOWBAT_OPT_POWEROFF) {
264                         bundle_add(b, "_SYSPOPUP_CONTENT_", "poweroff");
265                 } else if(lowbat_popup_option == LOWBAT_OPT_CHARGEERR) {
266                         bundle_add(b, "_SYSPOPUP_CONTENT_", "chargeerr");
267                 } else {
268                         bundle_add(b, "_SYSPOPUP_CONTENT_", "check");
269                 }
270
271                 ret = syspopup_launch("lowbat-syspopup", b);
272                 if (ret < 0) {
273                         PRT_TRACE_EM("popup lauch failed\n");
274                         bundle_free(b);
275                         return 1;
276                 }
277                         lowbat_popup_id = NULL;
278                 lowbat_popup_option = 0;
279                 bundle_free(b);
280         } else {
281                 PRT_TRACE_EM("boot-animation running yet");
282                 return 1;
283         }
284
285         return 0;
286 }
287
288 int lowbat_def_predefine_action(int argc, char **argv)
289 {
290         int ret, state=0;
291         char argstr[128];
292         char* option = NULL;
293
294         if (argc < 1)
295                 return -1;
296
297         if(lowbat_popup_id != NULL) {
298                 ecore_timer_del(lowbat_popup_id);
299                 lowbat_popup_id = NULL;
300         }
301
302         bundle *b = NULL;
303         b = bundle_create();
304         if(!strcmp(argv[0],WARNING_LOW_BAT_ACT) || !strcmp(argv[0],CRITICAL_LOW_BAT_ACT)) {
305                 bundle_add(b, "_SYSPOPUP_CONTENT_", "warning");
306                 lowbat_popup_option = LOWBAT_OPT_WARNING;
307         } else if(!strcmp(argv[0],POWER_OFF_BAT_ACT)) {
308                 bundle_add(b, "_SYSPOPUP_CONTENT_", "poweroff");
309                 lowbat_popup_option = LOWBAT_OPT_POWEROFF;
310         } else if(!strcmp(argv[0],CHARGE_ERROR_ACT)) {
311                 bundle_add(b, "_SYSPOPUP_CONTENT_", "chargeerr");
312                 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
313         } else {
314                 bundle_add(b, "_SYSPOPUP_CONTENT_", "check");
315                 lowbat_popup_option = LOWBAT_OPT_CHECK;
316         }
317
318         ret = vconf_get_int("memory/boot-animation/finished", &state);
319         if (state == 1 || ret != 0) {
320                 ret = syspopup_launch("lowbat-syspopup", b);
321                 if (ret < 0) {
322                         PRT_TRACE_EM("popup lauch failed\n");
323                         bundle_free(b);
324                         lowbat_popup_option = 0;
325                         return -1;
326                 }
327         } else {
328                 PRT_TRACE_EM("boot-animation running yet");
329                 lowbat_popup_id = ecore_timer_add(1, lowbat_popup, NULL);
330         }
331         bundle_free(b);
332         return 0;
333 }
334
335 Eina_Bool powerdown_ap_by_force(void *data)
336 {
337         struct timeval now;
338         int poweroff_duration = POWEROFF_DURATION;
339         char *buf;
340
341         /* Getting poweroff duration */
342         buf = getenv("PWROFF_DUR");
343         if (buf != NULL && strlen(buf) < 1024)
344                 poweroff_duration = atoi(buf);
345         if (poweroff_duration < 0 || poweroff_duration > 60)
346                 poweroff_duration = POWEROFF_DURATION;
347
348         gettimeofday(&now, NULL);
349         /* Waiting until power off duration and displaying animation */
350         while (now.tv_sec - tv_start_poweroff.tv_sec < poweroff_duration) {
351                 usleep(100000);
352                 gettimeofday(&now, NULL);
353         }
354
355         PRT_TRACE("Power off by force\n");
356         kill(-1, SIGTERM);
357         /* give a chance to be terminated for each process */
358         sleep(1);
359         sync();
360         reboot(RB_POWER_OFF);
361         return EINA_TRUE;
362 }
363
364 static void powerdown_ap(TelTapiEvent_t *event, void *data)
365 {
366         struct timeval now;
367         int poweroff_duration = POWEROFF_DURATION;
368         char *buf;
369
370         if (power_subscription_id) {
371                 tel_deregister_event(power_subscription_id);
372                 power_subscription_id = 0;
373         }
374         PRT_TRACE("Power off \n");
375
376         /* Getting poweroff duration */
377         buf = getenv("PWROFF_DUR");
378         if (buf != NULL && strlen(buf) < 1024)
379                 poweroff_duration = atoi(buf);
380         if (poweroff_duration < 0 || poweroff_duration > 60)
381                 poweroff_duration = POWEROFF_DURATION;
382
383         gettimeofday(&now, NULL);
384         /* Waiting until power off duration and displaying animation */
385         while (now.tv_sec - tv_start_poweroff.tv_sec < poweroff_duration) {
386                 usleep(100000);
387                 gettimeofday(&now, NULL);
388         }
389
390         kill(-1, SIGTERM);
391         /* give a chance to be terminated for each process */
392         sleep(1);
393         sync();
394         reboot(RB_POWER_OFF);
395 }
396
397 int poweroff_def_predefine_action(int argc, char **argv)
398 {
399         int ret;
400
401         heynoti_publish(POWEROFF_NOTI_NAME);
402
403         pm_change_state(LCD_NORMAL);
404         system("/etc/rc.d/rc.shutdown &");
405         sync();
406
407         gettimeofday(&tv_start_poweroff, NULL);
408         ret =
409             tel_register_event(TAPI_EVENT_POWER_PHONE_OFF,
410                                &power_subscription_id,
411                                (TelAppCallback) & powerdown_ap, NULL);
412         if (ret != TAPI_API_SUCCESS) {
413                 PRT_TRACE_ERR
414                     ("tel_register_event is not subscribed. error %d\n", ret);
415                 powerdown_ap_by_force(NULL);
416                 return 0;
417         }
418
419         ret = tel_process_power_command(TAPI_PHONE_POWER_OFF);
420         if (ret != TAPI_API_SUCCESS) {
421                 PRT_TRACE_ERR("tel_process_power_command() error %d\n", ret);
422                 powerdown_ap_by_force(NULL);
423                 return 0;
424         }
425
426         return 0;
427 }
428
429 static void restart_ap(TelTapiEvent_t *event, void *data);
430
431 Eina_Bool restart_ap_ecore(void *data)
432 {
433         restart_ap(NULL, (void *)-1);
434         return EINA_TRUE;
435 }
436
437 static void restart_ap(TelTapiEvent_t *event, void *data)
438 {
439         struct timeval now;
440         int poweroff_duration = POWEROFF_DURATION;
441         char *buf;
442
443         if (power_subscription_id) {
444                 tel_deregister_event(power_subscription_id);
445                 power_subscription_id = 0;
446         }
447
448         PRT_INFO("Restart\n");
449         sync();
450
451         buf = getenv("PWROFF_DUR");
452         if (buf != NULL && strlen(buf) < 1024)
453                 poweroff_duration = atoi(buf);
454         if (poweroff_duration < 0 || poweroff_duration > 60)
455                 poweroff_duration = POWEROFF_DURATION;
456         gettimeofday(&now, NULL);
457         while (now.tv_sec - tv_start_poweroff.tv_sec < poweroff_duration) {
458                 usleep(100000);
459                 gettimeofday(&now, NULL);
460         }
461
462         reboot(RB_AUTOBOOT);
463 }
464
465 int restart_def_predefine_action(int argc, char **argv)
466 {
467         int ret;
468
469         pm_change_state(LCD_NORMAL);
470         system("/etc/rc.d/rc.shutdown &");
471         sync();
472
473         gettimeofday(&tv_start_poweroff, NULL);
474
475         ret =
476             tel_register_event(TAPI_EVENT_POWER_PHONE_OFF,
477                                &power_subscription_id,
478                                (TelAppCallback) & restart_ap, NULL);
479         if (ret != TAPI_API_SUCCESS) {
480                 PRT_TRACE_ERR
481                     ("tel_register_event is not subscribed. error %d\n", ret);
482                 restart_ap(NULL, (void *)-1);
483                 return 0;
484         }
485
486         ret = tel_process_power_command(TAPI_PHONE_POWER_OFF);
487         if (ret != TAPI_API_SUCCESS) {
488                 PRT_TRACE_ERR("tel_process_power_command() error %d\n", ret);
489                 restart_ap(NULL, (void *)-1);
490                 return 0;
491         }
492
493         return 0;
494 }
495
496 int launching_predefine_action(int argc, char **argv)
497 {
498         int ret;
499
500         if (argc < 0)
501                 return -1;
502
503         /* current just launching poweroff-popup */
504         ret = syspopup_launch("poweroff-syspopup", NULL);
505         if (ret < 0) {
506                 PRT_TRACE_ERR("poweroff popup predefine action failed");
507                 return -1;
508         }
509         return 0;
510 }
511
512 static void ss_action_entry_load_from_sodir()
513 {
514         DIR *dp;
515         struct dirent *dentry;
516         struct sysnoti *msg;
517         char *ext;
518         char tmp[128];
519
520         dp = opendir(PREDEFINE_SO_DIR);
521         if (!dp) {
522                 ERR("fail open %s", PREDEFINE_SO_DIR);
523                 return;
524         }
525
526         msg = malloc(sizeof(struct sysnoti));
527         if (msg == NULL) {
528                 ERR("Malloc failed");
529                 closedir(dp);
530                 return;
531         }
532
533         msg->pid = getpid();
534
535         while ((dentry = readdir(dp)) != NULL) {
536                 if ((ext = strstr(dentry->d_name, ".so")) == NULL)
537                         continue;
538
539                 snprintf(tmp, sizeof(tmp), "%s/%s", PREDEFINE_SO_DIR,
540                          dentry->d_name);
541                 msg->path = tmp;
542                 *ext = 0;
543                 msg->type = &(dentry->d_name[3]);
544                 ss_action_entry_add(msg);
545         }
546         free(msg);
547
548         closedir(dp);
549 }
550
551 void ss_predefine_internal_init(void)
552 {
553         ss_action_entry_add_internal(PREDEF_LOWMEM, lowmem_def_predefine_action,
554                                      NULL, NULL);
555         ss_action_entry_add_internal(PREDEF_LOWBAT, lowbat_def_predefine_action,
556                                      NULL, NULL);
557         ss_action_entry_add_internal(PREDEF_USBCON, usbcon_def_predefine_action,
558                                      NULL, NULL);
559         ss_action_entry_add_internal(PREDEF_EARJACKCON,
560                                      earjackcon_def_predefine_action, NULL,
561                                      NULL);
562         ss_action_entry_add_internal(PREDEF_POWEROFF,
563                                      poweroff_def_predefine_action, NULL, NULL);
564         ss_action_entry_add_internal(PREDEF_PWROFF_POPUP,
565                                      launching_predefine_action, NULL, NULL);
566         ss_action_entry_add_internal(PREDEF_REBOOT,
567                                      restart_def_predefine_action, NULL, NULL);
568
569         ss_action_entry_load_from_sodir();
570
571         /* check and set earjack init status */
572         earjackcon_def_predefine_action(0, NULL);
573 }