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