d5f0b792d20d263370e4075468d4f0e4209920db
[platform/core/system/deviced.git] / src / battery / power-supply.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 <stdio.h>
21 #include <stdbool.h>
22 #include <vconf.h>
23 #include <bundle.h>
24 #include <eventsystem.h>
25 #include <hal/device/hal-battery.h>
26 #include <sys/stat.h>
27 #include <libsyscommon/ini-parser.h>
28 #include <system/syscommon-plugin-deviced-common-interface.h>
29
30 #include "shared/devices.h"
31 #include "shared/device-notifier.h"
32 #include "core/udev.h"
33 #include "core/log.h"
34 #include "poll.h"
35 #include "setting.h"
36 #include "shared/eventsystem.h"
37 #include "shared/plugin.h"
38 #include "shared/apps.h"
39 #include "shared/event.h"
40 #include "core.h"
41 #include "display-lock.h"
42 #include "display-ops.h"
43 #include "display-state-transition.h"
44 #include "power-supply.h"
45 #include "battery.h"
46 #include "battery-ops.h"
47 #include "extcon/extcon.h"
48 #include "lowbat-handler.h"
49 #include "battery-parser.h"
50
51 #ifndef VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL
52 #define VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL "db/setting/blockmode_wearable"
53 #endif
54
55 #ifndef VCONFKEY_SETAPPL_THEATER_MODE_ENABLE
56 #define VCONFKEY_SETAPPL_THEATER_MODE_ENABLE "db/setting/theater_mode_enable"
57 #endif
58
59 #ifndef VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE
60 #define VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE "db/setting/goodnight_mode_enable"
61 #endif
62
63 #define BATTERY_NAME        "battery"
64 #define CHARGEFULL_NAME     "Full"
65 #define CHARGENOW_NAME      "Charging"
66 #define DISCHARGE_NAME      "Discharging"
67 #define NOTCHARGE_NAME      "Not charging"
68 #define OVERHEAT_NAME       "Overheat"
69 #define TEMPCOLD_NAME       "Cold"
70 #define OVERVOLT_NAME       "Over voltage"
71 #define GOOD_NAME           "Good"
72
73 #define CHARGER_WIRELESS_TYPE_BT    10
74 #define CHARGER_WIRELESS_TYPE_3G    22
75 #define CHARGER_INCOMPATIBLE_TYPE   11
76 #define CHARGER_D2D_TYPE            110
77 #define WIRELESS_CHARGER_CONNECTED  2
78
79 #define SIGNAL_TEMP_GOOD          "TempGood"
80
81 #define METHOD_FULL_NOTI_ON   "BatteryFullNotiOn"
82 #define METHOD_FULL_NOTI_OFF  "BatteryFullNotiOff"
83 #define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
84
85 #define CHARGER_CHARGE_ON_NODE "/sys/class/power_supply/battery/chg_on"
86
87 #define RETRY_MAX 5
88 #define BATTERY_CHECK_TIMER_INTERVAL 500  /* 0.5 second */
89 #define LCD_DIM_TIME_IN_BATTERY_HEALTH  10000   /* ms */
90
91 static struct battery_plugin *battery_plgn;
92
93 static struct battery_status battery;
94 struct battery_status old_battery;
95 static int noti_id;
96 static int abnormal_health_popup_timer;
97 static bool launching_health_popup;
98
99 static guint power_timer;
100 static device_notifier_state_e old_state = -1;
101
102 static enum deviced_display_state g_display_state = DEVICED_DISPLAY_STATE_ON;
103
104 static struct battery_config_info g_battery_info;
105
106 bool battery_initialized;
107
108 bool battery_do_not_disturb(void);
109 int battery_pm_change_internal(int pid, int s_bits);
110 static int delayed_init_done(void *data);
111 static void update_health(enum battery_noti_status status);
112 static int load_uevent(struct parse_result *result, void *user_data);
113 static int event_handler_state_changed(void *data);
114 static void power_supply_exit(void *data);
115
116 inline struct battery_status *get_var_battery_status(void)
117 {
118         return &battery;
119 }
120
121 static int lowbat_execute(void *data)
122 {
123         static const struct device_ops *lowbat_ops;
124
125         FIND_DEVICE_INT(lowbat_ops, "lowbat");
126         return device_execute(lowbat_ops, data);
127 }
128
129 static int power_supply_broadcast_str(char *sig, char *status)
130 {
131         static char old_sig[32];
132         static char old_status[32];
133         char *str;
134         int ret;
135
136         if (!sig || !status) {
137                 _E("there is no signal name");
138                 return -EINVAL;
139         }
140
141         if (strncmp(old_sig, sig, strlen(sig)) == 0 && strncmp(old_status, status, strlen(status)) == 0)
142                 return 0;
143
144         snprintf(old_sig, sizeof(old_sig), "%s", sig);
145         snprintf(old_status, sizeof(old_status), "%s", status);
146
147         str = status;
148
149         ret = gdbus_signal_emit(NULL,
150                                                 DEVICED_PATH_BATTERY,
151                                                 DEVICED_INTERFACE_BATTERY,
152                                                 sig,
153                                                 g_variant_new("(s)", str));
154
155         if (ret == 0)
156                 return 1;
157         else
158                 return ret;
159 }
160
161 static void pm_check_and_change(int bInserted)
162 {
163         static int old = -1;
164
165         if (old == bInserted)
166                 return;
167         old = bInserted;
168         battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_NORMAL);
169 }
170
171 static void health_status_broadcast(void)
172 {
173         gdbus_signal_emit(NULL,
174                 DEVICED_PATH_BATTERY,
175                 DEVICED_INTERFACE_BATTERY,
176                 SIGNAL_TEMP_GOOD,
177                 NULL);
178 }
179
180 static void full_noti_cb(GVariant *var, void *user_data, GError *err)
181 {
182         int id = 0;
183
184         if (!var)
185                 return;
186
187         if (!g_variant_get_safe(var, "(i)", &id)) {
188                 _E("Failed to notify full: no message(%s)", g_variant_get_type_string(var));
189                 goto out;
190         }
191
192         noti_id = id;
193         _D("Inserted battery full noti(%d).", noti_id);
194
195 out:
196         g_variant_unref(var);
197 }
198
199 static void noti_off_cb(GVariant *var, void *user_data, GError *err)
200 {
201         int val = 0;
202
203         if (!g_variant_get_safe(var, "(i)", &val)) {
204                 _E("Failed to off notification: no message(%s)", g_variant_get_type_string(var));
205                 goto out;
206         }
207
208         _D("Noti off: %d", val);
209
210 out:
211         g_variant_unref(var);
212 }
213
214 static int send_full_noti(enum charge_full_type state)
215 {
216         int ret = 0;
217         int noti = 0;
218         int retry;
219
220         if (battery_plgn->check_power_supply_noti)
221                 noti = battery_plgn->check_power_supply_noti();
222
223         if (!noti)
224                 return ret;
225
226         switch (state) {
227         case CHARGING_FULL:
228                 for (retry = RETRY_MAX; retry > 0; retry--) {
229                         ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
230                                         POPUP_PATH_NOTI,
231                                         POPUP_INTERFACE_NOTI,
232                                         METHOD_FULL_NOTI_ON,
233                                         NULL, full_noti_cb, -1, NULL);
234                         if (ret == 0) {
235                                 _D("Created battery full noti.");
236                                 return ret;
237                         }
238                 }
239                 _E("Failed to call dbus method: %d", ret);
240                 break;
241         case CHARGING_NOT_FULL:
242                 if (noti_id <= 0)
243                         return -EPERM;
244                 for (retry = RETRY_MAX; retry > 0; retry--) {
245                         ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
246                                         POPUP_PATH_NOTI,
247                                         POPUP_INTERFACE_NOTI,
248                                         METHOD_FULL_NOTI_OFF,
249                                         g_variant_new("(i)", noti_id),
250                                         noti_off_cb, -1, NULL);
251                         if (ret == 0) {
252                                 _D("Deleted battery full noti.");
253                                 noti_id = 0;
254                                 return ret;
255                         }
256                 }
257                 _E("Failed to call dbus method: %d", ret);
258                 break;
259         }
260         return ret;
261 }
262
263 static void charge_noti_on(GVariant *var, void *user_data, GError *err)
264 {
265         int id = 0;
266
267         if (!var)
268                 return;
269
270         if (!g_variant_get_safe(var, "(i)", &id)) {
271                 _E("Failed to notify charge: no message(%s)", g_variant_get_type_string(var));
272                 goto out;
273         }
274
275         _D("Inserted battery charge noti: %d", id);
276
277 out:
278         g_variant_unref(var);
279 }
280
281 static int send_charge_noti(void)
282 {
283         int ret = 0;
284         int retry;
285
286         for (retry = RETRY_MAX; retry > 0; retry--) {
287                 ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
288                                 POPUP_PATH_NOTI,
289                                 POPUP_INTERFACE_NOTI,
290                                 METHOD_CHARGE_NOTI_ON,
291                                 NULL, charge_noti_on, -1, NULL);
292                 if (ret == 0) {
293                         _I("Created battery charge noti.");
294                         return ret;
295                 }
296         }
297         _E("Failed to call dbus method: %d", ret);
298         return ret;
299 }
300
301 static void power_supply_noti(enum battery_noti_type type, enum battery_noti_status status)
302 {
303         static int charger = CHARGER_DISCHARGING;
304         static int full = CHARGING_NOT_FULL;
305         int ret_val;
306
307         if (type == DEVICE_NOTI_BATT_CHARGE) {
308                 if (status == DEVICE_NOTI_ON && charger == CHARGER_DISCHARGING) {
309                         send_charge_noti();
310                         charger = CHARGER_CHARGING;
311                 } else if (status == DEVICE_NOTI_OFF && charger == CHARGER_CHARGING)
312                         charger = CHARGER_DISCHARGING;
313         } else if (type == DEVICE_NOTI_BATT_FULL) {
314                 if (status == DEVICE_NOTI_ON && full == CHARGING_NOT_FULL) {
315                         ret_val = send_full_noti(CHARGING_FULL);
316                         if (ret_val == 0)
317                                 full = CHARGING_FULL;
318                 } else if (status == DEVICE_NOTI_OFF && full == CHARGING_FULL) {
319                         ret_val = send_full_noti(CHARGING_NOT_FULL);
320                         if (ret_val == 0)
321                                 full = CHARGING_NOT_FULL;
322                 }
323         }
324 }
325
326 int power_supply_broadcast(char *sig, int status)
327 {
328         static int old;
329         static char sig_old[32];
330         int ret;
331
332         if (!sig) {
333                 _E("There is no signal name.");
334                 return -EINVAL;
335         }
336         if (strncmp(sig_old, sig, strlen(sig)) == 0 && old == status) {
337                 _D("Skip broadcasting same signal(%s) and status(%d).", sig, status);
338                 return 0;
339         }
340
341         old = status;
342
343         snprintf(sig_old, sizeof(sig_old), "%s", sig);
344
345         ret = gdbus_signal_emit(NULL,
346                                                 DEVICED_PATH_BATTERY,
347                                                 DEVICED_INTERFACE_BATTERY,
348                                                 sig,
349                                                 g_variant_new("(i)", status));
350         if (ret == 0)
351                 return 1;
352         else
353                 return ret;
354 }
355
356 static void noti_batt_full(void)
357 {
358         static int bat_full_noti;
359
360         if (!battery.charge_full && bat_full_noti == 1) {
361                 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
362                 bat_full_noti = 0;
363                 /* off the full charge state */
364                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
365         }
366         if (battery.charge_full && bat_full_noti == 0) {
367                 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
368                 bat_full_noti = 1;
369                 /* turn on LCD, if battery is fully charged */
370                 if (battery_plgn->check_power_supply_noti && battery_plgn->check_power_supply_noti()) {
371                         battery_pm_change_internal(DEVICED_EVENT_BATTERY_CAPACITY_FULL, LCD_NORMAL);
372                 } else
373                         _I("Block LCD.");
374
375                 /* on the full charge state */
376                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
377         }
378 }
379
380 static void check_power_supply(int state)
381 {
382         pm_check_and_change(state);
383         display_setting_update_pm_setting(SETTING_CHARGING, state);
384 }
385
386 static void charger_state_send_system_event(int state)
387 {
388         const char *str;
389
390         switch (state) {
391         case CHARGING_STATUS_CHARGING:
392                 str = EVT_VAL_BATTERY_CHARGER_CHARGING;
393                 break;
394         case CHARGING_STATUS_FULL:
395                 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
396                 CRITICAL_LOG("Battery charger: %s", str);
397                 break;
398         case CHARGING_STATUS_DISCHARGING:
399                 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
400                 CRITICAL_LOG("Battery charger: %s", str);
401                 break;
402         default:
403                 _E("Invalid parameter: %d", state);
404                 return;
405         }
406
407         event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, str);
408 }
409
410 static void update_present(enum battery_noti_status status)
411 {
412
413         CRITICAL_LOG("Charge(%d) present(%d, old: %d)", battery.charge_now, battery.present, old_battery.present);
414
415         old_battery.present = battery.present;
416         if (status == DEVICE_NOTI_ON) {
417                 battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_DIM);
418                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
419                 display_lock_request_lock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
420         } else {
421                 battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_NORMAL);
422                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
423                 display_lock_request_unlock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
424         }
425         if (battery_plgn->changed_battery_cf)
426                 battery_plgn->changed_battery_cf(battery.present);
427 }
428
429 static void launch_health_popup(void)
430 {
431         if (launching_health_popup)
432                 return;
433
434         launching_health_popup = true;
435
436         syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
437         battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_NORMAL);
438         battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_DIM);
439         display_lock_request_unlock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
440         display_lock_request_lock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
441         if (battery.health == HEALTH_LOW)
442                 battery_charge_err_low_act(NULL);
443         else if (battery.health == HEALTH_HIGH)
444                 battery_charge_err_high_act(NULL);
445
446         launching_health_popup = false;
447 }
448
449 /* Warning popup for every 1 minutes until
450  * battery health returns to normal. */
451 static gboolean health_popup_cb(void *data)
452 {
453         launch_health_popup();
454         battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_NORMAL);
455         return G_SOURCE_CONTINUE;
456 }
457
458 static void update_health(enum battery_noti_status status)
459 {
460         _I("Charge(%d) health(%d, old: %d)", battery.charge_now, battery.health, old_battery.health);
461
462         old_battery.health = battery.health;
463         if (status == DEVICE_NOTI_ON) {
464                 CRITICAL_LOG("Popup: Battery health status is not good, %s.", battery.health_s);
465                 launch_health_popup();
466                 if (!abnormal_health_popup_timer)
467                         abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
468         } else {
469                 battery_pm_change_internal(DEVICED_EVENT_MISC_POPUP, LCD_NORMAL);
470                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
471                 display_lock_request_unlock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
472                 display_lock_request_unlock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
473                 health_status_broadcast();
474                 if (abnormal_health_popup_timer) {
475                         CRITICAL_LOG("Battery health returned to normal. Stop abnormal popup.");
476                         g_source_remove(abnormal_health_popup_timer);
477                         abnormal_health_popup_timer = 0;
478                 }
479                 if (battery_plgn->remove_health_popup)
480                         battery_plgn->remove_health_popup();
481         }
482 }
483
484 void relaunch_health_popup(void)
485 {
486         if (launching_health_popup)
487                 return;
488
489         launching_health_popup = true;
490
491         if (abnormal_health_popup_timer)
492                 g_source_remove(abnormal_health_popup_timer);
493
494         display_lock_request_unlock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
495         display_lock_request_lock_with_option(DEVICED_EVENT_MISC_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
496         if (battery.health == HEALTH_LOW)
497                 battery_charge_err_low_act(NULL);
498         else if (battery.health == HEALTH_HIGH)
499                 battery_charge_err_high_act(NULL);
500
501         abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
502
503         launching_health_popup = false;
504 }
505
506 static void check_abnormal_status(void)
507 {
508         static int notify_status = DEVICE_NOTI_OFF;
509
510         if (old_battery.health != HEALTH_LOW && old_battery.health != HEALTH_HIGH &&
511             (battery.health == HEALTH_LOW || battery.health == HEALTH_HIGH))
512                 update_health(DEVICE_NOTI_ON);
513         else if ((old_battery.health == HEALTH_LOW || old_battery.health == HEALTH_HIGH) &&
514                 battery.health != HEALTH_LOW && battery.health != HEALTH_HIGH)
515                 update_health(DEVICE_NOTI_OFF);
516
517         if (old_battery.present != PRESENT_ABNORMAL && battery.present == PRESENT_ABNORMAL)
518                 update_present(DEVICE_NOTI_ON);
519         else if (battery.present != PRESENT_ABNORMAL && old_battery.present == PRESENT_ABNORMAL)
520                 update_present(DEVICE_NOTI_OFF);
521
522         if (old_battery.health != HEALTH_OVP && battery.health == HEALTH_OVP) {
523                 _I("Charge %d OVP %d(old %d)",
524                         battery.charge_now, battery.health, old_battery.health);
525
526                 old_battery.health = battery.health;
527
528                 if (notify_status == DEVICE_NOTI_ON)
529                         return;
530                 notify_status = DEVICE_NOTI_ON;
531
532                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)&battery.health);
533
534                 if (battery_plgn->update_ovp)
535                         battery_plgn->update_ovp(DEVICE_NOTI_ON);
536         } else if (battery.health != HEALTH_OVP && old_battery.health == HEALTH_OVP) {
537                 _I("Charge %d OVP %d(old %d)",
538                         battery.charge_now, battery.health, old_battery.health);
539
540                 old_battery.health = battery.health;
541
542                 if (notify_status == DEVICE_NOTI_OFF)
543                         return;
544                 notify_status = DEVICE_NOTI_OFF;
545
546                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)&battery.health);
547
548                 if (battery_plgn->update_ovp)
549                         battery_plgn->update_ovp(DEVICE_NOTI_OFF);
550         }
551 }
552
553 static void check_charging_status(const char *env_value)
554 {
555         int len;
556
557         if (env_value == NULL)
558                 return;
559
560         len = strlen(env_value);
561         if (strncmp(env_value, CHARGEFULL_NAME, len) == 0)
562                 battery.charging_status = CHARGING_STATUS_FULL;
563         else if (strncmp(env_value, CHARGENOW_NAME, len) == 0)
564                 battery.charging_status = CHARGING_STATUS_CHARGING;
565         else if (strncmp(env_value, DISCHARGE_NAME, len) == 0)
566                 battery.charging_status = CHARGING_STATUS_DISCHARGING;
567         else if (strncmp(env_value, NOTCHARGE_NAME, len) == 0)
568                 battery.charging_status = CHARGING_STATUS_NOT_CHARGING;
569         else
570                 battery.charging_status = CHARGING_STATUS_UNKNOWN;
571
572         if (battery.charging_status == CHARGING_STATUS_FULL) {
573                 battery.charge_full = CHARGING_FULL;
574                 battery.charge_now = CHARGER_DISCHARGING;
575         } else if (battery.charging_status == CHARGING_STATUS_CHARGING) {
576                 battery.charge_full = CHARGING_NOT_FULL;
577                 battery.charge_now = CHARGER_CHARGING;
578         } else if (battery.charging_status == CHARGING_STATUS_DISCHARGING) {
579                 battery.charge_full = CHARGING_NOT_FULL;
580                 battery.charge_now = CHARGER_DISCHARGING;
581         } else if (battery.charging_status == CHARGING_STATUS_NOT_CHARGING) {
582                 battery.charge_full = CHARGING_NOT_FULL;
583                 battery.charge_now = CHARGER_ABNORMAL;
584         } else {
585                 battery.charge_full = CHARGING_NOT_FULL;
586                 battery.charge_now = CHARGER_DISCHARGING;
587         }
588 }
589
590 static void check_health_status(const char *env_value)
591 {
592         int len;
593
594         if (env_value == NULL) {
595                 battery.health = HEALTH_GOOD;
596                 return;
597         }
598
599         snprintf(battery.health_s, sizeof(battery.health_s), "%s", env_value);
600
601         len = strlen(env_value);
602         if (strncmp(env_value, OVERHEAT_NAME, len) == 0)
603                 battery.health = HEALTH_HIGH;
604         else if (strncmp(env_value, TEMPCOLD_NAME, len) == 0)
605                 battery.health = HEALTH_LOW;
606         else if (strncmp(env_value, OVERVOLT_NAME, len) == 0)
607                 battery.health = HEALTH_OVP;
608         else if (strncmp(env_value, GOOD_NAME, len) == 0)
609                 battery.health = HEALTH_GOOD;
610         else
611                 battery.health = HEALTH_NO_OPT;
612 }
613
614 static void check_power_source(const char *env_value)
615 {
616         int maxlen = sizeof(battery.power_source_s);
617
618         if (!env_value)
619                 return;
620
621         snprintf(battery.power_source_s, maxlen, "%s", env_value);
622         battery.power_source_s[maxlen - 1] = '\0';
623
624         if (strncmp(battery.power_source_s, "ac", sizeof("ac")) == 0) {
625                 battery.online_type = CHARGER_TYPE_AC;
626         } else if (strncmp(battery.power_source_s, "usb", sizeof("usb")) == 0) {
627                 battery.online_type = CHARGER_TYPE_USB;
628         } else if (strncmp(battery.power_source_s, "wireless", sizeof("wireless")) == 0) {
629                 battery.online_type = CHARGER_TYPE_WIRELESS;
630         } else {
631                 battery.online_type = CHARGER_TYPE_NONE;
632         }
633 }
634
635 static void check_misc_status(const char *env_value)
636 {
637         if (env_value == NULL) {
638                 battery.misc = MISC_NONE;
639                 return;
640         }
641         battery.misc = atoi(env_value);
642 }
643
644 static void notify_charger_event(int notifier)
645 {
646         struct battery_config_charger_event_handler **event_handlers =
647                                         g_battery_info.event_handlers;
648         int event_handler_number = g_battery_info.event_handler_number;
649
650         if (!event_handlers || event_handler_number <= 0) {
651                 _D("There is no charger event handler");
652                 return;
653         }
654
655         for (int i = 0; i < event_handler_number; ++i) {
656                 if (!event_handlers[i])
657                         continue;
658
659                 if (event_handlers[i]->notifier == notifier) {
660                         _D("Battery charger event=%s(%d)",
661                                 event_handlers[i]->name,
662                                 event_handlers[i]->id);
663
664                         if (event_handlers[i]->wakelock_duration)
665                                 event_acquire_wakelock(event_handlers[i]->id,
666                                                 event_handlers[i]->wakelock_duration);
667
668                         if (event_handlers[i]->broadcast)
669                                 event_broadcast_id(event_handlers[i]->id);
670                 }
671         }
672 }
673
674 static void process_power_supply(void *data)
675 {
676         bool broadcasted = true;
677         int ret_lock = -1;
678         int ret_val;
679
680         ret_lock = display_lock_request_lock_with_option(DEVICED_EVENT_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
681
682         if (old_battery.charge_now != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
683                 ret_val = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
684                 if (ret_val < 0)
685                         _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
686
687                 if (power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now) < 0)
688                         broadcasted = false;
689         }
690
691         if (!strcmp(old_battery.status_s, CHARGEFULL_NAME) &&
692                 !strcmp(battery.status_s, CHARGENOW_NAME)) {
693                 battery_pm_change_internal(DEVICED_EVENT_BATTERY, LCD_NORMAL);
694         }
695
696         if (old_battery.charge_full != battery.charge_full)
697                 if (power_supply_broadcast(CHARGE_FULL_SIGNAL, battery.charge_full) < 0)
698                         broadcasted = false;
699
700         if (strncmp(old_battery.health_s, battery.health_s, strlen(battery.health_s))) {
701                 snprintf(old_battery.health_s, sizeof(old_battery.health_s), "%s", battery.health_s);
702                 if (power_supply_broadcast_str(CHARGE_HEALTH_SIGNAL, battery.health_s) < 0)
703                         broadcasted = false;
704         }
705
706         if (old_battery.capacity != battery.capacity) {
707                 ret_val = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
708                 if (ret_val < 0)
709                         _E("Failed to set vconf value for battery capacity: %d", vconf_get_ext_errno());
710
711                 if (power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, battery.capacity) < 0)
712                         broadcasted = false;
713         }
714
715         (void)lowbat_execute(data);
716
717         if (old_battery.charger_connected != battery.charger_connected) {
718                 check_power_supply(battery.charger_connected);
719                 ret_val = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, battery.charger_connected);
720                 if (ret_val < 0)
721                         _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
722                 if (battery.charger_connected == 0) {
723                         CRITICAL_LOG("Battery charger disconnected");
724                         event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, EVT_VAL_BATTERY_CHARGER_CONNECTED);
725                         syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED, NULL);
726                         notify_charger_event(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED);
727                 } else if (battery.charger_connected == 1) {
728                         CRITICAL_LOG("Battery charger connected");
729                         event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, EVT_VAL_BATTERY_CHARGER_DISCONNECTED);
730                         syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, NULL);
731                         notify_charger_event(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED);
732                 } else {
733                         _E("Invalid charger connected");
734                 }
735         }
736
737         if (old_battery.charging_status != battery.charging_status)
738                 charger_state_send_system_event(battery.charging_status);
739
740         if (old_battery.online_type != battery.online_type) {
741                 ret_val = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_TYPE, battery.online_type);
742                 if (ret_val < 0)
743                         _E("Failed to set vconf value for charger type: %d", vconf_get_ext_errno());
744
745                 if (power_supply_broadcast(CHARGER_TYPE_SIGNAL, battery.online_type) < 0)
746                 broadcasted = false;
747         }
748
749         if (old_battery.misc != battery.misc)
750                 if (power_supply_broadcast(CHARGE_MISC_EVENT_SIGNAL, battery.misc) < 0)
751                         broadcasted = false;
752
753         if (old_battery.charge_full != battery.charge_full)
754                 noti_batt_full();
755
756         if (old_battery.charge_now != battery.charge_now ||
757             old_battery.charge_full != battery.charge_full ||
758             old_battery.capacity != battery.capacity ||
759             old_battery.health != battery.health ||
760                 old_battery.misc != battery.misc ||
761                 old_battery.online_type != battery.online_type)
762                 _I("Signal(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s)",
763                         broadcasted,
764                         CHARGER_STATUS_SIGNAL, battery.charger_connected,
765                         CHARGER_TYPE_SIGNAL, battery.online_type,
766                         CHARGE_NOW_SIGNAL, battery.charge_now,
767                         CHARGE_FULL_SIGNAL, battery.charge_full,
768                         CHARGE_CAPACITY_SIGNAL, battery.capacity,
769                         CHARGE_LEVEL_SIGNAL, battery.capacity_level,
770                         CHARGE_MISC_EVENT_SIGNAL, battery.misc,
771                         CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s);
772
773         old_battery.capacity = battery.capacity;
774         old_battery.capacity_level = battery.capacity_level;
775         old_battery.charger_connected = battery.charger_connected;
776         old_battery.online_type = battery.online_type;
777         old_battery.charging_status = battery.charging_status;
778         old_battery.charge_full = battery.charge_full;
779
780         old_battery.misc = battery.misc;
781         snprintf(old_battery.status_s, sizeof(old_battery.status_s), "%s", battery.status_s);
782
783         check_abnormal_status();
784
785         syscommon_notifier_emit_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
786         if (old_battery.charge_now != battery.charge_now) {
787                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, &battery.charge_now);
788                 old_battery.charge_now = battery.charge_now;
789         }
790
791         if (ret_lock == 0) {
792                 display_lock_request_unlock_with_option(DEVICED_EVENT_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
793         }
794 }
795
796 static int battery_state(struct battery_info *info)
797 {
798         static struct battery_status prev_status;
799
800         if (!info) {
801                 memcpy(&prev_status, &battery, sizeof(battery));
802                 return 0;
803         }
804
805         if (battery.capacity != 0 && prev_status.capacity == battery.capacity &&
806                 prev_status.charging_status == battery.charging_status &&
807                 prev_status.online_type == battery.online_type &&
808                 prev_status.charge_full == battery.charge_full &&
809                 prev_status.charge_now == battery.charge_now &&
810                 prev_status.health == battery.health &&
811                 prev_status.present == battery.present &&
812                 prev_status.current_now == battery.current_now &&
813                 prev_status.current_average == battery.current_average &&
814                 prev_status.charger_connected == battery.charger_connected)
815                 return 0;
816
817         prev_status.capacity = battery.capacity;
818         prev_status.charging_status = battery.charging_status;
819         prev_status.charge_full = battery.charge_full;
820         prev_status.charge_now = battery.charge_now;
821         prev_status.health = battery.health;
822         prev_status.present = battery.present;
823         prev_status.charger_connected = battery.charger_connected;
824
825         _I("%s(%s) %s(%d) Capa(%d) Hth(%s,%d) Pres(%d) Curr(%d,%d)",
826                         info->status,
827                         battery.charge_now == CHARGER_CHARGING ? "Charging"
828                                 : (battery.charge_now == CHARGER_DISCHARGING ? "Discharging" : "Abnormal"),
829                         info->power_source,
830                         info->online,
831                         info->capacity,
832                         info->health,
833                         battery.health,
834                         info->present,
835                         info->current_now,
836                         info->current_average);
837         return 1;
838 }
839
840 static void battery_disable_module(int value)
841 {
842         int retval;
843         static const struct invalidate_list {
844                 const char *vconfkey;
845                 int *member;
846         } list[] = {
847                 { VCONFKEY_SYSMAN_BATTERY_CAPACITY, &old_battery.capacity },
848                 { VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &old_battery.capacity_level },
849                 { VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, &old_battery.charge_now },
850                 { VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, NULL },
851         };
852
853         _D("Invalidate battery value to %d", value);
854
855         for (int i = 0; i < ARRAY_SIZE(list); ++i) {
856                 if (list[i].vconfkey) {
857                         retval = vconf_set_int(list[i].vconfkey, value);
858                         if (retval == 0)
859                                 _D("Set vconf %s to %d", list[i].vconfkey, value);
860                         else
861                                 _E("Failed to set %s to %d, %d", list[i].vconfkey, value, retval);
862                 }
863                 if (list[i].member)
864                         *(list[i].member) = value;
865         }
866
867         power_supply_exit(NULL);
868 }
869
870 static void battery_changed(struct battery_info *info, void *data)
871 {
872         int ret_val;
873
874         if (!info) {
875                 (void)battery_state(NULL);
876                 return;
877         }
878
879         if (info->status) {
880                 snprintf(battery.status_s, sizeof(battery.status_s),
881                                 "%s", info->status);
882                 check_charging_status(info->status);
883         } else
884                 battery.status_s[0] = '\0';
885
886         if (info->health) {
887                 snprintf(battery.health_s, sizeof(battery.health_s),
888                                 "%s", info->health);
889                 check_health_status(info->health);
890         } else
891                 battery.health_s[0] = '\0';
892
893         if (info->power_source)
894                 check_power_source(info->power_source);
895         else
896                 battery.power_source_s[0] = '\0';
897
898         battery.charger_connected = info->online;
899         battery.present = info->present;
900         battery.capacity = info->capacity;
901         battery.current_now = info->current_now;
902         battery.current_average = info->current_average;
903         battery.temperature = info->temperature;
904         battery.voltage_now = info->voltage_now;
905         battery.voltage_average = info->voltage_average;
906
907         battery_initialized = true;
908
909         ret_val = battery_state(info);
910         if (ret_val != 1)
911                 return;
912
913         ret_val = delayed_init_done(NULL);
914         if (ret_val) {
915                 /* If the same notification is requested repeatedly, it is ignored by power_supply_noti().
916                  * A notification will be triggered only when charging_status changes between
917                  * CHARGING_STATUS_CHARGING/FULL <-> CHARGING_STATUS_DISCHARGING. */
918                 if (battery.charging_status == CHARGING_STATUS_CHARGING || battery.charging_status == CHARGING_STATUS_FULL)
919                         power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
920                 else if (battery.charging_status == CHARGING_STATUS_DISCHARGING)
921                         power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
922         }
923
924         if (ret_val == 0) {
925                 battery.health = HEALTH_GOOD;
926                 battery.present = PRESENT_NORMAL;
927         }
928
929         if (battery.present) {
930                 process_power_supply(&battery.capacity);
931         } else {
932                 CRITICAL_LOG_E("Battery disconnected. Disable the battery module.");
933                 battery_disable_module(-ENODEV);
934         }
935 }
936
937 static gboolean power_supply_update_during_booting(void *data)
938 {
939         int retval;
940
941         retval = hal_device_battery_get_current_state(battery_changed, NULL);
942         if (retval == -ENODEV) {
943                 CRITICAL_LOG_E("There is no battery detected. Disable the battery module.");
944                 battery_disable_module(retval);
945                 return G_SOURCE_REMOVE;
946         }
947
948         return G_SOURCE_CONTINUE;
949 }
950
951 static void power_supply_timer_start(void)
952 {
953         _D("Battery init timer during booting.");
954         power_timer = g_timeout_add(BATTERY_CHECK_TIMER_INTERVAL,
955                                 power_supply_update_during_booting, NULL);
956         if (power_timer == 0)
957                 _E("Failed to add battery init timer during booting.");
958         else
959                 _I("Started battery init timer during booting.");
960 }
961
962 static GVariant *dbus_get_charger_status(GDBusConnection *conn,
963         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
964         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
965 {
966         int ret_val, status;
967
968         ret_val = vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &status);
969         if (ret_val < 0) {
970                 _E("Failed to get vconf value for charger status: %d", vconf_get_ext_errno());
971                 status = -EIO;
972         }
973         return g_variant_new("(i)", status);
974 }
975
976 static GVariant *dbus_get_charger_type(GDBusConnection *conn,
977         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
978         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
979 {
980         int type = battery.online_type;
981
982         return g_variant_new("(i)", type);
983 }
984
985 static GVariant *dbus_get_charge_now(GDBusConnection *conn,
986         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
987         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
988 {
989         int ret;
990
991         ret = battery.charge_now;
992
993         return g_variant_new("(i)", ret);
994 }
995
996 static GVariant *dbus_get_charge_level(GDBusConnection *conn,
997         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
998         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
999 {
1000         int ret, val;
1001
1002         ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &val);
1003         if (ret < 0) {
1004                 _E("Failed to get vconf value for battery status low: %d", vconf_get_ext_errno());
1005                 val = -EIO;
1006         }
1007
1008         return g_variant_new("(i)", val);
1009 }
1010
1011 static GVariant *dbus_get_percent(GDBusConnection *conn,
1012         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1013         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1014 {
1015         int ret;
1016
1017         ret = battery.capacity;
1018
1019         return g_variant_new("(i)", ret);
1020 }
1021
1022 static GVariant *dbus_get_percent_raw(GDBusConnection *conn,
1023         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1024         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1025 {
1026         int ret;
1027
1028         ret = -ENOTSUP;
1029
1030         return g_variant_new("(i)", ret);
1031 }
1032
1033 static GVariant *dbus_is_full(GDBusConnection *conn,
1034         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1035         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1036 {
1037         int ret;
1038
1039         ret = battery.charge_full;
1040
1041         return g_variant_new("(i)", ret);
1042 }
1043
1044 static GVariant *dbus_get_health(GDBusConnection *conn,
1045         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1046         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1047 {
1048         const char *str;
1049
1050         str = battery.health_s;
1051
1052         return g_variant_new("(s)", str);
1053 }
1054
1055 static GVariant *dbus_get_misc(GDBusConnection *conn,
1056         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1057         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1058 {
1059         int ret;
1060
1061         ret = battery.misc;
1062
1063         return g_variant_new("(i)", ret);
1064 }
1065
1066
1067 static GVariant *dbus_get_power_supply_handler(GDBusConnection *conn,
1068         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1069         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1070 {
1071         /* This method is for getting battery state after battery modification
1072          * by battery test driver. At this point, restore uevent buffering, which
1073          * had been disabled by test driver. */
1074         lowbat_enable_uevent_buffering();
1075
1076         return g_variant_new("(iiiiiiisiiiii)", 0,
1077                                 battery.capacity,
1078                                 battery.charging_status,
1079                                 battery.health,
1080                                 battery.charger_connected,
1081                                 battery.present,
1082                                 battery.misc,
1083                                 battery.power_source_s,
1084                                 battery.voltage_now,
1085                                 battery.voltage_average,
1086                                 battery.current_now,
1087                                 battery.current_average,
1088                                 battery.temperature);
1089 }
1090
1091 static GVariant *dbus_power_supply_handler(GDBusConnection *conn,
1092         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1093         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1094 {
1095         pid_t pid;
1096         int ret = 0, argc = 0;
1097         int charger_connected;
1098         char *type_str;
1099         char *argv[13];
1100         struct battery_info info = {0, };
1101
1102         g_variant_get(param, "(sisssisssssssss)", &type_str,
1103                                 &argc,
1104                                 &argv[0],
1105                                 &argv[1],
1106                                 &argv[2],
1107                                 &charger_connected,
1108                                 &argv[4],
1109                                 &argv[5],
1110                                 &argv[6],
1111                                 &argv[7],
1112                                 &argv[8],
1113                                 &argv[9],
1114                                 &argv[10],
1115                                 &argv[11],
1116                                 &argv[12]);
1117
1118         if (argc < 0) {
1119                 _E("Message is invalid.");
1120                 ret = -EINVAL;
1121                 goto out;
1122         }
1123
1124         pid = gdbus_connection_get_sender_pid(conn, sender);
1125         if (pid == -1 || kill(pid, 0) == -1) {
1126                 _E("Process(%d) does not exist, dbus ignored.", pid);
1127                 ret = -ESRCH;
1128                 goto out;
1129         }
1130
1131         /* The battery change triggered by this dbus must be processed
1132          * within a single subroutine as the objective of this method call is mostly
1133          * for the testing. Therefore, do not buffering the mocked uevent so that make
1134          * the test driver can get the changed battery result without waiting */
1135         lowbat_disable_uevent_buffering();
1136
1137         info.capacity = atoi(argv[0]);
1138         info.status = strdup(argv[1]);
1139         info.health = strdup(argv[2]);
1140         info.online = charger_connected;
1141         info.present = atoi(argv[4]);
1142         check_misc_status(argv[5]);
1143         info.power_source = strdup(argv[7]);
1144         info.voltage_now = atoi(argv[8]);
1145         info.voltage_average = atoi(argv[9]);
1146         info.current_now = atoi(argv[10]);
1147         info.current_average = atoi(argv[11]);
1148         info.temperature = atoi(argv[12]);
1149         _D("C(%d) S(%s) H(%s) O(%d) P(%d) SRC(%s) Vol(%d %d) Cur(%d %d) T(%d)",
1150                 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);
1151
1152         battery_changed(&info, NULL);
1153
1154 out:
1155         g_free(type_str);
1156         g_free(argv[0]);
1157         g_free(argv[1]);
1158         g_free(argv[2]);
1159         g_free(argv[4]);
1160         g_free(argv[5]);
1161         g_free(argv[6]);
1162         g_free(argv[7]);
1163         g_free(argv[8]);
1164         g_free(argv[9]);
1165         g_free(argv[10]);
1166         g_free(argv[11]);
1167         g_free(argv[12]);
1168
1169         free(info.status);
1170         free(info.health);
1171         free(info.power_source);
1172
1173         return g_variant_new("(i)", ret);
1174 }
1175
1176 static void battery_get_info(struct battery_info *info, void *data)
1177 {
1178         struct battery_info *bat = data;
1179
1180         if (!info || !bat)
1181                 return;
1182
1183         bat->status = strdup(info->status);
1184         bat->health = strdup(info->health);
1185         bat->power_source = strdup(info->power_source);
1186         bat->online = info->online;
1187         bat->present = info->present;
1188         bat->capacity = info->capacity;
1189         bat->current_now = info->current_now;
1190         bat->current_average = info->current_average;
1191         bat->temperature = info->temperature;
1192         bat->voltage_now = info->voltage_now;
1193         bat->voltage_average = info->voltage_average;
1194 }
1195
1196 static GVariant *dbus_get_battery_info(GDBusConnection *conn,
1197         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1198         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1199 {
1200         int ret = 0, val;
1201         const char *str;
1202         struct battery_info info = {0, };
1203
1204         if (old_state == DEVICE_NOTIFIER_STATE_STOP)
1205                 goto out;
1206
1207         if (battery_initialized)
1208                 goto out;
1209
1210         ret = hal_device_battery_get_current_state(battery_get_info, &info);
1211         if (ret != -ENODEV) {
1212                 if (ret < 0)
1213                         _E("Failed to get battery info: %d", ret);
1214
1215                 battery_changed(&info, NULL);
1216                 free(info.status);
1217                 free(info.health);
1218                 free(info.power_source);
1219         } else {
1220                 if (vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &val) == 0 &&
1221                         val != VCONFKEY_SYSMAN_USB_DISCONNECTED)
1222                         str = POWER_SOURCE_USB;
1223                 else if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &val) == 0 &&
1224                         val == VCONFKEY_SYSMAN_CHARGER_CONNECTED)
1225                         str = POWER_SOURCE_AC;
1226                 else
1227                         str = POWER_SOURCE_NONE;
1228                 snprintf(battery.power_source_s, sizeof(battery.power_source_s), "%s", str);
1229
1230                 battery.current_now = -1; /* Not supported */
1231                 battery.current_average = -1; /* Not supported */
1232                 ret = 0;
1233         }
1234
1235 out:
1236         return g_variant_new("(isssiiiiiiii)", ret,
1237                                 battery.status_s,
1238                                 battery.health_s,
1239                                 battery.power_source_s,
1240                                 battery.charger_connected,
1241                                 battery.present,
1242                                 battery.capacity,
1243                                 battery.current_now,
1244                                 battery.current_average,
1245                                 battery.voltage_now,
1246                                 battery.voltage_average,
1247                                 battery.temperature);
1248 }
1249
1250 static void update_battery_props(void)
1251 {
1252         if (config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery) < 0)
1253                 _E("Failed to check power supply uevent.");
1254 }
1255
1256 static GVariant *dbus_get_battery_props(GDBusConnection *conn,
1257         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1258         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1259 {
1260         update_battery_props();
1261
1262         return g_variant_new("(iiiiii)",
1263                                         battery.capacity,
1264                                         battery.temperature,
1265                                         battery.voltage_now,
1266                                         battery.voltage_average,
1267                                         battery.current_now,
1268                                         battery.current_average);
1269 }
1270
1271 static const dbus_method_s dbus_methods[] = {
1272         { CHARGER_STATUS_SIGNAL,      NULL, "i", dbus_get_charger_status },
1273         { CHARGE_NOW_SIGNAL,          NULL, "i", dbus_get_charge_now },
1274         { CHARGE_LEVEL_SIGNAL,         NULL, "i", dbus_get_charge_level },
1275         { CHARGE_CAPACITY_SIGNAL,     NULL, "i", dbus_get_percent },
1276         { CHARGE_CAPACITY_LAW_SIGNAL, NULL, "i", dbus_get_percent_raw },
1277         { CHARGE_FULL_SIGNAL,         NULL, "i", dbus_is_full },
1278         { CHARGE_HEALTH_SIGNAL,        NULL, "s", dbus_get_health },
1279         { POWER_SUBSYSTEM,      "sisssisssssssss", "i", dbus_power_supply_handler },
1280         { GET_POWER_SUBSYSTEM,      NULL, "iiiiiiisiiiii", dbus_get_power_supply_handler },
1281         { "GetBatteryInfo",           NULL, "isssiiiiiiii", dbus_get_battery_info },
1282         { CHARGER_TYPE_SIGNAL,         NULL, "i", dbus_get_charger_type },
1283         { CHARGE_BATTERY_PROPERTIES,   NULL, "iiiiii", dbus_get_battery_props },
1284         { CHARGE_MISC_EVENT_SIGNAL,    NULL, "i", dbus_get_misc },
1285 };
1286
1287 static const dbus_interface_u dbus_interface = {
1288         .oh = NULL,
1289         .name = DEVICED_INTERFACE_BATTERY,
1290         .methods = dbus_methods,
1291         .nr_methods = ARRAY_SIZE(dbus_methods),
1292 };
1293
1294 static int delayed_init_done(void *data)
1295 {
1296         static int done;
1297         int retval;
1298         device_notifier_state_e state = DEVICE_NOTIFIER_STATE_START;
1299
1300         if (data == NULL)
1301                 return done;
1302         done = *(int *)data;
1303         if (done == 0)
1304                 return done;
1305
1306         if (power_timer) {
1307                 g_source_remove(power_timer);
1308                 power_timer = 0;
1309         }
1310
1311         /* check battery has been initialized */
1312         retval = hal_device_battery_get_current_state(battery_changed, NULL);
1313         if (retval == -ENODEV) {
1314                 CRITICAL_LOG_E("Failed to initialize battery state, %d. Disable the battery module.", retval);
1315                 battery_disable_module(retval);
1316                 return done;
1317         }
1318
1319         event_handler_state_changed((void *)&state);
1320
1321         _I("booting done %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s)",
1322                         CHARGER_STATUS_SIGNAL, battery.charger_connected,
1323                         CHARGE_NOW_SIGNAL, battery.charge_now,
1324                         CHARGE_FULL_SIGNAL, battery.charge_full,
1325                         CHARGE_CAPACITY_SIGNAL, battery.capacity,
1326                         CHARGE_LEVEL_SIGNAL, battery.capacity_level,
1327                         CHARGE_MISC_EVENT_SIGNAL, battery.misc,
1328                         CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s);
1329
1330         syscommon_notifier_unsubscribe_notify(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1331
1332         return done;
1333 }
1334
1335 /**
1336  * FIXME: Getting display state shoule be done by display module function.
1337  * After refactoring display module, it should be changed to use getter in display module.
1338  */
1339 static int handle_display_state_changed(void *data)
1340 {
1341         if (!data) {
1342                 _E("Invalid parameter");
1343                 return -EINVAL;
1344         }
1345
1346         g_display_state = *(int *)data;
1347
1348         if (battery_plgn->launch_health_popup_by_display_state)
1349                 battery_plgn->launch_health_popup_by_display_state(g_display_state);
1350
1351         return 0;
1352 }
1353
1354 bool battery_do_not_disturb(void)
1355 {
1356         int block = 0, theater = 0, night = 0;
1357         int r;
1358
1359         if (g_display_state == DEVICED_DISPLAY_STATE_OFF) {
1360                 r = vconf_get_bool(VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL, &block);
1361                 if (r < 0)
1362                         _E("Failed to set vconf value for blockmode wearable: %d", vconf_get_ext_errno());
1363                 r = vconf_get_bool(VCONFKEY_SETAPPL_THEATER_MODE_ENABLE, &theater);
1364                 if (r < 0)
1365                         _E("Failed to set vconf value for theator mode enable: %d", vconf_get_ext_errno());
1366                 r = vconf_get_bool(VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE, &night);
1367                 if (r < 0)
1368                         _E("Failed to set vconf value for goodnight mode enable: %d", vconf_get_ext_errno());
1369         }
1370
1371         if (block != 0 || theater != 0 || night != 0) {
1372                 _I("Skip lcd and popup(block %d theater %d night %d).", block, theater, night);
1373                 return true;
1374         }
1375
1376         return false;
1377 }
1378
1379 int battery_pm_change_internal(int pid, int s_bits)
1380 {
1381         if (battery_do_not_disturb())
1382                 return 0;
1383
1384         display_state_transition_request_state_transition_with_option(pid, s_bits);
1385
1386         return 0;
1387 }
1388
1389 static int load_uevent(struct parse_result *result, void *user_data)
1390 {
1391         struct battery_status *info = user_data;
1392
1393         if (!info)
1394                 return -EINVAL;
1395
1396         if (MATCH(result->name, CHARGE_STATUS)) {
1397                 if (strstr(result->value, "Charging")) {
1398                         info->charge_now = CHARGER_CHARGING;
1399                         info->charge_full = CHARGING_NOT_FULL;
1400                 } else if (strstr(result->value, "Discharging")) {
1401                         info->charge_now = CHARGER_DISCHARGING;
1402                         info->charge_full = CHARGING_NOT_FULL;
1403                 } else if (strstr(result->value, "Full")) {
1404                         info->charge_now = CHARGER_DISCHARGING;
1405                         info->charge_full = CHARGING_FULL;
1406                 } else if (strstr(result->value, "Not charging")) {
1407                         info->charge_now = CHARGER_ABNORMAL;
1408                         info->charge_full = CHARGING_NOT_FULL;
1409                 }
1410                 snprintf(info->status_s, sizeof(info->status_s), "%s", result->value);
1411         } else if (MATCH(result->name, CAPACITY)) {
1412                 info->capacity = atoi(result->value);
1413         } else if (MATCH(result->name, TEMPERATURE)) {
1414                 info->temperature = atoi(result->value) / 10;
1415         } else if (MATCH(result->name, VOLTAGE_NOW)) {
1416                 info->voltage_now = atoi(result->value);
1417         } else if (MATCH(result->name, VOLTAGE_AVG)) {
1418                 info->voltage_average = atoi(result->value);
1419         } else if (MATCH(result->name, CURRENT_NOW)) {
1420                 info->current_now = atoi(result->value);
1421         } else if (MATCH(result->name, CURRENT_AVG)) {
1422                 info->current_average = atoi(result->value);
1423         } else if (MATCH(result->name, CHARGE_HEALTH)) {
1424                 snprintf(info->health_s, sizeof(info->health_s), "%s", result->value);
1425         }
1426
1427         return 0;
1428 }
1429
1430 static int power_supply_probe(void *data)
1431 {
1432         int ret_val, r;
1433
1434
1435         ret_val = hal_device_battery_get_backend();
1436         if (ret_val < 0) {
1437                 _E("There is no HAL for battery.");
1438                 if (access(POWER_PATH, R_OK) == 0)
1439                         return 0; /* Just power_supply uevent is used */
1440
1441                 goto out;
1442         }
1443
1444         _I("Battery device structure load success.");
1445         return 0;
1446
1447 out:
1448         /**
1449          * Set battery vconf as -ENOTSUP
1450          * These vconf key used by runtime-info and capi-system-device.
1451          */
1452         r = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, -ENOTSUP);
1453         if (r < 0)
1454                 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
1455         r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, -ENOTSUP);
1456         if (r < 0)
1457                 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
1458         r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, -ENOTSUP);
1459         if (r < 0)
1460                 _E("Failed to set vconf value for battery level status: %d", vconf_get_ext_errno());
1461         _I("There is no battery device: %d", ret_val);
1462         return -ENODEV;
1463 }
1464
1465 static void add_power_supply_handler(void)
1466 {
1467         hal_device_battery_register_changed_event(battery_changed, NULL);
1468         hal_device_battery_get_current_state(battery_changed, NULL);
1469 }
1470
1471 static void remove_power_supply_handler(void)
1472 {
1473         hal_device_battery_unregister_changed_event(battery_changed);
1474 }
1475
1476 static int event_handler_state_changed(void *data)
1477 {
1478         device_notifier_state_e state = *(device_notifier_state_e *)data;
1479
1480         if (old_state == state)
1481                 return 0;
1482
1483         old_state = state;
1484
1485         if (state == DEVICE_NOTIFIER_STATE_START)
1486                 add_power_supply_handler();
1487         else if (state == DEVICE_NOTIFIER_STATE_STOP)
1488                 remove_power_supply_handler();
1489
1490         return 0;
1491 }
1492
1493 static void power_supply_init(void *data)
1494 {
1495         int ret;
1496
1497         memset(&battery, 0, sizeof(struct battery_status));
1498         memset(&old_battery, 0, sizeof(struct battery_status));
1499         battery.misc = MISC_NONE;
1500         battery.charger_connected = -1;
1501
1502         /* It will be true on initializing battery structure */
1503         battery_initialized = false;
1504
1505         /* process check battery timer until booting done */
1506         power_supply_timer_start();
1507
1508         syscommon_notifier_subscribe_notify(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1509         syscommon_notifier_subscribe_notify(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1510         syscommon_notifier_subscribe_notify(DEVICE_NOTIFIER_LCD, handle_display_state_changed);
1511
1512         ret = gdbus_add_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
1513         if (ret < 0)
1514                 _E("Failed to init dbus method: %d", ret);
1515
1516         battery_ops_init((void *)battery_plgn);
1517
1518         battery_parser_load_config(&g_battery_info);
1519 }
1520
1521 static void power_supply_exit(void *data)
1522 {
1523         device_notifier_state_e state = DEVICE_NOTIFIER_STATE_STOP;
1524
1525         syscommon_notifier_unsubscribe_notify(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1526         syscommon_notifier_unsubscribe_notify(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1527
1528         event_handler_state_changed((void *)&state);
1529
1530         battery_ops_exit(NULL);
1531
1532         battery_parser_unload_config(&g_battery_info);
1533 }
1534
1535 static const struct device_ops power_supply_ops = {
1536         DECLARE_NAME_LEN("power_supply"),
1537         .probe    = power_supply_probe,
1538         .init     = power_supply_init,
1539         .exit     = power_supply_exit,
1540 };
1541
1542 DEVICE_OPS_REGISTER(&power_supply_ops)
1543
1544 static void __CONSTRUCTOR__ initialize(void)
1545 {
1546         battery_plgn = get_var_battery_plugin();
1547         if (!battery_plgn)
1548                 _E("Failed to get battery plugin variable.");
1549 }