1526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil/*
2526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * Copyright (C) 2013 The Android Open Source Project
3526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil *
4526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * Licensed under the Apache License, Version 2.0 (the "License");
5526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * you may not use this file except in compliance with the License.
6526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * You may obtain a copy of the License at
7526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil *
8526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil *      http://www.apache.org/licenses/LICENSE-2.0
9526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil *
10526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * Unless required by applicable law or agreed to in writing, software
11526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * distributed under the License is distributed on an "AS IS" BASIS,
12526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * See the License for the specific language governing permissions and
14526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil * limitations under the License.
15526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil */
16526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
17526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#define LOG_TAG "healthd-common"
18526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#define KLOG_LEVEL 6
19526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
20526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <healthd/healthd.h>
21526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <healthd/BatteryMonitor.h>
22526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
23526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <errno.h>
24526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <libgen.h>
25526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <stdio.h>
26526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <stdlib.h>
27526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <string.h>
28526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <unistd.h>
29526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <batteryservice/BatteryService.h>
30526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <cutils/klog.h>
31526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <cutils/uevent.h>
32526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <sys/epoll.h>
33526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <sys/timerfd.h>
34526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#include <utils/Errors.h>
35526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
36526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilusing namespace android;
37526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
38526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
39526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil  // Periodic chores fast interval in seconds
40526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
41526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#else
42526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
43526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#endif
44526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
45526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
46526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil  // Periodic chores fast interval in seconds
47526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
48526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#else
49526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
50526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#endif
51526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
52526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic struct healthd_config healthd_config = {
53526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
54526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
55526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryStatusPath = String8(String8::kEmptyString),
56526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryHealthPath = String8(String8::kEmptyString),
57526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryPresentPath = String8(String8::kEmptyString),
58526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryCapacityPath = String8(String8::kEmptyString),
59526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryVoltagePath = String8(String8::kEmptyString),
60526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryTemperaturePath = String8(String8::kEmptyString),
61526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryTechnologyPath = String8(String8::kEmptyString),
62526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryCurrentNowPath = String8(String8::kEmptyString),
63526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryCurrentAvgPath = String8(String8::kEmptyString),
64526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryChargeCounterPath = String8(String8::kEmptyString),
65526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryFullChargePath = String8(String8::kEmptyString),
66526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .batteryCycleCountPath = String8(String8::kEmptyString),
67526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .energyCounter = NULL,
68526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .boot_min_cap = 0,
69526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    .screen_on = NULL,
70526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil};
71526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
72526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic int eventct;
73526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic int epollfd;
74526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
75526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#define POWER_SUPPLY_SUBSYSTEM "power_supply"
76526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
77526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil// epoll_create() parameter is actually unused
78526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#define MAX_EPOLL_EVENTS 40
79526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic int uevent_fd;
80526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic int wakealarm_fd;
81526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
82526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil// -1 for no epoll timeout
83526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic int awake_poll_interval = -1;
84526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
85526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
86526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
87526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic BatteryMonitor* gBatteryMonitor;
88526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
89526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstruct healthd_mode_ops *healthd_mode_ops;
90526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
91526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilint healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
92526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    struct epoll_event ev;
93526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
94526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    ev.events = EPOLLIN;
95526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
96526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (wakeup == EVENT_WAKEUP_FD)
97526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        ev.events |= EPOLLWAKEUP;
98526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
99526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    ev.data.ptr = (void *)handler;
100526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
101526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR(LOG_TAG,
102526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil                   "epoll_ctl failed; errno=%d\n", errno);
103526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        return -1;
104526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
105526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
106526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    eventct++;
107526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    return 0;
108526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
109526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
110526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic void wakealarm_set_interval(int interval) {
111526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    struct itimerspec itval;
112526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
113526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (wakealarm_fd == -1)
114526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            return;
115526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
116526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    wakealarm_wake_interval = interval;
117526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
118526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (interval == -1)
119526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        interval = 0;
120526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
121526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    itval.it_interval.tv_sec = interval;
122526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    itval.it_interval.tv_nsec = 0;
123526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    itval.it_value.tv_sec = interval;
124526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    itval.it_value.tv_nsec = 0;
125526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
126526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
127526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
128526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
129526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
130526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatus_t healthd_get_property(int id, struct BatteryProperty *val) {
131526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    return gBatteryMonitor->getProperty(id, val);
132526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
133526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
134526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilvoid healthd_battery_update(void) {
135526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    // Fast wake interval when on charger (watch for overheat);
136526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    // slow wake interval when on battery (watch for drained battery).
137526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
138526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil   int new_wake_interval = gBatteryMonitor->update() ?
139526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil       healthd_config.periodic_chores_interval_fast :
140526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil           healthd_config.periodic_chores_interval_slow;
141526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
142526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (new_wake_interval != wakealarm_wake_interval)
143526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            wakealarm_set_interval(new_wake_interval);
144526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
145526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    // During awake periods poll at fast rate.  If wake alarm is set at fast
146526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    // rate then just use the alarm; if wake alarm is set at slow rate then
147526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    // poll at fast rate while awake and let alarm wake up at slow rate when
148526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    // asleep.
149526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
150526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (healthd_config.periodic_chores_interval_fast == -1)
151526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        awake_poll_interval = -1;
152526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    else
153526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        awake_poll_interval =
154526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            new_wake_interval == healthd_config.periodic_chores_interval_fast ?
155526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil                -1 : healthd_config.periodic_chores_interval_fast * 1000;
156526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
157526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
158526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilvoid healthd_dump_battery_state(int fd) {
159526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    gBatteryMonitor->dumpState(fd);
160526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    fsync(fd);
161526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
162526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
163526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic void periodic_chores() {
164526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    healthd_battery_update();
165526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
166526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
167526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil#define UEVENT_MSG_LEN 2048
168526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic void uevent_event(uint32_t /*epevents*/) {
169526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    char msg[UEVENT_MSG_LEN+2];
170526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    char *cp;
171526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    int n;
172526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
173526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
174526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (n <= 0)
175526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        return;
176526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
177526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        return;
178526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
179526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    msg[n] = '\0';
180526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    msg[n+1] = '\0';
181526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    cp = msg;
182526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
183526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    while (*cp) {
184526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
185526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            healthd_battery_update();
186526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            break;
187526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        }
188526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
189526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        /* advance to after the next \0 */
190526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        while (*cp++)
191526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            ;
192526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
193526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
194526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
195526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic void uevent_init(void) {
196526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    uevent_fd = uevent_open_socket(64*1024, true);
197526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
198526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (uevent_fd < 0) {
199526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
200526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        return;
201526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
202526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
203526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
204526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
205526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR(LOG_TAG,
206526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil                   "register for uevent events failed\n");
207526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
208526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
209526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic void wakealarm_event(uint32_t /*epevents*/) {
210526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    unsigned long long wakeups;
211526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
212526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
213526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
214526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        return;
215526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
216526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
217526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    periodic_chores();
218526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
219526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
220526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic void wakealarm_init(void) {
221526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
222526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (wakealarm_fd == -1) {
223526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
224526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        return;
225526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
226526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
227526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
228526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR(LOG_TAG,
229526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil                   "Registration of wakealarm event failed\n");
230526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
231526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
232526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
233526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
234526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic void healthd_mainloop(void) {
235526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    int nevents = 0;
236526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    while (1) {
237526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        struct epoll_event events[eventct];
238526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        int timeout = awake_poll_interval;
239526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        int mode_timeout;
240526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
241526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        /* Don't wait for first timer timeout to run periodic chores */
242526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        if (!nevents)
243526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            periodic_chores();
244526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
245526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        healthd_mode_ops->heartbeat();
246526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
247526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        mode_timeout = healthd_mode_ops->preparetowait();
248526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
249526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            timeout = mode_timeout;
250526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        nevents = epoll_wait(epollfd, events, eventct, timeout);
251526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        if (nevents == -1) {
252526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            if (errno == EINTR)
253526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil                continue;
254526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
255526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            break;
256526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        }
257526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
258526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        for (int n = 0; n < nevents; ++n) {
259526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil            if (events[n].data.ptr)
260526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil                (*(void (*)(int))events[n].data.ptr)(events[n].events);
261526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        }
262526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
263526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
264526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    return;
265526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
266526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
267526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilstatic int healthd_init() {
268526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    epollfd = epoll_create(MAX_EPOLL_EVENTS);
269526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (epollfd == -1) {
270526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR(LOG_TAG,
271526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil                   "epoll_create failed; errno=%d\n",
272526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil                   errno);
273526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        return -1;
274526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
275526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
276526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    healthd_board_init(&healthd_config);
277526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    healthd_mode_ops->init(&healthd_config);
278526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    wakealarm_init();
279526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    uevent_init();
280526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    gBatteryMonitor = new BatteryMonitor();
281526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    gBatteryMonitor->init(&healthd_config);
282526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    return 0;
283526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
284526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
285526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patilint healthd_main() {
286526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    int ret;
287526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
288526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    klog_set_level(KLOG_LEVEL);
289526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
290526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (!healthd_mode_ops) {
291526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR("healthd ops not set, exiting\n");
292526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        exit(1);
293526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
294526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
295526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    ret = healthd_init();
296526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    if (ret) {
297526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        KLOG_ERROR("Initialization failed, exiting\n");
298526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil        exit(2);
299526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    }
300526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil
301526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    healthd_mainloop();
302526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    KLOG_ERROR("Main loop terminated, exiting\n");
303526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil    return 3;
304526f8cf339f6c215d2d89924824b674cb99cfcc9Sandeep Patil}
305