22a7415dcdcf03658563817de76f884c393b0540
[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 "core/launch.h"
37 #include "core/devices.h"
38 #include "shared/device-notifier.h"
39 #include "shared/common.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-handler.h"
47 #include "apps/apps.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 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         FIND_DEVICE_INT(ops, POWER_OPS_NAME);
157
158         return ops->execute(data);
159 }
160
161 static int booting_done(void *data)
162 {
163         int status;
164         static int done;
165         static int popup;
166
167         if (data == NULL) {
168                 if (!done)
169                         popup = 1;
170                 goto out;
171         }
172
173         status = lowbat_initialized(NULL);
174         if (status == BATTERY_UNKNOWN)
175                 lowbat_monitor_init(NULL);
176
177         done = *(int *)data;
178         if (!done)
179                 goto out;
180         _I("Booting done.");
181         if (popup) {
182                 popup = 0;
183                 if (battery->charge_now != CHARGER_CHARGING &&
184                     battery->charge_full != CHARGING_FULL)
185                         lowbat_popup(BAT_OPT_NONE);
186                 else
187                         _I("Skip low battery popup during charging.");
188         }
189 out:
190         return done;
191 }
192
193 int lowbat_popup(int option)
194 {
195         static int launched_poweroff;
196         static int lowbat_popup_option;
197         static char *value;
198
199         if (option == BAT_OPT_NONE) {
200                 if (!value)
201                         return -1;
202                 else
203                         goto direct_launch;
204         }
205
206         if (option == BAT_OPT_POWEROFF)
207                 launched_poweroff = 0;
208
209         switch (option) {
210         case BAT_OPT_CRITICAL:
211                 value = "lowbattery_critical";
212                 break;
213         case BAT_OPT_WARNING:
214                 value = "lowbattery_warning";
215                 break;
216         case BAT_OPT_POWEROFF:
217                 value = "poweroff";
218                 break;
219         case BAT_OPT_ERR_TEMP_LOW:
220                 value = "chargeerrlow";
221                 break;
222         case BAT_OPT_ERR_TEMP_HIGH:
223                 value = "chargeerrhigh";
224                 break;
225         case BAT_OPT_ERR_CF_OPEN:
226                 value = "battdisconnect";
227                 break;
228         default:
229                 return -1;
230         }
231
232         lowbat_popup_option = option;
233
234 direct_launch:
235         _D("Popup value=%s", value);
236         if (booting_done(NULL)) {
237
238                 if (launched_poweroff == 1) {
239                         _I("Will be foreced power off.");
240                         power_execute(POWER_POWEROFF);
241                         return 0;
242                 }
243
244                 if (lowbat_popup_option == BAT_OPT_POWEROFF)
245                         launched_poweroff = 1;
246
247                 if (battery_do_not_disturb()) {
248                         _I("block LCD and %s Popup", value);
249                         return 0;
250                 }
251                 if (lowbat_popup_option == BAT_OPT_ERR_TEMP_LOW ||
252                     lowbat_popup_option == BAT_OPT_ERR_TEMP_HIGH ||
253                     lowbat_popup_option == BAT_OPT_ERR_CF_OPEN) {
254                         if (disp_plgn->pm_change_internal)
255                                 disp_plgn->pm_change_internal(INTERNAL_LOCK_LOWBAT, LCD_DIM);
256                 } else {
257                         if (disp_plgn->pm_change_internal)
258                                 disp_plgn->pm_change_internal(INTERNAL_LOCK_LOWBAT, LCD_NORMAL);
259                 }
260                 if (lowbat_popup_option == BAT_OPT_ERR_TEMP_LOW ||
261                     lowbat_popup_option == BAT_OPT_ERR_TEMP_HIGH ||
262                     lowbat_popup_option == BAT_OPT_ERR_CF_OPEN)
263                         return launch_system_app(APP_ABNORMAL,
264                                 2, APP_KEY_TYPE, value);
265                 return launch_system_app(APP_DEFAULT,
266                                 2, APP_KEY_TYPE, value);
267         } else
268                 _D("Boot-animation running yet.");
269
270         return 0;
271 }
272
273 static int battery_warning_low_act(void *data)
274 {
275         if (battery_plgn->lowbat_noti_launch)
276                 battery_plgn->lowbat_noti_launch(cur_bat_capacity, BAT_OPT_WARNING);
277
278         (void)lowbat_popup(BAT_OPT_WARNING);
279         return 0;
280 }
281
282 static int battery_critical_low_act(void *data)
283 {
284         if (battery_plgn->lowbat_noti_launch)
285                 battery_plgn->lowbat_noti_launch(cur_bat_capacity, BAT_OPT_CRITICAL);
286
287         (void)lowbat_popup(BAT_OPT_CRITICAL);
288         return 0;
289 }
290
291 int battery_power_off_act(void *data)
292 {
293         CRITICAL_LOG("Low battery power off.");
294         return power_execute(POWER_POWEROFF);
295 }
296
297 int battery_charge_err_cf_act(void *data)
298 {
299         return lowbat_popup(BAT_OPT_ERR_CF_OPEN);
300 }
301
302 int battery_charge_err_low_act(void *data)
303 {
304         if (disp_plgn->pm_lock_internal)
305                 disp_plgn->pm_lock_internal(INTERNAL_LOCK_OVERCOOL, LCD_OFF, STAY_CUR_STATE, 60000);
306         return lowbat_popup(BAT_OPT_ERR_TEMP_LOW);
307 }
308
309 int battery_charge_err_high_act(void *data)
310 {
311         if (disp_plgn->pm_lock_internal)
312                 disp_plgn->pm_lock_internal(INTERNAL_LOCK_OVERHEAT, LCD_OFF, STAY_CUR_STATE, 60000);
313         return lowbat_popup(BAT_OPT_ERR_TEMP_HIGH);
314 }
315
316 static void lowbat_scenario_init(void)
317 {
318         int ret;
319
320         ret = vconf_get_int(VCONF_KEY_BATTERY_WARNING_LEVEL, &custom_warning_level);
321         if (ret < 0)
322                 _E("Failed to get vconf value for battery warning level: %d", vconf_get_ext_errno());
323
324         if (custom_warning_level != BATTERY_UNKNOWN)
325                 battery_info.warning = custom_warning_level;
326
327         lowbat_add_scenario(battery_info.normal, battery_info.warning, battery_warning_low_act);
328         lowbat_add_scenario(battery_info.normal, battery_info.critical, battery_critical_low_act);
329         lowbat_add_scenario(battery_info.normal, battery_info.poweroff, battery_critical_low_act);
330         lowbat_add_scenario(battery_info.normal, battery_info.realoff, battery_power_off_act);
331         lowbat_add_scenario(battery_info.warning, battery_info.warning, battery_warning_low_act);
332         lowbat_add_scenario(battery_info.warning, battery_info.critical, battery_critical_low_act);
333         lowbat_add_scenario(battery_info.warning, battery_info.poweroff, battery_critical_low_act);
334         lowbat_add_scenario(battery_info.warning, battery_info.realoff, 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.realoff, battery_power_off_act);
337         lowbat_add_scenario(battery_info.poweroff, battery_info.poweroff, battery_critical_low_act);
338         lowbat_add_scenario(battery_info.poweroff, battery_info.realoff, battery_power_off_act);
339         lowbat_add_scenario(battery_info.realoff, battery_info.realoff, 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->online && custom_warning_launch)
435                 return;
436         if (battery->online > POWER_SUPPLY_TYPE_BATTERY && 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->online, 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.realoff) {
496                 if (battery->charge_now == CHARGER_CHARGING || battery->charger_charging == CHARGER_DISABLED) {
497                         _I("Skip lowbat poweroff during test (c:%d charge:%d online:%d charger_charging:%d)",
498                                 battery->capacity, battery->charge_now, battery->online, battery->charger_charging);
499                         new_bat_state = battery_info.poweroff;
500                         if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
501                                 status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
502                 } else {
503                         new_bat_state = battery_info.realoff;
504                         if (vconf_state != VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
505                                 status = VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF;
506                 }
507         } else if (new_bat_capacity <= battery_info.poweroff) {
508                 new_bat_state = battery_info.poweroff;
509                 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
510                         status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
511         } else if (new_bat_capacity <= battery_info.critical) {
512                 new_bat_state = battery_info.critical;
513                 if (vconf_state != VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
514                         status = VCONFKEY_SYSMAN_BAT_CRITICAL_LOW;
515         } else if (new_bat_capacity <= battery_info.warning) {
516                 new_bat_state = battery_info.warning;
517                 if (vconf_state != VCONFKEY_SYSMAN_BAT_WARNING_LOW)
518                         status = VCONFKEY_SYSMAN_BAT_WARNING_LOW;
519         } else {
520                 new_bat_state = battery_info.normal;
521                 if (new_bat_capacity == BATTERY_FULL) {
522                         if (battery->charge_full) {
523                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_FULL)
524                                         status = VCONFKEY_SYSMAN_BAT_FULL;
525                         } else {
526                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
527                                         status = VCONFKEY_SYSMAN_BAT_NORMAL;
528                         }
529                 } else {
530                         if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
531                                 status = VCONFKEY_SYSMAN_BAT_NORMAL;
532                 }
533         }
534
535         /* If the battery continues to run out even though it is being charged
536          * for a certain period of time, turn off the device. */
537         if (new_bat_capacity <= battery_info.realoff && battery->charge_now == CHARGER_CHARGING) {
538                 if (low_bat_skip_cnt >= RETRY_MAX) {
539                         new_bat_state = battery_info.realoff;
540                         status = VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF;
541                         _I("Go to real poweroff inspite of charging (c:%d charge:%d online:%d charger_charging %d current now %d)",
542                                 battery->capacity, battery->charge_now, battery->online, battery->charger_charging, battery->current_now);
543                         low_bat_skip_cnt = 0;
544                 } else if (battery->current_now <= MIN_INOW_VALUE) {
545                         low_bat_skip_cnt++;
546                 } else {
547                         low_bat_skip_cnt = 0;
548                 }
549         } else {
550                 low_bat_skip_cnt = 0;
551         }
552
553         if (status != -1) {
554                 result = status;
555                 if (disp_plgn->update_pm_setting)
556                         disp_plgn->update_pm_setting(SETTING_LOW_BATT, status);
557         } else
558                 result = vconf_state;
559
560         check_extreme_status(status);
561
562         if (new_bat_capacity <= battery_info.warning)
563                 low_bat = true;
564
565         if (low_bat_old != low_bat) {
566                 device_notify(DEVICE_NOTIFIER_LOWBAT, (void *)&low_bat);
567                 low_bat_old = low_bat;
568         }
569
570         if (battery->online == POWER_SUPPLY_TYPE_UNKNOWN)
571                 return result;
572         if (cur_bat_state == new_bat_state && online == battery->online)
573                 return result;
574
575         online = battery->online;
576         if (cur_bat_state == BATTERY_UNKNOWN)
577                 cur_bat_state = battery_info.normal;
578         if (lowbat_scenario(cur_bat_state, new_bat_state, NULL))
579                 _I("Cur(%d) new(%d) capacity(%d).", cur_bat_state, new_bat_state, bat_percent);
580                 cur_bat_state = new_bat_state;
581
582         return result;
583 }
584
585 static int check_lowbat_percent(int *pct)
586 {
587         int bat_percent;
588
589         bat_percent = battery->capacity;
590         if (bat_percent < 0)
591                 return -ENODEV;
592         if (bat_percent > 100)
593                 bat_percent = 100;
594         change_lowbat_level(bat_percent);
595         battery_level_send_system_event(bat_percent);
596         *pct = bat_percent;
597         return 0;
598 }
599
600 static int lowbat_monitor(void *data)
601 {
602         int bat_percent, r;
603
604         r = lowbat_initialized(NULL);
605         if (r != BATTERY_ENABLED)
606                 return battery->charging_level;
607
608         if (data == NULL) {
609                 r = check_lowbat_percent(&bat_percent);
610                 if (r < 0)
611                         return battery->charging_level;
612         } else
613                 bat_percent = *(int *)data;
614         return lowbat_process(bat_percent, NULL);
615 }
616
617 static int lowbat_monitor_init(void *data)
618 {
619         int status;
620
621         status = lowbat_initialized(NULL);
622         if (status != BATTERY_UNKNOWN)
623                 return 0;
624
625         status = BATTERY_ENABLED;
626         lowbat_initialized(&status);
627
628         /* it's called just this once. */
629         unregister_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
630
631         /* load battery configuration file */
632         battery_config_load(&battery_info);
633         _I("Battery conf: %d %d %d %d %d", battery_info.normal, battery_info.warning,
634                 battery_info.critical, battery_info.poweroff, battery_info.realoff);
635
636         lowbat_scenario_init();
637         check_lowbat_percent(&battery->capacity);
638         lowbat_process(battery->capacity, NULL);
639         return 0;
640 }
641
642
643 static GVariant * dbus_set_lowbat_level(GDBusConnection *conn,
644         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
645         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
646 {
647         int ret = 0;
648         int now;
649         int status;
650
651         g_variant_get(param, "(i)", &now);
652
653         status = lowbat_initialized(NULL);
654         if (status != BATTERY_ENABLED) {
655                 _E("Invalid lowbat handler.");
656                 ret = -EINVAL;
657                 goto out;
658         }
659
660         if (now <= battery_info.warning && now != BATTERY_UNKNOWN) {
661                 _E("Invalid level is requested: %d", now);
662                 ret = -EINVAL;
663                 goto out;
664         }
665
666         custom_warning_level = now;
667         custom_warning_launch = false;
668
669         ret = vconf_set_int(VCONF_KEY_BATTERY_WARNING_LEVEL, custom_warning_level);
670         if (ret < 0)
671                 _E("Failed to set vconf value for battery warning level: %d", vconf_get_ext_errno());
672         _D("Custom warning level is changed to %d.", custom_warning_level);
673
674 out:
675         return g_variant_new("(i)", ret);
676 }
677
678 static GVariant * dbus_get_lowbat_level(GDBusConnection *conn,
679         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
680         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
681 {
682         _D("Warning level: %d", custom_warning_level);
683         return g_variant_new("(i)", custom_warning_level);
684 }
685
686 static const dbus_method_s dbus_methods[] = {
687         { "SetLowbatLevel",  "i", "i", dbus_set_lowbat_level },
688         { "GetLowbatLevel",  NULL, "i", dbus_get_lowbat_level },
689         /* Add methods here */
690 };
691
692 static const dbus_interface_u dbus_interface = {
693         .oh = NULL,
694         .name = DEVICED_INTERFACE_BATTERY,
695         .methods = dbus_methods,
696         .nr_methods = ARRAY_SIZE(dbus_methods),
697 };
698
699 static int lowbat_probe(void *data)
700 {
701         static const struct device_ops *ops;
702         int ret = -EINVAL;
703
704         FIND_DEVICE_INT(ops, "power_supply");
705         ret = ops->probe(data);
706         if (ret == 0)
707                 _I("Support lowbat handler.");
708
709         return ret;
710 }
711
712 static void lowbat_init(void *data)
713 {
714         int ret;
715
716         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
717         register_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
718
719         ret = gdbus_add_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
720         if (ret < 0)
721                 _E("Failed to init dbus method: %d", ret);
722 }
723
724 static void lowbat_exit(void *data)
725 {
726         int status = BATTERY_DISABLED;
727
728         lowbat_initialized(&status);
729         if (low_batt_sig_timer) {
730                 g_source_remove(low_batt_sig_timer);
731                 low_batt_sig_timer = 0;
732         }
733 }
734
735 static gboolean low_battery_charge_status(void *data)
736 {
737         low_batt_sig_timer = 0;
738         battery->charging_level = lowbat_monitor(data);
739         if (battery->charging_level > 0 && old_battery.charging_level != battery->charging_level) {
740                 if (vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, battery->charging_level) < 0)
741                         _E("Fail to set level.");
742                 if (power_supply_broadcast(CHARGE_LEVEL_SIGNAL, battery->charging_level) < 0)
743                         _E("power_supply_broadcast failed");
744         }
745         return G_SOURCE_REMOVE;
746 }
747
748 static int lowbat_execute(void *data)
749 {
750         int capacity = *(int *)data;
751
752         /* In battery kernel side, it has a requirement that battery charging event must get quickly.
753          * So deviced receives the discharging and charging event within 1.5 sec,
754          * added a timer to wait for the second signal, if there is no second signal then execute
755          * the lowbat_execute.
756          */
757         if (low_batt_sig_timer) {
758                 g_source_remove(low_batt_sig_timer);
759                 low_batt_sig_timer = 0;
760         }
761
762         /* Do lowbat_process immediately rather deferring it when poweroff is needed.
763          * This prevents poweroff from being delayed infinitely when the uevent continues
764          * to occur shorter than 1.5 seconds on realoff capacity */
765         if (capacity <= battery_info.realoff)
766                 low_battery_charge_status(data);
767         else
768                 low_batt_sig_timer = g_timeout_add(1500, low_battery_charge_status, data);
769
770         return 0;
771 }
772
773 static const struct device_ops lowbat_device_ops = {
774         DECLARE_NAME_LEN("lowbat"),
775         .probe    = lowbat_probe,
776         .init     = lowbat_init,
777         .execute  = lowbat_execute,
778         .exit     = lowbat_exit,
779 };
780
781 DEVICE_OPS_REGISTER(&lowbat_device_ops)
782
783 static void __CONSTRUCTOR__ initialize(void)
784 {
785         disp_plgn = get_var_display_plugin();
786         if (!disp_plgn)
787                 _E("Failed to get display plugin variable.");
788
789         battery_plgn = get_var_battery_plugin();
790         if (!battery_plgn)
791                 _E("Failed to get battery plugin variable.");
792
793         battery = get_var_battery_status();
794         if (!battery)
795                 _E("Failed to get battery status structure variable.");
796 }