1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "healthd"
18 #define KLOG_LEVEL 6
19 
20 #include "healthd.h"
21 #include "BatteryMonitor.h"
22 
23 #include <errno.h>
24 #include <libgen.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <batteryservice/BatteryService.h>
30 #include <cutils/klog.h>
31 #include <cutils/uevent.h>
32 #include <sys/epoll.h>
33 #include <sys/timerfd.h>
34 #include <utils/Errors.h>
35 
36 using namespace android;
37 
38 // Periodic chores intervals in seconds
39 #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
40 #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
41 
42 static struct healthd_config healthd_config = {
43     .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
44     .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
45     .batteryStatusPath = String8(String8::kEmptyString),
46     .batteryHealthPath = String8(String8::kEmptyString),
47     .batteryPresentPath = String8(String8::kEmptyString),
48     .batteryCapacityPath = String8(String8::kEmptyString),
49     .batteryVoltagePath = String8(String8::kEmptyString),
50     .batteryTemperaturePath = String8(String8::kEmptyString),
51     .batteryTechnologyPath = String8(String8::kEmptyString),
52     .batteryCurrentNowPath = String8(String8::kEmptyString),
53     .batteryCurrentAvgPath = String8(String8::kEmptyString),
54     .batteryChargeCounterPath = String8(String8::kEmptyString),
55     .energyCounter = NULL,
56     .boot_min_cap = 0,
57     .screen_on = NULL,
58 };
59 
60 static int eventct;
61 static int epollfd;
62 
63 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
64 
65 // epoll_create() parameter is actually unused
66 #define MAX_EPOLL_EVENTS 40
67 static int uevent_fd;
68 static int wakealarm_fd;
69 
70 // -1 for no epoll timeout
71 static int awake_poll_interval = -1;
72 
73 static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
74 
75 static BatteryMonitor* gBatteryMonitor;
76 
77 struct healthd_mode_ops *healthd_mode_ops;
78 
79 // Android mode
80 
81 extern void healthd_mode_android_init(struct healthd_config *config);
82 extern int healthd_mode_android_preparetowait(void);
83 extern void healthd_mode_android_battery_update(
84     struct android::BatteryProperties *props);
85 
86 // Charger mode
87 
88 extern void healthd_mode_charger_init(struct healthd_config *config);
89 extern int healthd_mode_charger_preparetowait(void);
90 extern void healthd_mode_charger_heartbeat(void);
91 extern void healthd_mode_charger_battery_update(
92     struct android::BatteryProperties *props);
93 
94 // NOPs for modes that need no special action
95 
96 static void healthd_mode_nop_init(struct healthd_config *config);
97 static int healthd_mode_nop_preparetowait(void);
98 static void healthd_mode_nop_heartbeat(void);
99 static void healthd_mode_nop_battery_update(
100     struct android::BatteryProperties *props);
101 
102 static struct healthd_mode_ops android_ops = {
103     .init = healthd_mode_android_init,
104     .preparetowait = healthd_mode_android_preparetowait,
105     .heartbeat = healthd_mode_nop_heartbeat,
106     .battery_update = healthd_mode_android_battery_update,
107 };
108 
109 static struct healthd_mode_ops charger_ops = {
110     .init = healthd_mode_charger_init,
111     .preparetowait = healthd_mode_charger_preparetowait,
112     .heartbeat = healthd_mode_charger_heartbeat,
113     .battery_update = healthd_mode_charger_battery_update,
114 };
115 
116 static struct healthd_mode_ops recovery_ops = {
117     .init = healthd_mode_nop_init,
118     .preparetowait = healthd_mode_nop_preparetowait,
119     .heartbeat = healthd_mode_nop_heartbeat,
120     .battery_update = healthd_mode_nop_battery_update,
121 };
122 
healthd_mode_nop_init(struct healthd_config *)123 static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
124 }
125 
healthd_mode_nop_preparetowait(void)126 static int healthd_mode_nop_preparetowait(void) {
127     return -1;
128 }
129 
healthd_mode_nop_heartbeat(void)130 static void healthd_mode_nop_heartbeat(void) {
131 }
132 
healthd_mode_nop_battery_update(struct android::BatteryProperties *)133 static void healthd_mode_nop_battery_update(
134     struct android::BatteryProperties* /*props*/) {
135 }
136 
healthd_register_event(int fd,void (* handler)(uint32_t))137 int healthd_register_event(int fd, void (*handler)(uint32_t)) {
138     struct epoll_event ev;
139 
140     ev.events = EPOLLIN | EPOLLWAKEUP;
141     ev.data.ptr = (void *)handler;
142     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
143         KLOG_ERROR(LOG_TAG,
144                    "epoll_ctl failed; errno=%d\n", errno);
145         return -1;
146     }
147 
148     eventct++;
149     return 0;
150 }
151 
wakealarm_set_interval(int interval)152 static void wakealarm_set_interval(int interval) {
153     struct itimerspec itval;
154 
155     if (wakealarm_fd == -1)
156             return;
157 
158     wakealarm_wake_interval = interval;
159 
160     if (interval == -1)
161         interval = 0;
162 
163     itval.it_interval.tv_sec = interval;
164     itval.it_interval.tv_nsec = 0;
165     itval.it_value.tv_sec = interval;
166     itval.it_value.tv_nsec = 0;
167 
168     if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
169         KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
170 }
171 
healthd_get_property(int id,struct BatteryProperty * val)172 status_t healthd_get_property(int id, struct BatteryProperty *val) {
173     return gBatteryMonitor->getProperty(id, val);
174 }
175 
healthd_battery_update(void)176 void healthd_battery_update(void) {
177     // Fast wake interval when on charger (watch for overheat);
178     // slow wake interval when on battery (watch for drained battery).
179 
180    int new_wake_interval = gBatteryMonitor->update() ?
181        healthd_config.periodic_chores_interval_fast :
182            healthd_config.periodic_chores_interval_slow;
183 
184     if (new_wake_interval != wakealarm_wake_interval)
185             wakealarm_set_interval(new_wake_interval);
186 
187     // During awake periods poll at fast rate.  If wake alarm is set at fast
188     // rate then just use the alarm; if wake alarm is set at slow rate then
189     // poll at fast rate while awake and let alarm wake up at slow rate when
190     // asleep.
191 
192     if (healthd_config.periodic_chores_interval_fast == -1)
193         awake_poll_interval = -1;
194     else
195         awake_poll_interval =
196             new_wake_interval == healthd_config.periodic_chores_interval_fast ?
197                 -1 : healthd_config.periodic_chores_interval_fast * 1000;
198 }
199 
healthd_dump_battery_state(int fd)200 void healthd_dump_battery_state(int fd) {
201     gBatteryMonitor->dumpState(fd);
202     fsync(fd);
203 }
204 
periodic_chores()205 static void periodic_chores() {
206     healthd_battery_update();
207 }
208 
209 #define UEVENT_MSG_LEN 2048
uevent_event(uint32_t)210 static void uevent_event(uint32_t /*epevents*/) {
211     char msg[UEVENT_MSG_LEN+2];
212     char *cp;
213     int n;
214 
215     n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
216     if (n <= 0)
217         return;
218     if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
219         return;
220 
221     msg[n] = '\0';
222     msg[n+1] = '\0';
223     cp = msg;
224 
225     while (*cp) {
226         if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
227             healthd_battery_update();
228             break;
229         }
230 
231         /* advance to after the next \0 */
232         while (*cp++)
233             ;
234     }
235 }
236 
uevent_init(void)237 static void uevent_init(void) {
238     uevent_fd = uevent_open_socket(64*1024, true);
239 
240     if (uevent_fd < 0) {
241         KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
242         return;
243     }
244 
245     fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
246     if (healthd_register_event(uevent_fd, uevent_event))
247         KLOG_ERROR(LOG_TAG,
248                    "register for uevent events failed\n");
249 }
250 
wakealarm_event(uint32_t)251 static void wakealarm_event(uint32_t /*epevents*/) {
252     unsigned long long wakeups;
253 
254     if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
255         KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
256         return;
257     }
258 
259     periodic_chores();
260 }
261 
wakealarm_init(void)262 static void wakealarm_init(void) {
263     wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
264     if (wakealarm_fd == -1) {
265         KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
266         return;
267     }
268 
269     if (healthd_register_event(wakealarm_fd, wakealarm_event))
270         KLOG_ERROR(LOG_TAG,
271                    "Registration of wakealarm event failed\n");
272 
273     wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
274 }
275 
healthd_mainloop(void)276 static void healthd_mainloop(void) {
277     while (1) {
278         struct epoll_event events[eventct];
279         int nevents;
280         int timeout = awake_poll_interval;
281         int mode_timeout;
282 
283         mode_timeout = healthd_mode_ops->preparetowait();
284         if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
285             timeout = mode_timeout;
286         nevents = epoll_wait(epollfd, events, eventct, timeout);
287 
288         if (nevents == -1) {
289             if (errno == EINTR)
290                 continue;
291             KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
292             break;
293         }
294 
295         for (int n = 0; n < nevents; ++n) {
296             if (events[n].data.ptr)
297                 (*(void (*)(int))events[n].data.ptr)(events[n].events);
298         }
299 
300         if (!nevents)
301             periodic_chores();
302 
303         healthd_mode_ops->heartbeat();
304     }
305 
306     return;
307 }
308 
healthd_init()309 static int healthd_init() {
310     epollfd = epoll_create(MAX_EPOLL_EVENTS);
311     if (epollfd == -1) {
312         KLOG_ERROR(LOG_TAG,
313                    "epoll_create failed; errno=%d\n",
314                    errno);
315         return -1;
316     }
317 
318     healthd_board_init(&healthd_config);
319     healthd_mode_ops->init(&healthd_config);
320     wakealarm_init();
321     uevent_init();
322     gBatteryMonitor = new BatteryMonitor();
323     gBatteryMonitor->init(&healthd_config);
324     return 0;
325 }
326 
main(int argc,char ** argv)327 int main(int argc, char **argv) {
328     int ch;
329     int ret;
330 
331     klog_set_level(KLOG_LEVEL);
332     healthd_mode_ops = &android_ops;
333 
334     if (!strcmp(basename(argv[0]), "charger")) {
335         healthd_mode_ops = &charger_ops;
336     } else {
337         while ((ch = getopt(argc, argv, "cr")) != -1) {
338             switch (ch) {
339             case 'c':
340                 healthd_mode_ops = &charger_ops;
341                 break;
342             case 'r':
343                 healthd_mode_ops = &recovery_ops;
344                 break;
345             case '?':
346             default:
347                 KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
348                            optopt);
349                 exit(1);
350             }
351         }
352     }
353 
354     ret = healthd_init();
355     if (ret) {
356         KLOG_ERROR("Initialization failed, exiting\n");
357         exit(2);
358     }
359 
360     healthd_mainloop();
361     KLOG_ERROR("Main loop terminated, exiting\n");
362     return 3;
363 }
364