rearrange wrong error log and delete redundant log regarding power handler
[platform/core/system/system-server.git] / src / power / power-handler.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <unistd.h>
21 #include <time.h>
22 #include <limits.h>
23 #include <fcntl.h>
24 #include <dirent.h>
25 #include <vconf.h>
26 #include <assert.h>
27 #include <limits.h>
28 #include <heynoti.h>
29 #include <vconf.h>
30 #include <ITapiModem.h>
31 #include <TelPower.h>
32 #include <tapi_event.h>
33 #include <tapi_common.h>
34 #include <syspopup_caller.h>
35 #include <sys/reboot.h>
36 #include <sys/time.h>
37 #include <mntent.h>
38 #include <sys/mount.h>
39 #include "dd-deviced.h"
40 #include "core/log.h"
41 #include "core/launch.h"
42 #include "core/queue.h"
43 #include "core/device-handler.h"
44 #include "device-node.h"
45 #include "core/predefine.h"
46 #include "core/data.h"
47 #include "core/common.h"
48 #include "core/devices.h"
49 #include "proc/proc-handler.h"
50 #include "display/poll.h"
51 #include "display/setting.h"
52
53 #define SIGNAL_NAME_POWEROFF_POPUP      "poweroffpopup"
54
55 #define PREDEF_ENTERSLEEP               "entersleep"
56 #define PREDEF_LEAVESLEEP               "leavesleep"
57 #define PREDEF_POWEROFF                 "poweroff"
58 #define PREDEF_REBOOT                   "reboot"
59 #define PREDEF_PWROFF_POPUP             "pwroff-popup"
60 #define PREDEF_INTERNAL_POWEROFF        "internal_poweroff"
61 #define PREDEF_FLIGHT_MODE              "flightmode"
62
63 #define POWEROFF_NOTI_NAME              "power_off_start"
64 #define POWEROFF_DURATION               2
65 #define MAX_RETRY                       2
66
67 static struct timeval tv_start_poweroff;
68
69 static Ecore_Timer *poweroff_timer_id = NULL;
70 static TapiHandle *tapi_handle = NULL;
71 static int power_off = 0;
72
73 static void poweroff_popup_edbus_signal_handler(void *data, DBusMessage *msg)
74 {
75         DBusError err;
76         char *str;
77         int val = 0;
78
79         if (dbus_message_is_signal(msg, INTERFACE_NAME, SIGNAL_NAME_POWEROFF_POPUP) == 0) {
80                 _E("there is no power off popup signal");
81                 return;
82         }
83
84         dbus_error_init(&err);
85
86         if (dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID) == 0) {
87                 _E("there is no message");
88                 return;
89         }
90
91         if (strncmp(str, PREDEF_PWROFF_POPUP, strlen(PREDEF_PWROFF_POPUP)) == 0)
92                 val = VCONFKEY_SYSMAN_POWER_OFF_POPUP;
93         else if (strncmp(str, PREDEF_POWEROFF, strlen(PREDEF_POWEROFF)) == 0)
94                 val = VCONFKEY_SYSMAN_POWER_OFF_DIRECT;
95         else if (strncmp(str, PREDEF_POWEROFF, strlen(PREDEF_REBOOT)) == 0)
96                 val = VCONFKEY_SYSMAN_POWER_OFF_RESTART;
97         if (val == 0) {
98                 _E("not supported message : %s", str);
99                 return;
100         }
101         vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, val);
102 }
103
104 static void poweroff_control_cb(keynode_t *in_key, struct ss_main_data *ad)
105 {
106         int val;
107         if (vconf_get_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, &val) != 0)
108                 return;
109         switch (val) {
110         case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
111                 ss_action_entry_call_internal(PREDEF_POWEROFF, 0);
112                 break;
113         case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
114                 ss_action_entry_call_internal(PREDEF_PWROFF_POPUP, 0);
115                 break;
116         case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
117                 ss_action_entry_call_internal(PREDEF_REBOOT, 0);
118                 break;
119         }
120
121         if (update_pm_setting)
122                 update_pm_setting(SETTING_POWEROFF, val);
123 }
124
125 static void remount_ro()
126 {
127         struct mntent* mnt;
128         const char* table = "/etc/mtab";
129         const char mmtpoint[10][64];
130         FILE* fp;
131         int r = -1, foundmount=0;
132         char buf[256];
133         fp = setmntent(table, "r");
134
135         if (!fp)
136                 return;
137
138         while (mnt=getmntent(fp)) {
139                 if (foundmount >= 10)
140                         continue;
141                 if (!strcmp(mnt->mnt_type, "ext4") && strstr(mnt->mnt_opts, "rw")) {
142                         memset(mmtpoint[foundmount], 0, 64);
143                         strncpy(mmtpoint[foundmount], mnt->mnt_dir, 63);
144                         foundmount++;
145                 }
146         }
147         endmntent(fp);
148         while (foundmount) {
149                 foundmount--;
150                 snprintf(buf, sizeof(buf), "fuser -c %s -k -15", mmtpoint[foundmount]);
151                 sleep(1);
152                 umount2(mmtpoint[foundmount], MNT_DETACH);
153         }
154 }
155
156 static void enter_flight_mode_cb(TapiHandle *handle, int result, void *data, void *user_data)
157 {
158         int bCurFlightMode = 0;
159         if (result != TAPI_POWER_FLIGHT_MODE_ENTER) {
160                 _E("flight mode enter failed %d",result);
161         } else {
162                 _D("enter flight mode result : %d",result);
163                 if (vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE,&bCurFlightMode) == 0) {
164                         _D("Flight Mode is %d", bCurFlightMode);
165                 } else {
166                         _E("failed to get vconf key");
167                 }
168         }
169 }
170
171 static void leave_flight_mode_cb(TapiHandle *handle, int result, void *data, void *user_data)
172 {
173         int bCurFlightMode = 0;
174         if (result != TAPI_POWER_FLIGHT_MODE_LEAVE) {
175                 _E("flight mode leave failed %d",result);
176         } else {
177                 _D("leave flight mode result : %d",result);
178                 if (vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE,&bCurFlightMode) == 0) {
179                         _D("Flight Mode is %d", bCurFlightMode);
180                 } else {
181                         _E("failed to get vconf key");
182                 }
183         }
184 }
185
186 int flight_mode_def_predefine_action(int argc, char **argv)
187 {
188         int bCurFlightMode;
189         int err = TAPI_API_SUCCESS;
190         if (argc != 1 || argv[0] == NULL) {
191                 _E("FlightMode Set predefine action failed");
192                 return -1;
193         }
194         bCurFlightMode = atoi(argv[0]);
195         if (bCurFlightMode == 1) {
196                 err = tel_set_flight_mode(tapi_handle, TAPI_POWER_FLIGHT_MODE_LEAVE, leave_flight_mode_cb, NULL);
197         } else if (bCurFlightMode == 0) {
198                 err = tel_set_flight_mode(tapi_handle, TAPI_POWER_FLIGHT_MODE_ENTER, enter_flight_mode_cb, NULL);
199         }
200         if (err != TAPI_API_SUCCESS)
201                 _E("FlightMode tel api action failed %d",err);
202         return 0;
203
204 }
205
206 static void __tel_init_cb(keynode_t *key_nodes,void *data)
207 {
208         int bTelReady = 0;
209         bTelReady = vconf_keynode_get_bool(key_nodes);
210         if (bTelReady == 1) {
211                 vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, (void*)__tel_init_cb);
212                 tapi_handle = tel_init(NULL);
213                 if (tapi_handle == NULL) {
214                         _E("tapi init error");
215                 }
216         } else {
217                 _E("tapi is not ready yet");
218         }
219 }
220
221 Eina_Bool powerdown_ap_by_force(void *data)
222 {
223         struct timeval now;
224         int poweroff_duration = POWEROFF_DURATION;
225         char *buf;
226
227         if(tapi_handle != NULL)
228         {
229                 tel_deinit(tapi_handle);
230                 tapi_handle = NULL;
231         }
232         /* Getting poweroff duration */
233         buf = getenv("PWROFF_DUR");
234         if (buf != NULL && strlen(buf) < 1024)
235                 poweroff_duration = atoi(buf);
236         if (poweroff_duration < 0 || poweroff_duration > 60)
237                 poweroff_duration = POWEROFF_DURATION;
238
239         gettimeofday(&now, NULL);
240         /* Waiting until power off duration and displaying animation */
241         while (now.tv_sec - tv_start_poweroff.tv_sec < poweroff_duration) {
242                 usleep(100000);
243                 gettimeofday(&now, NULL);
244         }
245
246         _I("Power off by force");
247         /* give a chance to be terminated for each process */
248         power_off = 1;
249         sync();
250         remount_ro();
251         reboot(RB_POWER_OFF);
252         return EINA_TRUE;
253 }
254
255 static void powerdown_ap(TapiHandle *handle, const char *noti_id, void *data, void *user_data)
256 {
257         struct timeval now;
258         int poweroff_duration = POWEROFF_DURATION;
259         char *buf;
260
261         if (poweroff_timer_id) {
262                 ecore_timer_del(poweroff_timer_id);
263                 poweroff_timer_id = NULL;
264         }
265         if (tapi_handle) {
266                 tel_deregister_noti_event(tapi_handle,TAPI_NOTI_MODEM_POWER);
267                 tel_deinit(tapi_handle);
268                 tapi_handle = NULL;
269         }
270
271         _I("Power off");
272
273         /* Getting poweroff duration */
274         buf = getenv("PWROFF_DUR");
275         if (buf != NULL && strlen(buf) < 1024)
276                 poweroff_duration = atoi(buf);
277         if (poweroff_duration < 0 || poweroff_duration > 60)
278                 poweroff_duration = POWEROFF_DURATION;
279
280         gettimeofday(&now, NULL);
281         /* Waiting until power off duration and displaying animation */
282         while (now.tv_sec - tv_start_poweroff.tv_sec < poweroff_duration) {
283                 usleep(100000);
284                 gettimeofday(&now, NULL);
285         }
286
287         /* give a chance to be terminated for each process */
288         power_off = 1;
289         sync();
290         remount_ro();
291         reboot(RB_POWER_OFF);
292 }
293 static void powerdown_res_cb(TapiHandle *handle, int result, void *data, void *user_data)
294 {
295         _D("poweroff command request : %d",result);
296 }
297
298
299 int internal_poweroff_def_predefine_action(int argc, char **argv)
300 {
301         int ret;
302
303         display_device_ops.exit(NULL);
304         system("/usr/lib/system-server/shutdown.sh &");
305         sync();
306
307         gettimeofday(&tv_start_poweroff, NULL);
308         if (tapi_handle) {
309                 ret = tel_register_noti_event(tapi_handle, TAPI_NOTI_MODEM_POWER, powerdown_ap, NULL);
310
311                 if (ret != TAPI_API_SUCCESS) {
312                         _E("tel_register_event is not subscribed. error %d", ret);
313                         powerdown_ap_by_force(NULL);
314                         return 0;
315                 }
316
317                 ret = tel_process_power_command(tapi_handle, TAPI_PHONE_POWER_OFF, powerdown_res_cb, NULL);
318                 if (ret != TAPI_API_SUCCESS) {
319                         _E("tel_process_power_command() error %d\n", ret);
320                         powerdown_ap_by_force(NULL);
321                         return 0;
322                 }
323                 poweroff_timer_id = ecore_timer_add(15, powerdown_ap_by_force, NULL);
324         } else {
325                 powerdown_ap_by_force(NULL);
326         }
327         return 0;
328 }
329
330 static void restart_ap(TapiHandle *handle, const char *noti_id, void *data, void *user_data);
331
332 Eina_Bool restart_ap_ecore(void *data)
333 {
334         restart_ap(tapi_handle,NULL,(void *)-1,NULL);
335         return EINA_TRUE;
336 }
337
338 static void restart_ap(TapiHandle *handle, const char *noti_id, void *data, void *user_data)
339 {
340         struct timeval now;
341         int poweroff_duration = POWEROFF_DURATION;
342         char *buf;
343
344         if (poweroff_timer_id) {
345                 ecore_timer_del(poweroff_timer_id);
346                 poweroff_timer_id = NULL;
347         }
348
349
350         if(tapi_handle != NULL)
351         {
352                 tel_deregister_noti_event(tapi_handle,TAPI_NOTI_MODEM_POWER);
353                 tel_deinit(tapi_handle);
354                 tapi_handle = NULL;
355         }
356
357         _I("Restart");
358         vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, (void*)poweroff_control_cb);
359         power_off = 1;
360         sync();
361
362         buf = getenv("PWROFF_DUR");
363         if (buf != NULL && strlen(buf) < 1024)
364                 poweroff_duration = atoi(buf);
365         if (poweroff_duration < 0 || poweroff_duration > 60)
366                 poweroff_duration = POWEROFF_DURATION;
367         gettimeofday(&now, NULL);
368         while (now.tv_sec - tv_start_poweroff.tv_sec < poweroff_duration) {
369                 usleep(100000);
370                 gettimeofday(&now, NULL);
371         }
372         remount_ro();
373
374         reboot(RB_AUTOBOOT);
375 }
376
377 static void restart_ap_by_force(void *data)
378 {
379         struct timeval now;
380         int poweroff_duration = POWEROFF_DURATION;
381         char *buf;
382
383         if (poweroff_timer_id) {
384                 ecore_timer_del(poweroff_timer_id);
385                 poweroff_timer_id = NULL;
386         }
387
388         if(tapi_handle != NULL) {
389                 tel_deinit(tapi_handle);
390                 tapi_handle = NULL;
391         }
392
393         _I("Restart");
394         power_off = 1;
395         sync();
396
397         buf = getenv("PWROFF_DUR");
398         if (buf != NULL && strlen(buf) < 1024)
399                 poweroff_duration = atoi(buf);
400         if (poweroff_duration < 0 || poweroff_duration > 60)
401                 poweroff_duration = POWEROFF_DURATION;
402         gettimeofday(&now, NULL);
403         while (now.tv_sec - tv_start_poweroff.tv_sec < poweroff_duration) {
404                 usleep(100000);
405                 gettimeofday(&now, NULL);
406         }
407         remount_ro();
408
409         reboot(RB_AUTOBOOT);
410 }
411
412 int entersleep_def_predefine_action(int argc, char **argv)
413 {
414         int ret;
415
416         pm_change_internal(getpid(), LCD_NORMAL);
417         system("/usr/lib/system-server/shutdown.sh &");
418         sync();
419
420         ret = tel_set_flight_mode(tapi_handle, TAPI_POWER_FLIGHT_MODE_ENTER, enter_flight_mode_cb, NULL);
421         _I("request for changing into flight mode : %d", ret);
422
423         system("/etc/rc.d/rc.entersleep");
424         pm_change_internal(getpid(), POWER_OFF);
425
426         return 0;
427 }
428
429 int poweroff_def_predefine_action(int argc, char **argv)
430 {
431         int retry_count = 0;
432
433         heynoti_publish(POWEROFF_NOTI_NAME);
434
435         while (retry_count < MAX_RETRY) {
436                 if (ss_action_entry_call_internal(PREDEF_INTERNAL_POWEROFF, 0) < 0) {
437                         _E("failed to request poweroff to system_server");
438                         retry_count++;
439                         continue;
440                 }
441                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, (void*)poweroff_control_cb);
442                 return 0;
443         }
444         return -1;
445 }
446
447 int launching_predefine_action(int argc, char **argv)
448 {
449         int ret;
450
451         if (argc < 0)
452                 return -1;
453
454         /* current just launching poweroff-popup */
455         if (predefine_control_launch("poweroff-syspopup", NULL, 0) < 0) {
456                 _E("poweroff-syspopup launch failed");
457                 return -1;
458         }
459         return 0;
460 }
461
462 int leavesleep_def_predefine_action(int argc, char **argv)
463 {
464         int ret;
465
466         pm_change_internal(getpid(), LCD_NORMAL);
467         sync();
468
469         ret = tel_set_flight_mode(tapi_handle, TAPI_POWER_FLIGHT_MODE_LEAVE, leave_flight_mode_cb, NULL);
470         _I("request for changing into flight mode : %d", ret);
471
472         return 0;
473 }
474
475 int restart_def_predefine_action(int argc, char **argv)
476 {
477         int ret;
478
479         heynoti_publish(POWEROFF_NOTI_NAME);
480         pm_change_internal(getpid(), LCD_NORMAL);
481         display_device_ops.exit(NULL);
482         system("/etc/rc.d/rc.shutdown &");
483         sync();
484
485         gettimeofday(&tv_start_poweroff, NULL);
486
487         ret =
488             tel_register_noti_event(tapi_handle, TAPI_NOTI_MODEM_POWER, restart_ap, NULL);
489         if (ret != TAPI_API_SUCCESS) {
490                 _E("tel_register_event is not subscribed. error %d", ret);
491                 restart_ap_by_force((void *)-1);
492                 return 0;
493         }
494
495
496         ret = tel_process_power_command(tapi_handle, TAPI_PHONE_POWER_OFF, powerdown_res_cb, NULL);
497         if (ret != TAPI_API_SUCCESS) {
498                 _E("tel_process_power_command() error %d", ret);
499                 restart_ap_by_force((void *)-1);
500                 return 0;
501         }
502
503         poweroff_timer_id = ecore_timer_add(15, restart_ap_ecore, NULL);
504         return 0;
505 }
506
507 static void power_init(void *data)
508 {
509         int bTelReady = 0;
510
511         if (vconf_get_bool(VCONFKEY_TELEPHONY_READY,&bTelReady) == 0) {
512                 if (bTelReady == 1) {
513                         tapi_handle = tel_init(NULL);
514                         if (tapi_handle == NULL) {
515                                 _E("tapi init error");
516                         }
517                 } else {
518                         vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY, (void *)__tel_init_cb, NULL);
519                 }
520         } else {
521                 _E("failed to get tapi vconf key");
522         }
523
524         ss_action_entry_add_internal(PREDEF_ENTERSLEEP,
525                                      entersleep_def_predefine_action, NULL,
526                                      NULL);
527         ss_action_entry_add_internal(PREDEF_POWEROFF,
528                                      poweroff_def_predefine_action, NULL, NULL);
529         ss_action_entry_add_internal(PREDEF_PWROFF_POPUP,
530                                      launching_predefine_action, NULL, NULL);
531         ss_action_entry_add_internal(PREDEF_LEAVESLEEP,
532                                      leavesleep_def_predefine_action, NULL,
533                                      NULL);
534         ss_action_entry_add_internal(PREDEF_REBOOT,
535                                      restart_def_predefine_action, NULL, NULL);
536
537         ss_action_entry_add_internal(PREDEF_INTERNAL_POWEROFF,
538                                      internal_poweroff_def_predefine_action, NULL, NULL);
539
540         ss_action_entry_add_internal(PREDEF_FLIGHT_MODE,
541                                      flight_mode_def_predefine_action, NULL, NULL);
542
543         if (vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, (void *)poweroff_control_cb, NULL) < 0) {
544                 _E("Vconf notify key chaneged failed: KEY(%s)", VCONFKEY_SYSMAN_POWER_OFF_STATUS);
545         }
546
547         register_edbus_signal_handler(OBJECT_PATH, INTERFACE_NAME,
548                         SIGNAL_NAME_POWEROFF_POPUP,
549                     (void *)poweroff_popup_edbus_signal_handler);
550         register_edbus_signal_handler(OBJECT_PATH, INTERFACE_NAME,
551                         SIGNAL_NAME_LCD_CONTROL,
552                     (void *)lcd_control_edbus_signal_handler);
553 }
554
555 const struct device_ops power_device_ops = {
556         .init = power_init,
557 };