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