4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <eventsystem.h>
25 #include <hal/device/hal-battery.h>
27 #include <libsyscommon/ini-parser.h>
29 #include "shared/devices.h"
30 #include "shared/device-notifier.h"
31 #include "core/udev.h"
33 #include "display/poll.h"
34 #include "display/setting.h"
35 #include "shared/eventsystem.h"
36 #include "shared/plugin.h"
37 #include "shared/apps.h"
38 #include "display/core.h"
39 #include "display/display-ops.h"
40 #include "power-supply.h"
42 #include "battery-ops.h"
43 #include "extcon/extcon.h"
44 #include "lowbat-handler.h"
46 #ifndef VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL
47 #define VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL "db/setting/blockmode_wearable"
50 #ifndef VCONFKEY_SETAPPL_THEATER_MODE_ENABLE
51 #define VCONFKEY_SETAPPL_THEATER_MODE_ENABLE "db/setting/theater_mode_enable"
54 #ifndef VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE
55 #define VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE "db/setting/goodnight_mode_enable"
58 #define BATTERY_NAME "battery"
59 #define CHARGEFULL_NAME "Full"
60 #define CHARGENOW_NAME "Charging"
61 #define DISCHARGE_NAME "Discharging"
62 #define NOTCHARGE_NAME "Not charging"
63 #define OVERHEAT_NAME "Overheat"
64 #define TEMPCOLD_NAME "Cold"
65 #define OVERVOLT_NAME "Over voltage"
66 #define GOOD_NAME "Good"
68 #define CHARGER_WIRELESS_TYPE_BT 10
69 #define CHARGER_WIRELESS_TYPE_3G 22
70 #define CHARGER_INCOMPATIBLE_TYPE 11
71 #define CHARGER_D2D_TYPE 110
72 #define WIRELESS_CHARGER_CONNECTED 2
74 #define SIGNAL_TEMP_GOOD "TempGood"
76 #define METHOD_FULL_NOTI_ON "BatteryFullNotiOn"
77 #define METHOD_FULL_NOTI_OFF "BatteryFullNotiOff"
78 #define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
80 #define CHARGER_CHARGE_ON_NODE "/sys/class/power_supply/battery/chg_on"
83 #define BATTERY_CHECK_TIMER_INTERVAL 500 /* 0.5 second */
84 #define LCD_DIM_TIME_IN_BATTERY_HEALTH 10000 /* ms */
86 static struct display_plugin *disp_plgn;
87 static struct battery_plugin *battery_plgn;
89 static struct battery_status battery;
90 struct battery_status old_battery;
92 static int abnormal_health_popup_timer;
93 static bool launching_health_popup;
95 static guint power_timer;
96 static device_notifier_state_e old_state = -1;
98 bool battery_initialized;
100 bool battery_do_not_disturb(void);
101 int battery_pm_change_internal(int pid, int s_bits);
102 static int delayed_init_done(void *data);
103 static void update_health(enum battery_noti_status status);
104 static int load_uevent(struct parse_result *result, void *user_data);
105 static int event_handler_state_changed(void *data);
106 static void power_supply_exit(void *data);
108 inline struct battery_status *get_var_battery_status(void)
113 static int lowbat_execute(void *data)
115 static const struct device_ops *lowbat_ops;
117 FIND_DEVICE_INT(lowbat_ops, "lowbat");
118 return device_execute(lowbat_ops, data);
121 static int power_supply_broadcast_str(char *sig, char *status)
123 static char old_sig[32];
124 static char old_status[32];
128 if (!sig || !status) {
129 _E("there is no signal name");
133 if (strncmp(old_sig, sig, strlen(sig)) == 0 && strncmp(old_status, status, strlen(status)) == 0)
136 snprintf(old_sig, sizeof(old_sig), "%s", sig);
137 snprintf(old_status, sizeof(old_status), "%s", status);
141 ret = gdbus_signal_emit(NULL,
142 DEVICED_PATH_BATTERY,
143 DEVICED_INTERFACE_BATTERY,
145 g_variant_new("(s)", str));
153 static void pm_check_and_change(int bInserted)
157 if (old == bInserted)
160 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
163 static void health_status_broadcast(void)
165 gdbus_signal_emit(NULL,
166 DEVICED_PATH_BATTERY,
167 DEVICED_INTERFACE_BATTERY,
172 static void full_noti_cb(GVariant *var, void *user_data, GError *err)
179 if (!g_variant_get_safe(var, "(i)", &id)) {
180 _E("Failed to notify full: no message(%s)", g_variant_get_type_string(var));
185 _D("Inserted battery full noti(%d).", noti_id);
188 g_variant_unref(var);
191 static void noti_off_cb(GVariant *var, void *user_data, GError *err)
195 if (!g_variant_get_safe(var, "(i)", &val)) {
196 _E("Failed to off notification: no message(%s)", g_variant_get_type_string(var));
200 _D("Noti off: %d", val);
203 g_variant_unref(var);
206 static int send_full_noti(enum charge_full_type state)
212 if (battery_plgn->check_power_supply_noti)
213 noti = battery_plgn->check_power_supply_noti();
220 for (retry = RETRY_MAX; retry > 0; retry--) {
221 ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
223 POPUP_INTERFACE_NOTI,
225 NULL, full_noti_cb, -1, NULL);
227 _D("Created battery full noti.");
231 _E("Failed to call dbus method: %d", ret);
233 case CHARGING_NOT_FULL:
236 for (retry = RETRY_MAX; retry > 0; retry--) {
237 ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
239 POPUP_INTERFACE_NOTI,
240 METHOD_FULL_NOTI_OFF,
241 g_variant_new("(i)", noti_id),
242 noti_off_cb, -1, NULL);
244 _D("Deleted battery full noti.");
249 _E("Failed to call dbus method: %d", ret);
255 static void charge_noti_on(GVariant *var, void *user_data, GError *err)
262 if (!g_variant_get_safe(var, "(i)", &id)) {
263 _E("Failed to notify charge: no message(%s)", g_variant_get_type_string(var));
267 _D("Inserted battery charge noti: %d", id);
270 g_variant_unref(var);
273 static int send_charge_noti(void)
278 for (retry = RETRY_MAX; retry > 0; retry--) {
279 ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
281 POPUP_INTERFACE_NOTI,
282 METHOD_CHARGE_NOTI_ON,
283 NULL, charge_noti_on, -1, NULL);
285 _I("Created battery charge noti.");
289 _E("Failed to call dbus method: %d", ret);
293 static void power_supply_noti(enum battery_noti_type type, enum battery_noti_status status)
295 static int charger = CHARGER_DISCHARGING;
296 static int full = CHARGING_NOT_FULL;
299 if (type == DEVICE_NOTI_BATT_CHARGE) {
300 if (status == DEVICE_NOTI_ON && charger == CHARGER_DISCHARGING) {
302 charger = CHARGER_CHARGING;
303 } else if (status == DEVICE_NOTI_OFF && charger == CHARGER_CHARGING)
304 charger = CHARGER_DISCHARGING;
305 } else if (type == DEVICE_NOTI_BATT_FULL) {
306 if (status == DEVICE_NOTI_ON && full == CHARGING_NOT_FULL) {
307 ret_val = send_full_noti(CHARGING_FULL);
309 full = CHARGING_FULL;
310 } else if (status == DEVICE_NOTI_OFF && full == CHARGING_FULL) {
311 ret_val = send_full_noti(CHARGING_NOT_FULL);
313 full = CHARGING_NOT_FULL;
318 int power_supply_broadcast(char *sig, int status)
321 static char sig_old[32];
325 _E("There is no signal name.");
328 if (strncmp(sig_old, sig, strlen(sig)) == 0 && old == status) {
329 _D("Skip broadcasting same signal(%s) and status(%d).", sig, status);
335 snprintf(sig_old, sizeof(sig_old), "%s", sig);
337 ret = gdbus_signal_emit(NULL,
338 DEVICED_PATH_BATTERY,
339 DEVICED_INTERFACE_BATTERY,
341 g_variant_new("(i)", status));
348 static void noti_batt_full(void)
350 static int bat_full_noti;
352 if (!battery.charge_full && bat_full_noti == 1) {
353 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
355 /* off the full charge state */
356 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
358 if (battery.charge_full && bat_full_noti == 0) {
359 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
361 /* turn on LCD, if battery is fully charged */
362 if (battery_plgn->check_power_supply_noti && battery_plgn->check_power_supply_noti()) {
363 battery_pm_change_internal(INTERNAL_LOCK_BATTERY_FULL, LCD_NORMAL);
367 /* on the full charge state */
368 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
372 static void check_power_supply(int state)
374 pm_check_and_change(state);
375 if (disp_plgn->update_pm_setting)
376 disp_plgn->update_pm_setting(SETTING_CHARGING, state);
379 static void charger_state_send_system_event(int state)
384 case CHARGING_STATUS_CHARGING:
385 str = EVT_VAL_BATTERY_CHARGER_CHARGING;
387 case CHARGING_STATUS_FULL:
388 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
389 CRITICAL_LOG("Battery charger: %s", str);
391 case CHARGING_STATUS_DISCHARGING:
392 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
393 CRITICAL_LOG("Battery charger: %s", str);
396 _E("Invalid parameter: %d", state);
400 event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, str);
403 static void update_present(enum battery_noti_status status)
406 CRITICAL_LOG("Charge(%d) present(%d, old: %d)", battery.charge_now, battery.present, old_battery.present);
408 old_battery.present = battery.present;
409 if (status == DEVICE_NOTI_ON) {
410 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_DIM);
411 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
412 if (disp_plgn->pm_lock_internal)
413 disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
415 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
416 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
417 if (disp_plgn->pm_unlock_internal)
418 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
420 if (battery_plgn->changed_battery_cf)
421 battery_plgn->changed_battery_cf(battery.present);
424 static void launch_health_popup(void)
426 if (launching_health_popup)
429 launching_health_popup = true;
431 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
432 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
433 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_DIM);
434 if (disp_plgn->pm_unlock_internal)
435 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
436 if (disp_plgn->pm_lock_internal)
437 disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
438 if (battery.health == HEALTH_LOW)
439 battery_charge_err_low_act(NULL);
440 else if (battery.health == HEALTH_HIGH)
441 battery_charge_err_high_act(NULL);
443 launching_health_popup = false;
446 /* Warning popup for every 1 minutes until
447 * battery health returns to normal. */
448 static gboolean health_popup_cb(void *data)
450 launch_health_popup();
451 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
452 return G_SOURCE_CONTINUE;
455 static void update_health(enum battery_noti_status status)
457 _I("Charge(%d) health(%d, old: %d)", battery.charge_now, battery.health, old_battery.health);
459 old_battery.health = battery.health;
460 if (status == DEVICE_NOTI_ON) {
461 CRITICAL_LOG("Popup: Battery health status is not good, %s.", battery.health_s);
462 launch_health_popup();
463 if (!abnormal_health_popup_timer)
464 abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
466 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
467 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
468 if (disp_plgn->pm_unlock_internal) {
469 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
470 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
472 health_status_broadcast();
473 if (abnormal_health_popup_timer) {
474 CRITICAL_LOG("Battery health returned to normal. Stop abnormal popup.");
475 g_source_remove(abnormal_health_popup_timer);
476 abnormal_health_popup_timer = 0;
478 if (battery_plgn->remove_health_popup)
479 battery_plgn->remove_health_popup();
483 void relaunch_health_popup(void)
485 if (launching_health_popup)
488 launching_health_popup = true;
490 if (abnormal_health_popup_timer)
491 g_source_remove(abnormal_health_popup_timer);
493 if (disp_plgn->pm_unlock_internal)
494 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
495 if (disp_plgn->pm_lock_internal)
496 disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
497 if (battery.health == HEALTH_LOW)
498 battery_charge_err_low_act(NULL);
499 else if (battery.health == HEALTH_HIGH)
500 battery_charge_err_high_act(NULL);
502 abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
504 launching_health_popup = false;
507 static void check_abnormal_status(void)
509 if (old_battery.health != HEALTH_LOW && old_battery.health != HEALTH_HIGH &&
510 (battery.health == HEALTH_LOW || battery.health == HEALTH_HIGH))
511 update_health(DEVICE_NOTI_ON);
512 else if ((old_battery.health == HEALTH_LOW || old_battery.health == HEALTH_HIGH) &&
513 battery.health != HEALTH_LOW && battery.health != HEALTH_HIGH)
514 update_health(DEVICE_NOTI_OFF);
516 if (old_battery.present != PRESENT_ABNORMAL && battery.present == PRESENT_ABNORMAL)
517 update_present(DEVICE_NOTI_ON);
518 else if (battery.present != PRESENT_ABNORMAL && old_battery.present == PRESENT_ABNORMAL)
519 update_present(DEVICE_NOTI_OFF);
521 if (old_battery.health != HEALTH_OVP && battery.health == HEALTH_OVP) {
522 if (battery_plgn->update_ovp)
523 battery_plgn->update_ovp(DEVICE_NOTI_ON);
524 } else if (battery.health != HEALTH_OVP && old_battery.health == HEALTH_OVP) {
525 if (battery_plgn->update_ovp)
526 battery_plgn->update_ovp(DEVICE_NOTI_OFF);
530 static void check_charging_status(const char *env_value)
534 if (env_value == NULL)
537 len = strlen(env_value);
538 if (strncmp(env_value, CHARGEFULL_NAME, len) == 0)
539 battery.charging_status = CHARGING_STATUS_FULL;
540 else if (strncmp(env_value, CHARGENOW_NAME, len) == 0)
541 battery.charging_status = CHARGING_STATUS_CHARGING;
542 else if (strncmp(env_value, DISCHARGE_NAME, len) == 0)
543 battery.charging_status = CHARGING_STATUS_DISCHARGING;
544 else if (strncmp(env_value, NOTCHARGE_NAME, len) == 0)
545 battery.charging_status = CHARGING_STATUS_NOT_CHARGING;
547 battery.charging_status = CHARGING_STATUS_UNKNOWN;
549 if (battery.charging_status == CHARGING_STATUS_FULL) {
550 battery.charge_full = CHARGING_FULL;
551 battery.charge_now = CHARGER_DISCHARGING;
552 } else if (battery.charging_status == CHARGING_STATUS_CHARGING) {
553 battery.charge_full = CHARGING_NOT_FULL;
554 battery.charge_now = CHARGER_CHARGING;
555 } else if (battery.charging_status == CHARGING_STATUS_DISCHARGING) {
556 battery.charge_full = CHARGING_NOT_FULL;
557 battery.charge_now = CHARGER_DISCHARGING;
558 } else if (battery.charging_status == CHARGING_STATUS_NOT_CHARGING) {
559 battery.charge_full = CHARGING_NOT_FULL;
560 battery.charge_now = CHARGER_ABNORMAL;
562 battery.charge_full = CHARGING_NOT_FULL;
563 battery.charge_now = CHARGER_DISCHARGING;
567 static void check_health_status(const char *env_value)
571 if (env_value == NULL) {
572 battery.health = HEALTH_GOOD;
576 snprintf(battery.health_s, sizeof(battery.health_s), "%s", env_value);
578 len = strlen(env_value);
579 if (strncmp(env_value, OVERHEAT_NAME, len) == 0)
580 battery.health = HEALTH_HIGH;
581 else if (strncmp(env_value, TEMPCOLD_NAME, len) == 0)
582 battery.health = HEALTH_LOW;
583 else if (strncmp(env_value, OVERVOLT_NAME, len) == 0)
584 battery.health = HEALTH_OVP;
585 else if (strncmp(env_value, GOOD_NAME, len) == 0)
586 battery.health = HEALTH_GOOD;
588 battery.health = HEALTH_NO_OPT;
591 static void check_power_source(const char *env_value)
593 int maxlen = sizeof(battery.power_source_s);
598 snprintf(battery.power_source_s, maxlen, "%s", env_value);
599 battery.power_source_s[maxlen - 1] = '\0';
601 if (strncmp(battery.power_source_s, "ac", sizeof("ac")) == 0) {
602 battery.online_type = CHARGER_TYPE_AC;
603 } else if (strncmp(battery.power_source_s, "usb", sizeof("usb")) == 0) {
604 battery.online_type = CHARGER_TYPE_USB;
605 } else if (strncmp(battery.power_source_s, "wireless", sizeof("wireless")) == 0) {
606 battery.online_type = CHARGER_TYPE_WIRELESS;
608 battery.online_type = CHARGER_TYPE_NONE;
612 static void check_misc_status(const char *env_value)
614 if (env_value == NULL) {
615 battery.misc = MISC_NONE;
618 battery.misc = atoi(env_value);
621 static void process_power_supply(void *data)
623 bool broadcasted = true;
627 if (disp_plgn->pm_lock_internal)
628 ret_lock = disp_plgn->pm_lock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
630 if (old_battery.charge_now != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
631 ret_val = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
633 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
635 if (power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now) < 0)
639 if (!strcmp(old_battery.status_s, CHARGEFULL_NAME) &&
640 !strcmp(battery.status_s, CHARGENOW_NAME)) {
641 battery_pm_change_internal(INTERNAL_LOCK_BATTERY, LCD_NORMAL);
644 if (old_battery.charge_full != battery.charge_full)
645 if (power_supply_broadcast(CHARGE_FULL_SIGNAL, battery.charge_full) < 0)
648 if (strncmp(old_battery.health_s, battery.health_s, strlen(battery.health_s))) {
649 snprintf(old_battery.health_s, sizeof(old_battery.health_s), "%s", battery.health_s);
650 if (power_supply_broadcast_str(CHARGE_HEALTH_SIGNAL, battery.health_s) < 0)
654 if (old_battery.capacity != battery.capacity) {
655 ret_val = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
657 _E("Failed to set vconf value for battery capacity: %d", vconf_get_ext_errno());
659 if (power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, battery.capacity) < 0)
663 (void)lowbat_execute(data);
665 if (old_battery.charger_connected != battery.charger_connected) {
666 check_power_supply(battery.charger_connected);
667 ret_val = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, battery.charger_connected);
669 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
670 if (battery.charger_connected == 0) {
671 CRITICAL_LOG("Battery charger disconnected");
672 event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, EVT_VAL_BATTERY_CHARGER_CONNECTED);
673 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED, NULL);
674 } else if (battery.charger_connected == 1) {
675 CRITICAL_LOG("Battery charger connected");
676 event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, EVT_VAL_BATTERY_CHARGER_DISCONNECTED);
677 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, NULL);
679 _E("Invalid charger connected");
683 if (old_battery.charging_status != battery.charging_status)
684 charger_state_send_system_event(battery.charging_status);
686 if (old_battery.online_type != battery.online_type) {
687 ret_val = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_TYPE, battery.online_type);
689 _E("Failed to set vconf value for charger type: %d", vconf_get_ext_errno());
691 if (power_supply_broadcast(CHARGER_TYPE_SIGNAL, battery.online_type) < 0)
695 if (old_battery.misc != battery.misc)
696 if (power_supply_broadcast(CHARGE_MISC_EVENT_SIGNAL, battery.misc) < 0)
699 if (old_battery.charge_full != battery.charge_full)
702 if (old_battery.charge_now != battery.charge_now ||
703 old_battery.charge_full != battery.charge_full ||
704 old_battery.capacity != battery.capacity ||
705 old_battery.health != battery.health ||
706 old_battery.misc != battery.misc ||
707 old_battery.online_type != battery.online_type)
708 _I("Signal(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s)",
710 CHARGER_STATUS_SIGNAL, battery.charger_connected,
711 CHARGER_TYPE_SIGNAL, battery.online_type,
712 CHARGE_NOW_SIGNAL, battery.charge_now,
713 CHARGE_FULL_SIGNAL, battery.charge_full,
714 CHARGE_CAPACITY_SIGNAL, battery.capacity,
715 CHARGE_LEVEL_SIGNAL, battery.capacity_level,
716 CHARGE_MISC_EVENT_SIGNAL, battery.misc,
717 CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s);
719 old_battery.capacity = battery.capacity;
720 old_battery.capacity_level = battery.capacity_level;
721 old_battery.charger_connected = battery.charger_connected;
722 old_battery.online_type = battery.online_type;
723 old_battery.charging_status = battery.charging_status;
724 old_battery.charge_full = battery.charge_full;
726 old_battery.misc = battery.misc;
727 snprintf(old_battery.status_s, sizeof(old_battery.status_s), "%s", battery.status_s);
729 check_abnormal_status();
731 device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
732 if (old_battery.charge_now != battery.charge_now) {
733 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, &battery.charge_now);
734 old_battery.charge_now = battery.charge_now;
737 if (disp_plgn->pm_unlock_internal) {
739 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
744 static int battery_state(struct battery_info *info)
746 static struct battery_status prev_status;
749 memcpy(&prev_status, &battery, sizeof(battery));
753 if (battery.capacity != 0 && prev_status.capacity == battery.capacity &&
754 prev_status.charging_status == battery.charging_status &&
755 prev_status.online_type == battery.online_type &&
756 prev_status.charge_full == battery.charge_full &&
757 prev_status.charge_now == battery.charge_now &&
758 prev_status.health == battery.health &&
759 prev_status.present == battery.present &&
760 prev_status.current_now == battery.current_now &&
761 prev_status.current_average == battery.current_average &&
762 prev_status.charger_connected == battery.charger_connected)
765 prev_status.capacity = battery.capacity;
766 prev_status.charging_status = battery.charging_status;
767 prev_status.charge_full = battery.charge_full;
768 prev_status.charge_now = battery.charge_now;
769 prev_status.health = battery.health;
770 prev_status.present = battery.present;
771 prev_status.charger_connected = battery.charger_connected;
773 _I("%s(%s) %s(%d) Capa(%d) Hth(%s,%d) Pres(%d) Curr(%d,%d)",
775 battery.charge_now == CHARGER_CHARGING ? "Charging"
776 : (battery.charge_now == CHARGER_DISCHARGING ? "Discharging" : "Abnormal"),
784 info->current_average);
788 static void battery_disable_module(int value)
791 static const struct invalidate_list {
792 const char *vconfkey;
795 { VCONFKEY_SYSMAN_BATTERY_CAPACITY, &old_battery.capacity },
796 { VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &old_battery.capacity_level },
797 { VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, &old_battery.charge_now },
798 { VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, NULL },
801 _D("Invalidate battery value to %d", value);
803 for (int i = 0; i < ARRAY_SIZE(list); ++i) {
804 if (list[i].vconfkey) {
805 retval = vconf_set_int(list[i].vconfkey, value);
807 _D("Set vconf %s to %d", list[i].vconfkey, value);
809 _E("Failed to set %s to %d, %d", list[i].vconfkey, value, retval);
812 *(list[i].member) = value;
815 power_supply_exit(NULL);
818 static void battery_changed(struct battery_info *info, void *data)
823 (void)battery_state(NULL);
828 snprintf(battery.status_s, sizeof(battery.status_s),
830 check_charging_status(info->status);
832 battery.status_s[0] = '\0';
835 snprintf(battery.health_s, sizeof(battery.health_s),
837 check_health_status(info->health);
839 battery.health_s[0] = '\0';
841 if (info->power_source)
842 check_power_source(info->power_source);
844 battery.power_source_s[0] = '\0';
846 battery.charger_connected = info->online;
847 battery.present = info->present;
848 battery.capacity = info->capacity;
849 battery.current_now = info->current_now;
850 battery.current_average = info->current_average;
851 battery.temperature = info->temperature;
852 battery.voltage_now = info->voltage_now;
853 battery.voltage_average = info->voltage_average;
855 battery_initialized = true;
857 ret_val = battery_state(info);
861 ret_val = delayed_init_done(NULL);
863 /* If the same notification is requested repeatedly, it is ignored by power_supply_noti().
864 * A notification will be triggered only when charging_status changes between
865 * CHARGING_STATUS_CHARGING/FULL <-> CHARGING_STATUS_DISCHARGING. */
866 if (battery.charging_status == CHARGING_STATUS_CHARGING || battery.charging_status == CHARGING_STATUS_FULL)
867 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
868 else if (battery.charging_status == CHARGING_STATUS_DISCHARGING)
869 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
873 battery.health = HEALTH_GOOD;
874 battery.present = PRESENT_NORMAL;
877 if (battery.present) {
878 process_power_supply(&battery.capacity);
880 CRITICAL_LOG_E("Battery disconnected. Disable the battery module.");
881 battery_disable_module(-ENODEV);
885 static gboolean power_supply_update_during_booting(void *data)
889 retval = hal_device_battery_get_current_state(battery_changed, NULL);
890 if (retval == -ENODEV) {
891 CRITICAL_LOG_E("There is no battery detected. Disable the battery module.");
892 battery_disable_module(retval);
893 return G_SOURCE_REMOVE;
896 return G_SOURCE_CONTINUE;
899 static void power_supply_timer_start(void)
901 _D("Battery init timer during booting.");
902 power_timer = g_timeout_add(BATTERY_CHECK_TIMER_INTERVAL,
903 power_supply_update_during_booting, NULL);
904 if (power_timer == 0)
905 _E("Failed to add battery init timer during booting.");
907 _I("Started battery init timer during booting.");
910 static GVariant *dbus_get_charger_status(GDBusConnection *conn,
911 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
912 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
916 ret_val = vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &status);
918 _E("Failed to get vconf value for charger status: %d", vconf_get_ext_errno());
921 return g_variant_new("(i)", status);
924 static GVariant *dbus_get_charger_type(GDBusConnection *conn,
925 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
926 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
928 int type = battery.online_type;
930 return g_variant_new("(i)", type);
933 static GVariant *dbus_get_charge_now(GDBusConnection *conn,
934 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
935 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
939 ret = battery.charge_now;
941 return g_variant_new("(i)", ret);
944 static GVariant *dbus_get_charge_level(GDBusConnection *conn,
945 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
946 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
950 ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &val);
952 _E("Failed to get vconf value for battery status low: %d", vconf_get_ext_errno());
956 return g_variant_new("(i)", val);
959 static GVariant *dbus_get_percent(GDBusConnection *conn,
960 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
961 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
965 ret = battery.capacity;
967 return g_variant_new("(i)", ret);
970 static GVariant *dbus_get_percent_raw(GDBusConnection *conn,
971 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
972 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
978 return g_variant_new("(i)", ret);
981 static GVariant *dbus_is_full(GDBusConnection *conn,
982 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
983 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
987 ret = battery.charge_full;
989 return g_variant_new("(i)", ret);
992 static GVariant *dbus_get_health(GDBusConnection *conn,
993 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
994 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
998 str = battery.health_s;
1000 return g_variant_new("(s)", str);
1003 static GVariant *dbus_get_misc(GDBusConnection *conn,
1004 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1005 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1011 return g_variant_new("(i)", ret);
1015 static GVariant *dbus_get_power_supply_handler(GDBusConnection *conn,
1016 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1017 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1019 /* This method is for getting battery state after battery modification
1020 * by battery test driver. At this point, restore uevent buffering, which
1021 * had been disabled by test driver. */
1022 lowbat_enable_uevent_buffering();
1024 return g_variant_new("(iiiiiiisiiiii)", 0,
1026 battery.charging_status,
1028 battery.charger_connected,
1031 battery.power_source_s,
1032 battery.voltage_now,
1033 battery.voltage_average,
1034 battery.current_now,
1035 battery.current_average,
1036 battery.temperature);
1039 static GVariant *dbus_power_supply_handler(GDBusConnection *conn,
1040 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1041 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1044 int ret = 0, argc = 0;
1045 int charger_connected;
1048 struct battery_info info = {0, };
1050 g_variant_get(param, "(sisssisssssssss)", &type_str,
1067 _E("Message is invalid.");
1072 pid = gdbus_connection_get_sender_pid(conn, sender);
1073 if (pid == -1 || kill(pid, 0) == -1) {
1074 _E("Process(%d) does not exist, dbus ignored.", pid);
1079 /* The battery change triggered by this dbus must be processed
1080 * within a single subroutine as the objective of this method call is mostly
1081 * for the testing. Therefore, do not buffering the mocked uevent so that make
1082 * the test driver can get the changed battery result without waiting */
1083 lowbat_disable_uevent_buffering();
1085 info.capacity = atoi(argv[0]);
1086 info.status = strdup(argv[1]);
1087 info.health = strdup(argv[2]);
1088 info.online = charger_connected;
1089 info.present = atoi(argv[4]);
1090 check_misc_status(argv[5]);
1091 info.power_source = strdup(argv[7]);
1092 info.voltage_now = atoi(argv[8]);
1093 info.voltage_average = atoi(argv[9]);
1094 info.current_now = atoi(argv[10]);
1095 info.current_average = atoi(argv[11]);
1096 info.temperature = atoi(argv[12]);
1097 _D("C(%d) S(%s) H(%s) O(%d) P(%d) SRC(%s) Vol(%d %d) Cur(%d %d) T(%d)",
1098 info.capacity, info.status, info.health, info.online, info.present, info.power_source, info.voltage_now, info.voltage_average, info.current_now, info.current_average, info.temperature);
1100 battery_changed(&info, NULL);
1119 free(info.power_source);
1121 return g_variant_new("(i)", ret);
1124 static void battery_get_info(struct battery_info *info, void *data)
1126 struct battery_info *bat = data;
1131 bat->status = strdup(info->status);
1132 bat->health = strdup(info->health);
1133 bat->power_source = strdup(info->power_source);
1134 bat->online = info->online;
1135 bat->present = info->present;
1136 bat->capacity = info->capacity;
1137 bat->current_now = info->current_now;
1138 bat->current_average = info->current_average;
1139 bat->temperature = info->temperature;
1140 bat->voltage_now = info->voltage_now;
1141 bat->voltage_average = info->voltage_average;
1144 static GVariant *dbus_get_battery_info(GDBusConnection *conn,
1145 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1146 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1150 struct battery_info info = {0, };
1152 if (old_state == DEVICE_NOTIFIER_STATE_STOP)
1155 if (battery_initialized)
1158 ret = hal_device_battery_get_current_state(battery_get_info, &info);
1159 if (ret != -ENODEV) {
1161 _E("Failed to get battery info: %d", ret);
1163 battery_changed(&info, NULL);
1166 free(info.power_source);
1168 if (vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &val) == 0 &&
1169 val != VCONFKEY_SYSMAN_USB_DISCONNECTED)
1170 str = POWER_SOURCE_USB;
1171 else if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &val) == 0 &&
1172 val == VCONFKEY_SYSMAN_CHARGER_CONNECTED)
1173 str = POWER_SOURCE_AC;
1175 str = POWER_SOURCE_NONE;
1176 snprintf(battery.power_source_s, sizeof(battery.power_source_s), "%s", str);
1178 battery.current_now = -1; /* Not supported */
1179 battery.current_average = -1; /* Not supported */
1184 return g_variant_new("(isssiiiiiiii)", ret,
1187 battery.power_source_s,
1188 battery.charger_connected,
1191 battery.current_now,
1192 battery.current_average,
1193 battery.voltage_now,
1194 battery.voltage_average,
1195 battery.temperature);
1198 static void update_battery_props(void)
1200 if (config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery) < 0)
1201 _E("Failed to check power supply uevent.");
1204 static GVariant *dbus_get_battery_props(GDBusConnection *conn,
1205 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1206 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1208 update_battery_props();
1210 return g_variant_new("(iiiiii)",
1212 battery.temperature,
1213 battery.voltage_now,
1214 battery.voltage_average,
1215 battery.current_now,
1216 battery.current_average);
1219 static const dbus_method_s dbus_methods[] = {
1220 { CHARGER_STATUS_SIGNAL, NULL, "i", dbus_get_charger_status },
1221 { CHARGE_NOW_SIGNAL, NULL, "i", dbus_get_charge_now },
1222 { CHARGE_LEVEL_SIGNAL, NULL, "i", dbus_get_charge_level },
1223 { CHARGE_CAPACITY_SIGNAL, NULL, "i", dbus_get_percent },
1224 { CHARGE_CAPACITY_LAW_SIGNAL, NULL, "i", dbus_get_percent_raw },
1225 { CHARGE_FULL_SIGNAL, NULL, "i", dbus_is_full },
1226 { CHARGE_HEALTH_SIGNAL, NULL, "s", dbus_get_health },
1227 { POWER_SUBSYSTEM, "sisssisssssssss", "i", dbus_power_supply_handler },
1228 { GET_POWER_SUBSYSTEM, NULL, "iiiiiiisiiiii", dbus_get_power_supply_handler },
1229 { "GetBatteryInfo", NULL, "isssiiiiiiii", dbus_get_battery_info },
1230 { CHARGER_TYPE_SIGNAL, NULL, "i", dbus_get_charger_type },
1231 { CHARGE_BATTERY_PROPERTIES, NULL, "iiiiii", dbus_get_battery_props },
1232 { CHARGE_MISC_EVENT_SIGNAL, NULL, "i", dbus_get_misc },
1235 static const dbus_interface_u dbus_interface = {
1237 .name = DEVICED_INTERFACE_BATTERY,
1238 .methods = dbus_methods,
1239 .nr_methods = ARRAY_SIZE(dbus_methods),
1242 static int delayed_init_done(void *data)
1246 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_START;
1250 done = *(int *)data;
1255 g_source_remove(power_timer);
1259 /* check battery has been initialized */
1260 retval = hal_device_battery_get_current_state(battery_changed, NULL);
1261 if (retval == -ENODEV) {
1262 CRITICAL_LOG_E("Failed to initialize battery state, %d. Disable the battery module.", retval);
1263 battery_disable_module(retval);
1267 event_handler_state_changed((void *)&state);
1269 _I("booting done %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s)",
1270 CHARGER_STATUS_SIGNAL, battery.charger_connected,
1271 CHARGE_NOW_SIGNAL, battery.charge_now,
1272 CHARGE_FULL_SIGNAL, battery.charge_full,
1273 CHARGE_CAPACITY_SIGNAL, battery.capacity,
1274 CHARGE_LEVEL_SIGNAL, battery.capacity_level,
1275 CHARGE_MISC_EVENT_SIGNAL, battery.misc,
1276 CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s);
1278 unregister_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1283 bool battery_do_not_disturb(void)
1285 int block = 0, theater = 0, night = 0;
1288 if (battery_plgn->display_changed) {
1289 if (battery_plgn->display_changed(NULL) == S_LCDOFF) {
1290 r = vconf_get_bool(VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL, &block);
1292 _E("Failed to set vconf value for blockmode wearable: %d", vconf_get_ext_errno());
1293 r = vconf_get_bool(VCONFKEY_SETAPPL_THEATER_MODE_ENABLE, &theater);
1295 _E("Failed to set vconf value for theator mode enable: %d", vconf_get_ext_errno());
1296 r = vconf_get_bool(VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE, &night);
1298 _E("Failed to set vconf value for goodnight mode enable: %d", vconf_get_ext_errno());
1302 if (block != 0 || theater != 0 || night != 0) {
1303 _I("Skip lcd and popup(block %d theater %d night %d).", block, theater, night);
1310 int battery_pm_change_internal(int pid, int s_bits)
1312 if (battery_do_not_disturb())
1315 if (disp_plgn->pm_change_internal)
1316 disp_plgn->pm_change_internal(pid, s_bits);
1321 static int load_uevent(struct parse_result *result, void *user_data)
1323 struct battery_status *info = user_data;
1328 if (MATCH(result->name, CHARGE_STATUS)) {
1329 if (strstr(result->value, "Charging")) {
1330 info->charge_now = CHARGER_CHARGING;
1331 info->charge_full = CHARGING_NOT_FULL;
1332 } else if (strstr(result->value, "Discharging")) {
1333 info->charge_now = CHARGER_DISCHARGING;
1334 info->charge_full = CHARGING_NOT_FULL;
1335 } else if (strstr(result->value, "Full")) {
1336 info->charge_now = CHARGER_DISCHARGING;
1337 info->charge_full = CHARGING_FULL;
1338 } else if (strstr(result->value, "Not charging")) {
1339 info->charge_now = CHARGER_ABNORMAL;
1340 info->charge_full = CHARGING_NOT_FULL;
1342 snprintf(info->status_s, sizeof(info->status_s), "%s", result->value);
1343 } else if (MATCH(result->name, CAPACITY)) {
1344 info->capacity = atoi(result->value);
1345 } else if (MATCH(result->name, TEMPERATURE)) {
1346 info->temperature = atoi(result->value) / 10;
1347 } else if (MATCH(result->name, VOLTAGE_NOW)) {
1348 info->voltage_now = atoi(result->value);
1349 } else if (MATCH(result->name, VOLTAGE_AVG)) {
1350 info->voltage_average = atoi(result->value);
1351 } else if (MATCH(result->name, CURRENT_NOW)) {
1352 info->current_now = atoi(result->value);
1353 } else if (MATCH(result->name, CURRENT_AVG)) {
1354 info->current_average = atoi(result->value);
1355 } else if (MATCH(result->name, CHARGE_HEALTH)) {
1356 snprintf(info->health_s, sizeof(info->health_s), "%s", result->value);
1362 static int power_supply_probe(void *data)
1367 ret_val = hal_device_battery_get_backend();
1369 _E("There is no HAL for battery.");
1370 if (access(POWER_PATH, R_OK) == 0)
1371 return 0; /* Just power_supply uevent is used */
1376 _I("Battery device structure load success.");
1381 * Set battery vconf as -ENOTSUP
1382 * These vconf key used by runtime-info and capi-system-device.
1384 r = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, -ENOTSUP);
1386 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
1387 r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, -ENOTSUP);
1389 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
1390 r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, -ENOTSUP);
1392 _E("Failed to set vconf value for battery level status: %d", vconf_get_ext_errno());
1393 _I("There is no battery device: %d", ret_val);
1397 static void add_power_supply_handler(void)
1399 hal_device_battery_register_changed_event(battery_changed, NULL);
1400 hal_device_battery_get_current_state(battery_changed, NULL);
1403 static void remove_power_supply_handler(void)
1405 hal_device_battery_unregister_changed_event(battery_changed);
1408 static int event_handler_state_changed(void *data)
1410 device_notifier_state_e state = *(device_notifier_state_e *)data;
1412 if (old_state == state)
1417 if (state == DEVICE_NOTIFIER_STATE_START)
1418 add_power_supply_handler();
1419 else if (state == DEVICE_NOTIFIER_STATE_STOP)
1420 remove_power_supply_handler();
1425 static void power_supply_init(void *data)
1429 memset(&battery, 0, sizeof(struct battery_status));
1430 memset(&old_battery, 0, sizeof(struct battery_status));
1431 battery.misc = MISC_NONE;
1432 battery.charger_connected = -1;
1434 /* It will be true on initializing battery structure */
1435 battery_initialized = false;
1437 /* process check battery timer until booting done */
1438 power_supply_timer_start();
1440 register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1441 register_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1443 ret_dbus = gdbus_add_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
1445 _E("Failed to init dbus method: %d", ret_dbus);
1447 battery_ops_init((void *)battery_plgn);
1450 static void power_supply_exit(void *data)
1452 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_STOP;
1454 unregister_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1455 unregister_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1457 event_handler_state_changed((void *)&state);
1459 battery_ops_exit(NULL);
1462 static const struct device_ops power_supply_ops = {
1463 DECLARE_NAME_LEN("power_supply"),
1464 .probe = power_supply_probe,
1465 .init = power_supply_init,
1466 .exit = power_supply_exit,
1469 DEVICE_OPS_REGISTER(&power_supply_ops)
1471 static void __CONSTRUCTOR__ initialize(void)
1473 disp_plgn = get_var_display_plugin();
1475 _E("Failed to get display plugin variable.");
1477 battery_plgn = get_var_battery_plugin();
1479 _E("Failed to get battery plugin variable.");