050defe7be59bb72d67226bdec7ecb7ebd55752f
[platform/core/system/deviced.git] / src / battery / lowbat-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 <stdbool.h>
21 #include <assert.h>
22 #include <limits.h>
23 #include <vconf.h>
24 #include <fcntl.h>
25 #include <bundle.h>
26 #include <eventsystem.h>
27 #include <hal/device/hal-battery.h>
28 #include <libsyscommon/libgdbus.h>
29 #include <libsyscommon/list.h>
30
31 #include "lowbat-handler.h"
32 #include "battery-ops.h"
33 #include "battery.h"
34 #include "config.h"
35 #include "core/log.h"
36 #include "shared/devices.h"
37 #include "shared/device-notifier.h"
38 #include "shared/common.h"
39 #include "shared/apps.h"
40 #include "core/udev.h"
41 #include "shared/eventsystem.h"
42 #include "shared/plugin.h"
43 #include "display/setting.h"
44 #include "display/poll.h"
45 #include "display/display-ops.h"
46 #include "power/power.h"
47 #include "power/power-off.h"
48 #include "power-supply.h"
49
50 #define BATTERY_UNKNOWN         -1
51 #define BATTERY_DISABLED        0
52 #define BATTERY_ENABLED         1
53
54 #define VCONF_KEY_BATTERY_WARNING_LEVEL "db/sysman/battery_warning_level"
55
56 #define MIN_INOW_VALUE           -50
57
58 enum custom_level_control_type {
59         CUSTOM_CONTROL_NONE,
60         LOWER_THAN_WARNING,
61         HIGHER_THAN_WARNING,
62 };
63
64 struct lowbat_process_entry {
65         int old;
66         int now;
67         int (*func) (void *data);
68 };
69
70 static struct display_plugin *disp_plgn;
71 static struct battery_plugin *battery_plgn;
72
73 static struct battery_status *battery;
74
75 static int cur_bat_state = BATTERY_UNKNOWN;
76 static int cur_bat_capacity = BATTERY_UNKNOWN;
77 static int custom_warning_level = BATTERY_UNKNOWN;
78 static bool custom_warning_launch;
79
80 struct battery_config_info battery_info = {
81         .normal   = BATTERY_NORMAL,
82         .warning  = BATTERY_WARNING,
83         .critical = BATTERY_CRITICAL,
84         .poweroff = BATTERY_POWEROFF,
85         .realoff  = BATTERY_REALOFF,
86 };
87
88 static GList *lpe;
89 static int scenario_count;
90
91 static guint low_batt_sig_timer;
92
93 static int uevent_buffering = 0;
94 static int lowbat_monitor_init(void *data);
95
96 static int lowbat_initialized(void *data)
97 {
98         static int status = BATTERY_UNKNOWN;
99
100         if (!data)
101                 return status;
102
103         status = *(int *)data;
104         return status;
105 }
106
107 static int lowbat_scenario(int old, int now, void *data)
108 {
109         GList *n;
110         struct lowbat_process_entry *scenario;
111         int found = 0;
112
113         if (old == now && battery->charge_now)
114                 return found;
115         SYS_G_LIST_FOREACH(lpe, n, scenario) {
116                 if (old != scenario->old || now != scenario->now)
117                         continue;
118                 if (!scenario->func)
119                         continue;
120                 scenario->func(data);
121                         found = 1;
122                 break;
123         }
124         return found;
125 }
126
127 static int lowbat_add_scenario(int old, int now, int (*func)(void *data))
128 {
129         struct lowbat_process_entry *scenario;
130
131         _D("Lowbat_add_scenario: old(%d) now(%d) func(%p)", old, now, func);
132
133         if (!func) {
134                 _E("Invalid func address.");
135                 return -EINVAL;
136         }
137
138         scenario = malloc(sizeof(struct lowbat_process_entry));
139         if (!scenario) {
140                 _E("Failed to malloc for notifier.");
141                 return -ENOMEM;
142         }
143
144         scenario->old = old;
145         scenario->now = now;
146         scenario->func = func;
147
148         SYS_G_LIST_APPEND(lpe, scenario);
149         scenario_count++;
150         return 0;
151 }
152
153 static int power_execute(int state)
154 {
155         if (is_emulator()) {
156                 CRITICAL_LOG("Poweroff by lowbattery is disabled at emulator.");
157                 return 0;
158         }
159
160         power_request_change_state(state, LOWBAT_POWEROFF_REASON);
161
162         return 0;
163 }
164
165 static int delayed_init_done(void *data)
166 {
167         int status;
168         static int done;
169         static int popup;
170
171         if (data == NULL) {
172                 if (!done)
173                         popup = 1;
174                 goto out;
175         }
176
177         status = lowbat_initialized(NULL);
178         if (status == BATTERY_UNKNOWN)
179                 lowbat_monitor_init(NULL);
180
181         done = *(int *)data;
182         if (!done)
183                 goto out;
184         _I("Booting done.");
185         if (popup) {
186                 popup = 0;
187                 if (battery->charge_now != CHARGER_CHARGING &&
188                     battery->charge_full != CHARGING_FULL)
189                         lowbat_popup(BAT_OPT_NONE);
190                 else
191                         _I("Skip low battery popup during charging.");
192         }
193 out:
194         return done;
195 }
196
197 int lowbat_popup(int option)
198 {
199         static int launched_poweroff;
200         static int lowbat_popup_option;
201         static char *value;
202
203         if (option == BAT_OPT_NONE) {
204                 if (!value)
205                         return -1;
206                 else
207                         goto direct_launch;
208         }
209
210         if (option == BAT_OPT_POWEROFF)
211                 launched_poweroff = 0;
212
213         switch (option) {
214         case BAT_OPT_CRITICAL:
215                 value = "lowbattery_critical";
216                 break;
217         case BAT_OPT_WARNING:
218                 value = "lowbattery_warning";
219                 break;
220         case BAT_OPT_POWEROFF:
221                 value = "poweroff";
222                 break;
223         case BAT_OPT_ERR_TEMP_LOW:
224                 value = "chargeerrlow";
225                 break;
226         case BAT_OPT_ERR_TEMP_HIGH:
227                 value = "chargeerrhigh";
228                 break;
229         case BAT_OPT_ERR_CF_OPEN:
230                 value = "battdisconnect";
231                 break;
232         default:
233                 return -1;
234         }
235
236         lowbat_popup_option = option;
237
238 direct_launch:
239         _D("Popup value=%s", value);
240         if (delayed_init_done(NULL)) {
241
242                 if (launched_poweroff == 1) {
243                         _I("Will be foreced power off.");
244                         power_execute(POWER_STATE_POWEROFF);
245                         return 0;
246                 }
247
248                 if (lowbat_popup_option == BAT_OPT_POWEROFF)
249                         launched_poweroff = 1;
250
251                 if (battery_do_not_disturb()) {
252                         _I("block LCD and %s Popup", value);
253                         return 0;
254                 }
255                 if (lowbat_popup_option == BAT_OPT_ERR_TEMP_LOW ||
256                     lowbat_popup_option == BAT_OPT_ERR_TEMP_HIGH ||
257                     lowbat_popup_option == BAT_OPT_ERR_CF_OPEN) {
258                         if (disp_plgn->pm_change_internal)
259                                 disp_plgn->pm_change_internal(INTERNAL_LOCK_LOWBAT, LCD_DIM);
260                 } else {
261                         if (disp_plgn->pm_change_internal)
262                                 disp_plgn->pm_change_internal(INTERNAL_LOCK_LOWBAT, LCD_NORMAL);
263                 }
264                 if (lowbat_popup_option == BAT_OPT_ERR_TEMP_LOW ||
265                     lowbat_popup_option == BAT_OPT_ERR_TEMP_HIGH ||
266                     lowbat_popup_option == BAT_OPT_ERR_CF_OPEN)
267                         return launch_system_app(APP_ABNORMAL,
268                                 2, APP_KEY_TYPE, value);
269                 return launch_system_app(APP_DEFAULT,
270                                 2, APP_KEY_TYPE, value);
271         } else
272                 _D("Boot-animation running yet.");
273
274         return 0;
275 }
276
277 static int battery_warning_low_act(void *data)
278 {
279         if (battery_plgn->lowbat_noti_launch)
280                 battery_plgn->lowbat_noti_launch(cur_bat_capacity, BAT_OPT_WARNING);
281
282         (void)lowbat_popup(BAT_OPT_WARNING);
283         return 0;
284 }
285
286 static int battery_critical_low_act(void *data)
287 {
288         if (battery_plgn->lowbat_noti_launch)
289                 battery_plgn->lowbat_noti_launch(cur_bat_capacity, BAT_OPT_CRITICAL);
290
291         (void)lowbat_popup(BAT_OPT_CRITICAL);
292         return 0;
293 }
294
295 int battery_power_off_act(void *data)
296 {
297         CRITICAL_LOG("Low battery power off.");
298         return power_execute(POWER_STATE_POWEROFF);
299 }
300
301 int battery_charge_err_cf_act(void *data)
302 {
303         return lowbat_popup(BAT_OPT_ERR_CF_OPEN);
304 }
305
306 int battery_charge_err_low_act(void *data)
307 {
308         if (disp_plgn->pm_lock_internal)
309                 disp_plgn->pm_lock_internal(INTERNAL_LOCK_OVERCOOL, LCD_OFF, STAY_CUR_STATE, 60000);
310         return lowbat_popup(BAT_OPT_ERR_TEMP_LOW);
311 }
312
313 int battery_charge_err_high_act(void *data)
314 {
315         if (disp_plgn->pm_lock_internal)
316                 disp_plgn->pm_lock_internal(INTERNAL_LOCK_OVERHEAT, LCD_OFF, STAY_CUR_STATE, 60000);
317         return lowbat_popup(BAT_OPT_ERR_TEMP_HIGH);
318 }
319
320 static void lowbat_scenario_init(void)
321 {
322         int ret;
323
324         ret = vconf_get_int(VCONF_KEY_BATTERY_WARNING_LEVEL, &custom_warning_level);
325         if (ret < 0)
326                 _E("Failed to get vconf value for battery warning level: %d", vconf_get_ext_errno());
327
328         if (custom_warning_level != BATTERY_UNKNOWN)
329                 battery_info.warning = custom_warning_level;
330
331         lowbat_add_scenario(battery_info.normal, battery_info.warning, battery_warning_low_act);
332         lowbat_add_scenario(battery_info.normal, battery_info.critical, battery_critical_low_act);
333         lowbat_add_scenario(battery_info.normal, battery_info.poweroff, battery_critical_low_act);
334         lowbat_add_scenario(battery_info.normal, battery_info.realoff, battery_power_off_act);
335         lowbat_add_scenario(battery_info.warning, battery_info.warning, battery_warning_low_act);
336         lowbat_add_scenario(battery_info.warning, battery_info.critical, battery_critical_low_act);
337         lowbat_add_scenario(battery_info.warning, battery_info.poweroff, battery_critical_low_act);
338         lowbat_add_scenario(battery_info.warning, battery_info.realoff, battery_power_off_act);
339         lowbat_add_scenario(battery_info.critical, battery_info.critical, battery_critical_low_act);
340         lowbat_add_scenario(battery_info.critical, battery_info.realoff, battery_power_off_act);
341         lowbat_add_scenario(battery_info.poweroff, battery_info.poweroff, battery_critical_low_act);
342         lowbat_add_scenario(battery_info.poweroff, battery_info.realoff, battery_power_off_act);
343         lowbat_add_scenario(battery_info.realoff, battery_info.realoff, battery_power_off_act);
344 }
345
346 static void battery_level_send_system_event(int bat_percent)
347 {
348         const char *str;
349         static const char *prev;
350
351         if (bat_percent >= battery_info.normal && battery->charge_full == CHARGING_FULL)
352                 str = EVT_VAL_BATTERY_LEVEL_FULL;
353         else if (bat_percent > battery_info.warning)
354                 str = EVT_VAL_BATTERY_LEVEL_HIGH;
355         else if (bat_percent > battery_info.critical)
356                 str = EVT_VAL_BATTERY_LEVEL_LOW;
357         else if (bat_percent > battery_info.poweroff)
358                 str = EVT_VAL_BATTERY_LEVEL_CRITICAL;
359         else
360                 str = EVT_VAL_BATTERY_LEVEL_EMPTY;
361
362         if (battery_plgn->lowbat_noti_clean && prev)
363                 battery_plgn->lowbat_noti_clean(prev, str);
364
365         if (prev == str)
366                 return;
367
368         prev = str;
369
370         _D("System_event: %s", str);
371         CRITICAL_LOG("Battery %s.", str);
372         event_system_send(SYS_EVENT_BATTERY_LEVEL_STATUS,
373                         EVT_KEY_BATTERY_LEVEL_STATUS, str);
374 }
375
376 static void change_lowbat_level(int bat_percent)
377 {
378         int prev, now, ret;
379
380         ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, &prev);
381         if (ret < 0) {
382                 _E("Failed to get vconf value for battery level status: %d", vconf_get_ext_errno());
383                 return;
384         }
385
386         if (bat_percent >= battery_info.normal) {
387                 if (battery->charge_full == CHARGING_FULL)
388                         now = VCONFKEY_SYSMAN_BAT_LEVEL_FULL;
389                 else
390                         now = VCONFKEY_SYSMAN_BAT_LEVEL_HIGH;
391         } else if (bat_percent > battery_info.warning)
392                 now = VCONFKEY_SYSMAN_BAT_LEVEL_HIGH;
393         else if (bat_percent > battery_info.critical)
394                 now = VCONFKEY_SYSMAN_BAT_LEVEL_LOW;
395         else if (bat_percent > battery_info.poweroff)
396                 now = VCONFKEY_SYSMAN_BAT_LEVEL_CRITICAL;
397         else
398                 now = VCONFKEY_SYSMAN_BAT_LEVEL_EMPTY;
399
400         if (prev != now) {
401                 ret = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, now);
402                 if (ret < 0)
403                         _E("Failed to set vconf value for battery level status: %d", vconf_get_ext_errno());
404         }
405 }
406
407 static void lowbat_custom_popup(int online, int capacity)
408 {
409         static int custom_type = BATTERY_UNKNOWN;
410
411         if (custom_type == CUSTOM_CONTROL_NONE)
412                 return;
413         if (custom_warning_level == BATTERY_UNKNOWN ||
414             custom_warning_level == battery_info.warning)
415                 return;
416
417         if (custom_type == BATTERY_UNKNOWN) {
418                 if (custom_warning_level < battery_info.warning)
419                         custom_type = LOWER_THAN_WARNING;
420                 else if (custom_warning_level > battery_info.warning)
421                         custom_type = HIGHER_THAN_WARNING;
422                 else {
423                         custom_type = CUSTOM_CONTROL_NONE;
424                         _E("Custom type is not defined: %d", custom_warning_level);
425                         return;
426                 }
427         }
428
429         if (custom_type == LOWER_THAN_WARNING && capacity <= battery_info.critical)
430                 return;
431         if (custom_type == HIGHER_THAN_WARNING && capacity <= battery_info.warning)
432                 return;
433
434         if (capacity > custom_warning_level) {
435                 custom_warning_launch = false;
436                 return;
437         }
438         if (online == battery->charger_connected && custom_warning_launch)
439                 return;
440         if (battery->charger_connected == 1 && custom_warning_launch)
441                 return;
442
443         custom_warning_launch = true;
444         _I("Launch custom lowbattery warning popup. online(%d, %d), capacity(%d, %d)", online, battery->charger_connected, capacity, custom_warning_level);
445         (void)battery_warning_low_act(NULL);
446 }
447
448 void check_extreme_status(int status)
449 {
450         int extreme = 0;
451         int ret;
452
453         if (status <= VCONFKEY_SYSMAN_BAT_POWER_OFF ||
454             status > VCONFKEY_SYSMAN_BAT_FULL)
455                 return;
456         ret = vconf_get_int(VCONFKEY_PM_KEY_IGNORE, &extreme);
457         if (ret < 0)
458                 _E("Failed to get vconf value for pm key ignore: %d", vconf_get_ext_errno());
459         if (ret != 0 || extreme != 1)
460                 return;
461
462         ret = vconf_set_int(VCONFKEY_PM_KEY_IGNORE, 0);
463         if (ret != 0) {
464                 _E("Failed to set vconf value for pm key ignore: %d", vconf_get_ext_errno());
465                 return;
466         }
467         _I("Release key ignore.");
468 }
469
470 static int lowbat_process(int bat_percent, void *ad)
471 {
472         static int online;
473         static bool low_bat_old;
474         static int low_bat_skip_cnt = 0;
475         int new_bat_capacity;
476         int new_bat_state;
477         int vconf_state = -1;
478         int ret = 0;
479         int status = -1;
480         bool low_bat = false;
481         int result = 0;
482
483         if (!battery_initialized)
484                 return -EINVAL;
485
486         new_bat_capacity = bat_percent;
487         change_lowbat_level(new_bat_capacity);
488         lowbat_custom_popup(online, new_bat_capacity);
489         battery_level_send_system_event(new_bat_capacity);
490
491         cur_bat_capacity = new_bat_capacity;
492
493         ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &vconf_state);
494         if (ret < 0) {
495                 _E("Failed to get vconf value for battery status low: %d", vconf_get_ext_errno());
496                 return -EIO;
497         }
498
499         if (new_bat_capacity <= battery_info.realoff) {
500                 if (battery->charge_now == CHARGER_CHARGING) {
501                         new_bat_state = battery_info.poweroff;
502                         if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
503                                 status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
504                 } else {
505                         new_bat_state = battery_info.realoff;
506                         if (vconf_state != VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
507                                 status = VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF;
508                 }
509         } else if (new_bat_capacity <= battery_info.poweroff) {
510                 new_bat_state = battery_info.poweroff;
511                 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
512                         status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
513         } else if (new_bat_capacity <= battery_info.critical) {
514                 new_bat_state = battery_info.critical;
515                 if (vconf_state != VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
516                         status = VCONFKEY_SYSMAN_BAT_CRITICAL_LOW;
517         } else if (new_bat_capacity <= battery_info.warning) {
518                 new_bat_state = battery_info.warning;
519                 if (vconf_state != VCONFKEY_SYSMAN_BAT_WARNING_LOW)
520                         status = VCONFKEY_SYSMAN_BAT_WARNING_LOW;
521         } else {
522                 new_bat_state = battery_info.normal;
523                 if (new_bat_capacity == BATTERY_FULL) {
524                         if (battery->charge_full) {
525                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_FULL)
526                                         status = VCONFKEY_SYSMAN_BAT_FULL;
527                         } else {
528                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
529                                         status = VCONFKEY_SYSMAN_BAT_NORMAL;
530                         }
531                 } else {
532                         if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
533                                 status = VCONFKEY_SYSMAN_BAT_NORMAL;
534                 }
535         }
536
537         /* If the battery continues to run out even though it is being charged
538          * for a certain period of time, turn off the device. */
539         if (new_bat_capacity <= battery_info.realoff && battery->charge_now == CHARGER_CHARGING) {
540                 if (low_bat_skip_cnt >= RETRY_MAX) {
541                         new_bat_state = battery_info.realoff;
542                         status = VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF;
543                         _I("Go to real poweroff inspite of charging (c:%d charge:%d online:%d current_now:%d)",
544                                 battery->capacity, battery->charge_now, battery->charger_connected, battery->current_now);
545                         low_bat_skip_cnt = 0;
546                 } else if (battery->current_now <= MIN_INOW_VALUE) {
547                         low_bat_skip_cnt++;
548                 } else {
549                         low_bat_skip_cnt = 0;
550                 }
551         } else {
552                 low_bat_skip_cnt = 0;
553         }
554
555         if (status != -1) {
556                 result = status;
557                 if (disp_plgn->update_pm_setting)
558                         disp_plgn->update_pm_setting(SETTING_LOW_BATT, status);
559         } else
560                 result = vconf_state;
561
562         check_extreme_status(status);
563
564         if (new_bat_capacity <= battery_info.warning)
565                 low_bat = true;
566
567         if (low_bat_old != low_bat) {
568                 device_notify(DEVICE_NOTIFIER_LOWBAT, (void *)&low_bat);
569                 low_bat_old = low_bat;
570         }
571
572         if (battery->charger_connected == -1)
573                 return result;
574         if (cur_bat_state == new_bat_state && online == battery->charger_connected)
575                 return result;
576
577         online = battery->charger_connected;
578         if (cur_bat_state == BATTERY_UNKNOWN)
579                 cur_bat_state = battery_info.normal;
580         if (lowbat_scenario(cur_bat_state, new_bat_state, NULL))
581                 _I("Cur(%d) new(%d) capacity(%d).", cur_bat_state, new_bat_state, bat_percent);
582                 cur_bat_state = new_bat_state;
583
584         return result;
585 }
586
587 static int check_lowbat_percent(int *pct)
588 {
589         int bat_percent;
590
591         bat_percent = battery->capacity;
592         if (bat_percent < 0)
593                 return -ENODEV;
594         if (bat_percent > 100)
595                 bat_percent = 100;
596         change_lowbat_level(bat_percent);
597         battery_level_send_system_event(bat_percent);
598         *pct = bat_percent;
599         return 0;
600 }
601
602 static int lowbat_monitor(void *data)
603 {
604         int bat_percent, r;
605
606         r = lowbat_initialized(NULL);
607         if (r != BATTERY_ENABLED)
608                 return battery->capacity_level;
609
610         if (data == NULL) {
611                 r = check_lowbat_percent(&bat_percent);
612                 if (r < 0)
613                         return battery->capacity_level;
614         } else
615                 bat_percent = *(int *)data;
616         return lowbat_process(bat_percent, NULL);
617 }
618
619 static int lowbat_monitor_init(void *data)
620 {
621         int status;
622
623         status = lowbat_initialized(NULL);
624         if (status != BATTERY_UNKNOWN)
625                 return 0;
626
627         status = BATTERY_ENABLED;
628         lowbat_initialized(&status);
629
630         /* it's called just this once. */
631         unregister_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
632
633         /* load battery configuration file */
634         battery_config_load(&battery_info);
635         _I("Battery conf: %d %d %d %d %d", battery_info.normal, battery_info.warning,
636                 battery_info.critical, battery_info.poweroff, battery_info.realoff);
637
638         lowbat_scenario_init();
639         check_lowbat_percent(&battery->capacity);
640         lowbat_process(battery->capacity, NULL);
641         return 0;
642 }
643
644
645 static GVariant * dbus_set_lowbat_level(GDBusConnection *conn,
646         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
647         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
648 {
649         int ret = 0;
650         int now;
651         int status;
652
653         g_variant_get(param, "(i)", &now);
654
655         status = lowbat_initialized(NULL);
656         if (status != BATTERY_ENABLED) {
657                 _E("Invalid lowbat handler.");
658                 ret = -EINVAL;
659                 goto out;
660         }
661
662         if (now <= battery_info.warning && now != BATTERY_UNKNOWN) {
663                 _E("Invalid level is requested: %d", now);
664                 ret = -EINVAL;
665                 goto out;
666         }
667
668         custom_warning_level = now;
669         custom_warning_launch = false;
670
671         ret = vconf_set_int(VCONF_KEY_BATTERY_WARNING_LEVEL, custom_warning_level);
672         if (ret < 0)
673                 _E("Failed to set vconf value for battery warning level: %d", vconf_get_ext_errno());
674         _D("Custom warning level is changed to %d.", custom_warning_level);
675
676 out:
677         return g_variant_new("(i)", ret);
678 }
679
680 static GVariant * dbus_get_lowbat_level(GDBusConnection *conn,
681         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
682         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
683 {
684         _D("Warning level: %d", custom_warning_level);
685         return g_variant_new("(i)", custom_warning_level);
686 }
687
688 static const dbus_method_s dbus_methods[] = {
689         { "SetLowbatLevel",  "i", "i", dbus_set_lowbat_level },
690         { "GetLowbatLevel",  NULL, "i", dbus_get_lowbat_level },
691         /* Add methods here */
692 };
693
694 static const dbus_interface_u dbus_interface = {
695         .oh = NULL,
696         .name = DEVICED_INTERFACE_BATTERY,
697         .methods = dbus_methods,
698         .nr_methods = ARRAY_SIZE(dbus_methods),
699 };
700
701 static void lowbat_init(void *data)
702 {
703         int ret;
704
705         register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
706         register_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
707
708         ret = gdbus_add_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
709         if (ret < 0)
710                 _E("Failed to init dbus method: %d", ret);
711 }
712
713 static void lowbat_exit(void *data)
714 {
715         int status = BATTERY_DISABLED;
716
717         lowbat_initialized(&status);
718         if (low_batt_sig_timer) {
719                 g_source_remove(low_batt_sig_timer);
720                 low_batt_sig_timer = 0;
721         }
722 }
723
724 static gboolean low_battery_charging_status(void *data)
725 {
726         low_batt_sig_timer = 0;
727         battery->capacity_level = lowbat_monitor(data);
728         if (battery->capacity_level > 0 && old_battery.capacity_level != battery->capacity_level) {
729                 if (vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, battery->capacity_level) < 0)
730                         _E("Fail to set level.");
731                 if (power_supply_broadcast(CHARGE_LEVEL_SIGNAL, battery->capacity_level) < 0)
732                         _E("power_supply_broadcast failed");
733         }
734         return G_SOURCE_REMOVE;
735 }
736
737 static int lowbat_execute(void *data)
738 {
739         int capacity = *(int *)data;
740
741         /* In battery kernel side, it has a requirement that battery charging event must get quickly.
742          * So deviced receives the discharging and charging event within 1.5 sec,
743          * added a timer to wait for the second signal, if there is no second signal then execute
744          * the lowbat_execute.
745          */
746         if (low_batt_sig_timer) {
747                 g_source_remove(low_batt_sig_timer);
748                 low_batt_sig_timer = 0;
749         }
750
751         /* Do lowbat_process immediately rather deferring it when poweroff is needed.
752          * This prevents poweroff from being delayed infinitely when the uevent continues
753          * to occur shorter than 1.5 seconds on realoff capacity */
754         if (capacity <= battery_info.realoff || !uevent_buffering)
755                 low_battery_charging_status(data);
756         else
757                 low_batt_sig_timer = g_timeout_add(1500, low_battery_charging_status, data);
758
759         return 0;
760 }
761
762 void lowbat_enable_uevent_buffering(void)
763 {
764         uevent_buffering = 1;
765 }
766
767 void lowbat_disable_uevent_buffering(void)
768 {
769         uevent_buffering = 0;
770 }
771
772 static const struct device_ops lowbat_device_ops = {
773         DECLARE_NAME_LEN("lowbat"),
774         .init     = lowbat_init,
775         .execute  = lowbat_execute,
776         .exit     = lowbat_exit,
777 };
778
779 DEVICE_OPS_REGISTER(&lowbat_device_ops)
780
781 static void __CONSTRUCTOR__ initialize(void)
782 {
783         disp_plgn = get_var_display_plugin();
784         if (!disp_plgn)
785                 _E("Failed to get display plugin variable.");
786
787         battery_plgn = get_var_battery_plugin();
788         if (!battery_plgn)
789                 _E("Failed to get battery plugin variable.");
790
791         battery = get_var_battery_status();
792         if (!battery)
793                 _E("Failed to get battery status structure variable.");
794 }