blob: 82547db4fbb23cb44f2903a8d5e8e60803f68e8f [file] [log] [blame]
Todd Poynorfea5b4d2013-09-09 12:09:08 -07001/*
Luke Song1d540dd2017-07-13 15:10:35 -07002 * Copyright (C) 2011-2017 The Android Open Source Project
Todd Poynorfea5b4d2013-09-09 12:09:08 -07003 *
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#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
Colin Crosse1d52472014-05-15 17:49:06 -070020#include <inttypes.h>
Todd Poynorfea5b4d2013-09-09 12:09:08 -070021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/epoll.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <sys/un.h>
28#include <time.h>
29#include <unistd.h>
30
Tao Bao92c26012017-01-18 22:54:54 -080031#include <functional>
32
Damien Bargiacchi565ba022016-08-11 15:29:50 -070033#include <android-base/file.h>
Mark Salyzyn26f1dd72017-06-27 09:19:09 -070034#include <android-base/macros.h>
Damien Bargiacchi565ba022016-08-11 15:29:50 -070035
Todd Poynorfea5b4d2013-09-09 12:09:08 -070036#include <linux/netlink.h>
Luke Song1d540dd2017-07-13 15:10:35 -070037#include <sys/socket.h>
Todd Poynorfea5b4d2013-09-09 12:09:08 -070038
Todd Poynorfea5b4d2013-09-09 12:09:08 -070039#include <cutils/klog.h>
40#include <cutils/misc.h>
Riley Andrews6bd45882014-06-23 15:20:51 -070041#include <cutils/properties.h>
Luke Song1d540dd2017-07-13 15:10:35 -070042#include <cutils/uevent.h>
Todd Poynorc8183bb2017-01-31 15:51:50 -080043#include <sys/reboot.h>
Bharathc0d2a472020-04-15 11:39:06 +053044#include <cutils/android_reboot.h>
Todd Poynorfea5b4d2013-09-09 12:09:08 -070045#ifdef CHARGER_ENABLE_SUSPEND
46#include <suspend/autosuspend.h>
47#endif
48
Damien Bargiacchi565ba022016-08-11 15:29:50 -070049#include "AnimationParser.h"
Luke Song1d540dd2017-07-13 15:10:35 -070050#include "healthd_draw.h"
Todd Poynorfea5b4d2013-09-09 12:09:08 -070051
Yifan Hong10c2b402017-11-08 10:57:52 -080052#include <health2/Health.h>
Yabin Cuie98e1772016-02-17 12:21:34 -080053#include <healthd/healthd.h>
Todd Poynorfea5b4d2013-09-09 12:09:08 -070054
Damien Bargiacchi565ba022016-08-11 15:29:50 -070055using namespace android;
56
Luke Song1d540dd2017-07-13 15:10:35 -070057char* locale;
Colin Cross1c38f5d2014-02-13 13:34:37 -080058
Todd Poynorfea5b4d2013-09-09 12:09:08 -070059#ifndef max
Luke Song1d540dd2017-07-13 15:10:35 -070060#define max(a, b) ((a) > (b) ? (a) : (b))
Todd Poynorfea5b4d2013-09-09 12:09:08 -070061#endif
62
63#ifndef min
Luke Song1d540dd2017-07-13 15:10:35 -070064#define min(a, b) ((a) < (b) ? (a) : (b))
Todd Poynorfea5b4d2013-09-09 12:09:08 -070065#endif
66
Luke Song1d540dd2017-07-13 15:10:35 -070067#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
Todd Poynorfea5b4d2013-09-09 12:09:08 -070068
Luke Song1d540dd2017-07-13 15:10:35 -070069#define MSEC_PER_SEC (1000LL)
70#define NSEC_PER_MSEC (1000000LL)
Todd Poynorfea5b4d2013-09-09 12:09:08 -070071
Luke Song1d540dd2017-07-13 15:10:35 -070072#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
73#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
Todd Poynorfea5b4d2013-09-09 12:09:08 -070074#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
75
Luke Song1d540dd2017-07-13 15:10:35 -070076#define LAST_KMSG_MAX_SZ (32 * 1024)
Todd Poynorfea5b4d2013-09-09 12:09:08 -070077
Luke Song1d540dd2017-07-13 15:10:35 -070078#define LOGE(x...) KLOG_ERROR("charger", x);
79#define LOGW(x...) KLOG_WARNING("charger", x);
80#define LOGV(x...) KLOG_DEBUG("charger", x);
Todd Poynorfea5b4d2013-09-09 12:09:08 -070081
Luke Song1d540dd2017-07-13 15:10:35 -070082static constexpr const char* animation_desc_path =
83 "/res/values/charger/animation.txt";
Damien Bargiacchi565ba022016-08-11 15:29:50 -070084
Todd Poynorfea5b4d2013-09-09 12:09:08 -070085struct key_state {
86 bool pending;
87 bool down;
88 int64_t timestamp;
89};
90
Todd Poynorfea5b4d2013-09-09 12:09:08 -070091struct charger {
92 bool have_battery_state;
93 bool charger_connected;
Todd Poynorfea5b4d2013-09-09 12:09:08 -070094 int64_t next_screen_transition;
95 int64_t next_key_check;
96 int64_t next_pwr_check;
97
Luke Song1d540dd2017-07-13 15:10:35 -070098 key_state keys[KEY_MAX + 1];
Todd Poynorfea5b4d2013-09-09 12:09:08 -070099
Luke Song1d540dd2017-07-13 15:10:35 -0700100 animation* batt_anim;
Elliott Hughes9e85ea12015-04-15 10:25:55 -0700101 GRSurface* surf_unknown;
Ruchi Kandoia84b1f62014-10-21 18:24:11 -0700102 int boot_min_cap;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700103};
104
Luke Song1d540dd2017-07-13 15:10:35 -0700105static const animation BASE_ANIMATION = {
106 .text_clock =
107 {
108 .pos_x = 0,
109 .pos_y = 0,
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700110
Luke Song1d540dd2017-07-13 15:10:35 -0700111 .color_r = 255,
112 .color_g = 255,
113 .color_b = 255,
114 .color_a = 255,
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700115
Luke Song1d540dd2017-07-13 15:10:35 -0700116 .font = nullptr,
117 },
118 .text_percent =
119 {
120 .pos_x = 0,
121 .pos_y = 0,
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700122
Luke Song1d540dd2017-07-13 15:10:35 -0700123 .color_r = 255,
124 .color_g = 255,
125 .color_b = 255,
126 .color_a = 255,
127 },
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700128
129 .run = false,
130
131 .frames = nullptr,
132 .cur_frame = 0,
133 .num_frames = 0,
134 .first_frame_repeats = 2,
135
136 .cur_cycle = 0,
137 .num_cycles = 3,
138
139 .cur_level = 0,
140 .cur_status = BATTERY_STATUS_UNKNOWN,
141};
142
Luke Song1d540dd2017-07-13 15:10:35 -0700143static animation::frame default_animation_frames[] = {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700144 {
Filipec4546e92015-09-23 13:36:30 +0000145 .disp_time = 500,
146 .min_level = 0,
147 .max_level = 9,
148 .surface = NULL,
149 },
150 {
151 .disp_time = 500,
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700152 .min_level = 0,
153 .max_level = 19,
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700154 .surface = NULL,
155 },
156 {
Filipec4546e92015-09-23 13:36:30 +0000157 .disp_time = 500,
158 .min_level = 0,
159 .max_level = 29,
160 .surface = NULL,
161 },
162 {
163 .disp_time = 500,
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700164 .min_level = 0,
165 .max_level = 39,
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700166 .surface = NULL,
167 },
168 {
Filipec4546e92015-09-23 13:36:30 +0000169 .disp_time = 500,
170 .min_level = 0,
171 .max_level = 49,
172 .surface = NULL,
173 },
174 {
175 .disp_time = 500,
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700176 .min_level = 0,
177 .max_level = 59,
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700178 .surface = NULL,
179 },
180 {
Filipec4546e92015-09-23 13:36:30 +0000181 .disp_time = 500,
182 .min_level = 0,
183 .max_level = 69,
184 .surface = NULL,
185 },
186 {
187 .disp_time = 500,
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700188 .min_level = 0,
189 .max_level = 79,
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700190 .surface = NULL,
191 },
192 {
Filipec4546e92015-09-23 13:36:30 +0000193 .disp_time = 500,
194 .min_level = 0,
195 .max_level = 89,
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700196 .surface = NULL,
197 },
198 {
Filipec4546e92015-09-23 13:36:30 +0000199 .disp_time = 500,
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700200 .min_level = 0,
Filipec4546e92015-09-23 13:36:30 +0000201 .max_level = 97,
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700202 .surface = NULL,
203 },
204};
205
Luke Song1d540dd2017-07-13 15:10:35 -0700206static animation battery_animation = BASE_ANIMATION;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700207
Luke Song1d540dd2017-07-13 15:10:35 -0700208static charger charger_state;
209static healthd_config* healthd_config;
210static android::BatteryProperties* batt_prop;
211static std::unique_ptr<HealthdDraw> healthd_draw;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700212
213/* current time in milliseconds */
Luke Song1d540dd2017-07-13 15:10:35 -0700214static int64_t curr_time_ms() {
215 timespec tm;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700216 clock_gettime(CLOCK_MONOTONIC, &tm);
217 return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
218}
219
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700220#define MAX_KLOG_WRITE_BUF_SZ 256
221
Luke Song1d540dd2017-07-13 15:10:35 -0700222static void dump_last_kmsg(void) {
223 char* buf;
224 char* ptr;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700225 unsigned sz = 0;
226 int len;
227
Todd Poynorebeb0c02014-09-23 14:54:24 -0700228 LOGW("\n");
229 LOGW("*************** LAST KMSG ***************\n");
230 LOGW("\n");
Mark Salyzyn26f1dd72017-06-27 09:19:09 -0700231 const char* kmsg[] = {
232 // clang-format off
233 "/sys/fs/pstore/console-ramoops-0",
234 "/sys/fs/pstore/console-ramoops",
235 "/proc/last_kmsg",
236 // clang-format on
237 };
238 for (size_t i = 0; i < arraysize(kmsg); ++i) {
239 buf = (char*)load_file(kmsg[i], &sz);
240 if (buf && sz) break;
241 }
Todd Poynorcd7c1042013-11-22 17:52:59 -0800242
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700243 if (!buf || !sz) {
Mark Salyzyn26f1dd72017-06-27 09:19:09 -0700244 LOGW("last_kmsg not found. Cold reset?\n");
245 goto out;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700246 }
247
248 len = min(sz, LAST_KMSG_MAX_SZ);
249 ptr = buf + (sz - len);
250
251 while (len > 0) {
252 int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
253 char yoink;
Luke Song1d540dd2017-07-13 15:10:35 -0700254 char* nl;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700255
Luke Song1d540dd2017-07-13 15:10:35 -0700256 nl = (char*)memrchr(ptr, '\n', cnt - 1);
257 if (nl) cnt = nl - ptr + 1;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700258
259 yoink = ptr[cnt];
260 ptr[cnt] = '\0';
Todd Poynorebeb0c02014-09-23 14:54:24 -0700261 klog_write(6, "<4>%s", ptr);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700262 ptr[cnt] = yoink;
263
264 len -= cnt;
265 ptr += cnt;
266 }
267
268 free(buf);
269
270out:
Todd Poynorebeb0c02014-09-23 14:54:24 -0700271 LOGW("\n");
272 LOGW("************* END LAST KMSG *************\n");
273 LOGW("\n");
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700274}
275
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700276#ifdef CHARGER_ENABLE_SUSPEND
Luke Song1d540dd2017-07-13 15:10:35 -0700277static int request_suspend(bool enable) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700278 if (enable)
279 return autosuspend_enable();
280 else
281 return autosuspend_disable();
282}
283#else
Luke Song1d540dd2017-07-13 15:10:35 -0700284static int request_suspend(bool /*enable*/) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700285 return 0;
286}
287#endif
288
Luke Song1d540dd2017-07-13 15:10:35 -0700289static void kick_animation(animation* anim) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700290 anim->run = true;
291}
292
Luke Song1d540dd2017-07-13 15:10:35 -0700293static void reset_animation(animation* anim) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700294 anim->cur_cycle = 0;
295 anim->cur_frame = 0;
296 anim->run = false;
297}
298
Luke Song1d540dd2017-07-13 15:10:35 -0700299static void update_screen_state(charger* charger, int64_t now) {
300 animation* batt_anim = charger->batt_anim;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700301 int disp_time;
302
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700303 if (!batt_anim->run || now < charger->next_screen_transition) return;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700304
Luke Song1d540dd2017-07-13 15:10:35 -0700305 if (healthd_draw == nullptr) {
Ruchi Kandoibdf11c72014-09-25 19:44:42 -0700306 if (healthd_config && healthd_config->screen_on) {
307 if (!healthd_config->screen_on(batt_prop)) {
308 LOGV("[%" PRId64 "] leave screen off\n", now);
309 batt_anim->run = false;
310 charger->next_screen_transition = -1;
Luke Song1d540dd2017-07-13 15:10:35 -0700311 if (charger->charger_connected) request_suspend(true);
Ruchi Kandoibdf11c72014-09-25 19:44:42 -0700312 return;
313 }
Todd Poynora7300272014-06-30 13:15:05 -0700314 }
315
Luke Song1d540dd2017-07-13 15:10:35 -0700316 healthd_draw.reset(new HealthdDraw(batt_anim));
Todd Poynora7300272014-06-30 13:15:05 -0700317
318#ifndef CHARGER_DISABLE_INIT_BLANK
Luke Song1d540dd2017-07-13 15:10:35 -0700319 healthd_draw->blank_screen(true);
Todd Poynora7300272014-06-30 13:15:05 -0700320#endif
Todd Poynora7300272014-06-30 13:15:05 -0700321 }
322
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700323 /* animation is over, blank screen and leave */
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700324 if (batt_anim->num_cycles > 0 && batt_anim->cur_cycle == batt_anim->num_cycles) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700325 reset_animation(batt_anim);
326 charger->next_screen_transition = -1;
Luke Song1d540dd2017-07-13 15:10:35 -0700327 healthd_draw->blank_screen(true);
Colin Crosse1d52472014-05-15 17:49:06 -0700328 LOGV("[%" PRId64 "] animation done\n", now);
Luke Song1d540dd2017-07-13 15:10:35 -0700329 if (charger->charger_connected) request_suspend(true);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700330 return;
331 }
332
333 disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
334
Thierry Strudelac2aa7d2018-05-23 15:48:46 -0700335 /* unblank the screen on first cycle and first frame */
336 if (batt_anim->cur_cycle == 0 && batt_anim->cur_frame == 0) healthd_draw->blank_screen(false);
337
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700338 /* animation starting, set up the animation */
339 if (batt_anim->cur_frame == 0) {
Colin Crosse1d52472014-05-15 17:49:06 -0700340 LOGV("[%" PRId64 "] animation starting\n", now);
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700341 if (batt_prop) {
342 batt_anim->cur_level = batt_prop->batteryLevel;
343 batt_anim->cur_status = batt_prop->batteryStatus;
344 if (batt_prop->batteryLevel >= 0 && batt_anim->num_frames != 0) {
345 /* find first frame given current battery level */
346 for (int i = 0; i < batt_anim->num_frames; i++) {
347 if (batt_anim->cur_level >= batt_anim->frames[i].min_level &&
348 batt_anim->cur_level <= batt_anim->frames[i].max_level) {
349 batt_anim->cur_frame = i;
350 break;
351 }
352 }
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700353
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700354 // repeat the first frame first_frame_repeats times
355 disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
Luke Song1d540dd2017-07-13 15:10:35 -0700356 batt_anim->first_frame_repeats;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700357 }
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700358 }
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700359 }
360
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700361 /* draw the new frame (@ cur_frame) */
Luke Song1d540dd2017-07-13 15:10:35 -0700362 healthd_draw->redraw_screen(charger->batt_anim, charger->surf_unknown);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700363
364 /* if we don't have anim frames, we only have one image, so just bump
365 * the cycle counter and exit
366 */
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700367 if (batt_anim->num_frames == 0 || batt_anim->cur_level < 0) {
368 LOGW("[%" PRId64 "] animation missing or unknown battery status\n", now);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700369 charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
370 batt_anim->cur_cycle++;
371 return;
372 }
373
374 /* schedule next screen transition */
375 charger->next_screen_transition = now + disp_time;
376
Ruchi Kandoi9015eaa2014-06-23 11:13:15 -0700377 /* advance frame cntr to the next valid frame only if we are charging
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700378 * if necessary, advance cycle cntr, and reset frame cntr
379 */
Ruchi Kandoi9015eaa2014-06-23 11:13:15 -0700380 if (charger->charger_connected) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700381 batt_anim->cur_frame++;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700382
Ruchi Kandoi9015eaa2014-06-23 11:13:15 -0700383 while (batt_anim->cur_frame < batt_anim->num_frames &&
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700384 (batt_anim->cur_level < batt_anim->frames[batt_anim->cur_frame].min_level ||
385 batt_anim->cur_level > batt_anim->frames[batt_anim->cur_frame].max_level)) {
Ruchi Kandoi9015eaa2014-06-23 11:13:15 -0700386 batt_anim->cur_frame++;
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700387 }
Ruchi Kandoi9015eaa2014-06-23 11:13:15 -0700388 if (batt_anim->cur_frame >= batt_anim->num_frames) {
389 batt_anim->cur_cycle++;
390 batt_anim->cur_frame = 0;
391
392 /* don't reset the cycle counter, since we use that as a signal
393 * in a test above to check if animation is over
394 */
395 }
396 } else {
397 /* Stop animating if we're not charging.
398 * If we stop it immediately instead of going through this loop, then
399 * the animation would stop somewhere in the middle.
400 */
401 batt_anim->cur_frame = 0;
402 batt_anim->cur_cycle++;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700403 }
404}
405
Luke Song1d540dd2017-07-13 15:10:35 -0700406static int set_key_callback(charger* charger, int code, int value) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700407 int64_t now = curr_time_ms();
408 int down = !!value;
409
Luke Song1d540dd2017-07-13 15:10:35 -0700410 if (code > KEY_MAX) return -1;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700411
412 /* ignore events that don't modify our state */
Luke Song1d540dd2017-07-13 15:10:35 -0700413 if (charger->keys[code].down == down) return 0;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700414
415 /* only record the down even timestamp, as the amount
416 * of time the key spent not being pressed is not useful */
Luke Song1d540dd2017-07-13 15:10:35 -0700417 if (down) charger->keys[code].timestamp = now;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700418 charger->keys[code].down = down;
419 charger->keys[code].pending = true;
420 if (down) {
Colin Crosse1d52472014-05-15 17:49:06 -0700421 LOGV("[%" PRId64 "] key[%d] down\n", now, code);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700422 } else {
423 int64_t duration = now - charger->keys[code].timestamp;
424 int64_t secs = duration / 1000;
425 int64_t msecs = duration - secs * 1000;
Luke Song1d540dd2017-07-13 15:10:35 -0700426 LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n", now, code,
427 secs, msecs);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700428 }
429
430 return 0;
431}
432
Luke Song1d540dd2017-07-13 15:10:35 -0700433static void update_input_state(charger* charger, input_event* ev) {
434 if (ev->type != EV_KEY) return;
Tao Bao92c26012017-01-18 22:54:54 -0800435 set_key_callback(charger, ev->code, ev->value);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700436}
437
Luke Song1d540dd2017-07-13 15:10:35 -0700438static void set_next_key_check(charger* charger, key_state* key, int64_t timeout) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700439 int64_t then = key->timestamp + timeout;
440
441 if (charger->next_key_check == -1 || then < charger->next_key_check)
442 charger->next_key_check = then;
443}
444
Luke Song1d540dd2017-07-13 15:10:35 -0700445static void process_key(charger* charger, int code, int64_t now) {
446 key_state* key = &charger->keys[code];
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700447
448 if (code == KEY_POWER) {
449 if (key->down) {
450 int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
451 if (now >= reboot_timeout) {
Riley Andrews6bd45882014-06-23 15:20:51 -0700452 /* We do not currently support booting from charger mode on
453 all devices. Check the property and continue booting or reboot
454 accordingly. */
455 if (property_get_bool("ro.enable_boot_charger_mode", false)) {
Todd Poynorebeb0c02014-09-23 14:54:24 -0700456 LOGW("[%" PRId64 "] booting from charger mode\n", now);
Riley Andrews6bd45882014-06-23 15:20:51 -0700457 property_set("sys.boot_from_charger_mode", "1");
458 } else {
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700459 if (charger->batt_anim->cur_level >= charger->boot_min_cap) {
Ruchi Kandoia84b1f62014-10-21 18:24:11 -0700460 LOGW("[%" PRId64 "] rebooting\n", now);
Todd Poynorc8183bb2017-01-31 15:51:50 -0800461 reboot(RB_AUTOBOOT);
Ruchi Kandoia84b1f62014-10-21 18:24:11 -0700462 } else {
Luke Song1d540dd2017-07-13 15:10:35 -0700463 LOGV("[%" PRId64
464 "] ignore power-button press, battery level "
465 "less than minimum\n",
466 now);
Ruchi Kandoia84b1f62014-10-21 18:24:11 -0700467 }
Riley Andrews6bd45882014-06-23 15:20:51 -0700468 }
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700469 } else {
470 /* if the key is pressed but timeout hasn't expired,
471 * make sure we wake up at the right-ish time to check
472 */
473 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
Ruchi Kandoi9a11aaa2014-10-22 14:16:35 -0700474
Luke Song1d540dd2017-07-13 15:10:35 -0700475 /* Turn on the display and kick animation on power-key press
476 * rather than on key release
477 */
Ruchi Kandoi9a11aaa2014-10-22 14:16:35 -0700478 kick_animation(charger->batt_anim);
479 request_suspend(false);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700480 }
481 } else {
482 /* if the power key got released, force screen state cycle */
483 if (key->pending) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700484 kick_animation(charger->batt_anim);
485 }
486 }
487 }
488
489 key->pending = false;
490}
491
Luke Song1d540dd2017-07-13 15:10:35 -0700492static void handle_input_state(charger* charger, int64_t now) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700493 process_key(charger, KEY_POWER, now);
494
495 if (charger->next_key_check != -1 && now > charger->next_key_check)
496 charger->next_key_check = -1;
497}
498
Luke Song1d540dd2017-07-13 15:10:35 -0700499static void handle_power_supply_state(charger* charger, int64_t now) {
500 if (!charger->have_battery_state) return;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700501
Bharathc0d2a472020-04-15 11:39:06 +0530502 healthd_board_mode_charger_battery_update(batt_prop);
503
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700504 if (!charger->charger_connected) {
Ruchi Kandoi9a11aaa2014-10-22 14:16:35 -0700505 /* Last cycle would have stopped at the extreme top of battery-icon
506 * Need to show the correct level corresponding to capacity.
507 */
508 kick_animation(charger->batt_anim);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700509 request_suspend(false);
510 if (charger->next_pwr_check == -1) {
511 charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
Todd Poynorebeb0c02014-09-23 14:54:24 -0700512 LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
Colin Crosse1d52472014-05-15 17:49:06 -0700513 now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700514 } else if (now >= charger->next_pwr_check) {
Todd Poynorebeb0c02014-09-23 14:54:24 -0700515 LOGW("[%" PRId64 "] shutting down\n", now);
Todd Poynorc8183bb2017-01-31 15:51:50 -0800516 reboot(RB_POWER_OFF);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700517 } else {
518 /* otherwise we already have a shutdown timer scheduled */
519 }
520 } else {
521 /* online supply present, reset shutdown timer if set */
522 if (charger->next_pwr_check != -1) {
Todd Poynorebeb0c02014-09-23 14:54:24 -0700523 LOGW("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700524 kick_animation(charger->batt_anim);
525 }
526 charger->next_pwr_check = -1;
527 }
528}
529
Luke Song1d540dd2017-07-13 15:10:35 -0700530void healthd_mode_charger_heartbeat() {
531 charger* charger = &charger_state;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700532 int64_t now = curr_time_ms();
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700533
534 handle_input_state(charger, now);
535 handle_power_supply_state(charger, now);
536
537 /* do screen update last in case any of the above want to start
538 * screen transitions (animations, etc)
539 */
540 update_screen_state(charger, now);
541}
542
Luke Song1d540dd2017-07-13 15:10:35 -0700543void healthd_mode_charger_battery_update(android::BatteryProperties* props) {
544 charger* charger = &charger_state;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700545
546 charger->charger_connected =
Luke Song1d540dd2017-07-13 15:10:35 -0700547 props->chargerAcOnline || props->chargerUsbOnline || props->chargerWirelessOnline;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700548
549 if (!charger->have_battery_state) {
550 charger->have_battery_state = true;
551 charger->next_screen_transition = curr_time_ms() - 1;
552 reset_animation(charger->batt_anim);
553 kick_animation(charger->batt_anim);
554 }
Ruchi Kandoibdf11c72014-09-25 19:44:42 -0700555 batt_prop = props;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700556}
557
Luke Song1d540dd2017-07-13 15:10:35 -0700558int healthd_mode_charger_preparetowait(void) {
559 charger* charger = &charger_state;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700560 int64_t now = curr_time_ms();
561 int64_t next_event = INT64_MAX;
562 int64_t timeout;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700563
Luke Song1d540dd2017-07-13 15:10:35 -0700564 LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n",
565 now, charger->next_screen_transition, charger->next_key_check, charger->next_pwr_check);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700566
Luke Song1d540dd2017-07-13 15:10:35 -0700567 if (charger->next_screen_transition != -1) next_event = charger->next_screen_transition;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700568 if (charger->next_key_check != -1 && charger->next_key_check < next_event)
569 next_event = charger->next_key_check;
570 if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
571 next_event = charger->next_pwr_check;
572
573 if (next_event != -1 && next_event != INT64_MAX)
574 timeout = max(0, next_event - now);
575 else
576 timeout = -1;
577
Luke Song1d540dd2017-07-13 15:10:35 -0700578 return (int)timeout;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700579}
580
Luke Song1d540dd2017-07-13 15:10:35 -0700581static int input_callback(charger* charger, int fd, unsigned int epevents) {
582 input_event ev;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700583 int ret;
584
585 ret = ev_get_input(fd, epevents, &ev);
Luke Song1d540dd2017-07-13 15:10:35 -0700586 if (ret) return -1;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700587 update_input_state(charger, &ev);
588 return 0;
589}
590
Luke Song1d540dd2017-07-13 15:10:35 -0700591static void charger_event_handler(uint32_t /*epevents*/) {
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700592 int ret;
593
594 ret = ev_wait(-1);
Luke Song1d540dd2017-07-13 15:10:35 -0700595 if (!ret) ev_dispatch();
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700596}
597
Luke Song1d540dd2017-07-13 15:10:35 -0700598animation* init_animation() {
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700599 bool parse_success;
600
601 std::string content;
602 if (base::ReadFileToString(animation_desc_path, &content)) {
603 parse_success = parse_animation_desc(content, &battery_animation);
604 } else {
605 LOGW("Could not open animation description at %s\n", animation_desc_path);
606 parse_success = false;
607 }
608
609 if (!parse_success) {
610 LOGW("Could not parse animation description. Using default animation.\n");
611 battery_animation = BASE_ANIMATION;
612 battery_animation.animation_file.assign("charger/battery_scale");
613 battery_animation.frames = default_animation_frames;
614 battery_animation.num_frames = ARRAY_SIZE(default_animation_frames);
615 }
616 if (battery_animation.fail_file.empty()) {
617 battery_animation.fail_file.assign("charger/battery_fail");
618 }
619
620 LOGV("Animation Description:\n");
Luke Song1d540dd2017-07-13 15:10:35 -0700621 LOGV(" animation: %d %d '%s' (%d)\n", battery_animation.num_cycles,
622 battery_animation.first_frame_repeats, battery_animation.animation_file.c_str(),
623 battery_animation.num_frames);
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700624 LOGV(" fail_file: '%s'\n", battery_animation.fail_file.c_str());
Luke Song1d540dd2017-07-13 15:10:35 -0700625 LOGV(" clock: %d %d %d %d %d %d '%s'\n", battery_animation.text_clock.pos_x,
626 battery_animation.text_clock.pos_y, battery_animation.text_clock.color_r,
627 battery_animation.text_clock.color_g, battery_animation.text_clock.color_b,
628 battery_animation.text_clock.color_a, battery_animation.text_clock.font_file.c_str());
629 LOGV(" percent: %d %d %d %d %d %d '%s'\n", battery_animation.text_percent.pos_x,
630 battery_animation.text_percent.pos_y, battery_animation.text_percent.color_r,
631 battery_animation.text_percent.color_g, battery_animation.text_percent.color_b,
632 battery_animation.text_percent.color_a, battery_animation.text_percent.font_file.c_str());
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700633 for (int i = 0; i < battery_animation.num_frames; i++) {
634 LOGV(" frame %.2d: %d %d %d\n", i, battery_animation.frames[i].disp_time,
Luke Song1d540dd2017-07-13 15:10:35 -0700635 battery_animation.frames[i].min_level, battery_animation.frames[i].max_level);
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700636 }
637
638 return &battery_animation;
639}
640
Luke Song1d540dd2017-07-13 15:10:35 -0700641void healthd_mode_charger_init(struct healthd_config* config) {
Yifan Hong10c2b402017-11-08 10:57:52 -0800642 using android::hardware::health::V2_0::implementation::Health;
643
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700644 int ret;
Luke Song1d540dd2017-07-13 15:10:35 -0700645 charger* charger = &charger_state;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700646 int i;
647 int epollfd;
648
649 dump_last_kmsg();
650
Todd Poynorebeb0c02014-09-23 14:54:24 -0700651 LOGW("--------------- STARTING CHARGER MODE ---------------\n");
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700652
Bharathc0d2a472020-04-15 11:39:06 +0530653 if(!healthd_board_mode_charger_init()) {
654 LOGE("healthd_mode_charger_init failed restarting\n");
655 android_reboot(ANDROID_RB_RESTART2, 0, 0);
656 }
657
Luke Song1d540dd2017-07-13 15:10:35 -0700658 ret = ev_init(std::bind(&input_callback, charger, std::placeholders::_1, std::placeholders::_2));
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700659 if (!ret) {
660 epollfd = ev_get_epollfd();
Tim Murraye89ea5e2016-10-18 16:35:15 -0700661 healthd_register_event(epollfd, charger_event_handler, EVENT_WAKEUP_FD);
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700662 }
663
Luke Song1d540dd2017-07-13 15:10:35 -0700664 animation* anim = init_animation();
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700665 charger->batt_anim = anim;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700666
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700667 ret = res_create_display_surface(anim->fail_file.c_str(), &charger->surf_unknown);
668 if (ret < 0) {
Thierry Strudelac2aa7d2018-05-23 15:48:46 -0700669 LOGE("Cannot load custom battery_fail image. Reverting to built in: %d\n", ret);
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700670 ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
671 if (ret < 0) {
672 LOGE("Cannot load built in battery_fail image\n");
673 charger->surf_unknown = NULL;
674 }
675 }
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700676
Elliott Hughes9e85ea12015-04-15 10:25:55 -0700677 GRSurface** scale_frames;
Doug Zongkeree6ef152014-03-11 08:42:09 -0700678 int scale_count;
Tao Bao0db80232015-12-16 10:57:10 -0800679 int scale_fps; // Not in use (charger/battery_scale doesn't have FPS text
680 // chunk). We are using hard-coded frame.disp_time instead.
Luke Song1d540dd2017-07-13 15:10:35 -0700681 ret = res_create_multi_display_surface(anim->animation_file.c_str(), &scale_count, &scale_fps,
682 &scale_frames);
Doug Zongkeree6ef152014-03-11 08:42:09 -0700683 if (ret < 0) {
684 LOGE("Cannot load battery_scale image\n");
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700685 anim->num_frames = 0;
686 anim->num_cycles = 1;
687 } else if (scale_count != anim->num_frames) {
Luke Song1d540dd2017-07-13 15:10:35 -0700688 LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n", scale_count,
689 anim->num_frames);
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700690 anim->num_frames = 0;
691 anim->num_cycles = 1;
Doug Zongkeree6ef152014-03-11 08:42:09 -0700692 } else {
Damien Bargiacchi565ba022016-08-11 15:29:50 -0700693 for (i = 0; i < anim->num_frames; i++) {
694 anim->frames[i].surface = scale_frames[i];
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700695 }
696 }
Luke Song1d540dd2017-07-13 15:10:35 -0700697 ev_sync_key_state(
698 std::bind(&set_key_callback, charger, std::placeholders::_1, std::placeholders::_2));
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700699
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700700 charger->next_screen_transition = -1;
701 charger->next_key_check = -1;
702 charger->next_pwr_check = -1;
Yifan Hong10c2b402017-11-08 10:57:52 -0800703
704 // Initialize Health implementation (which initializes the internal BatteryMonitor).
705 Health::initInstance(config);
706
Ruchi Kandoibdf11c72014-09-25 19:44:42 -0700707 healthd_config = config;
Ruchi Kandoia84b1f62014-10-21 18:24:11 -0700708 charger->boot_min_cap = config->boot_min_cap;
Todd Poynorfea5b4d2013-09-09 12:09:08 -0700709}