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