1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "charger_thread.h"
17
18 #include <cinttypes>
19 #include <securec.h>
20 #include <parameters.h>
21 #include <linux/netlink.h>
22 #include "updater_ui.h"
23 #include "text_label.h"
24 #include "view.h"
25 #include "input_manager.h"
26 #include "input_type.h"
27 #include "init_reboot.h"
28 #include "battery_config.h"
29 #include "battery_log.h"
30
31 namespace OHOS {
32 namespace HDI {
33 namespace Battery {
34 namespace V1_1 {
35 namespace {
36 constexpr int32_t SHUTDOWN_TIME_MS = 2000;
37 constexpr int32_t SEC_TO_MSEC = 1000;
38 constexpr int32_t NSEC_TO_MSEC = 1000000;
39 constexpr int32_t REBOOT_TIME = 2000;
40 constexpr int32_t BACKLIGHT_OFF_TIME_MS = 10000;
41 constexpr int32_t VIBRATE_TIME_MS = 75;
42 constexpr int32_t MAX_IMG_COUNT = 62;
43 constexpr int32_t MAX_IMG_NAME_SIZE = 255;
44 constexpr int32_t LOOP_TOP_PICTURES = 10;
45 const std::string REBOOT_CMD = "";
46 const std::string SHUTDOWN_CMD = "shutdown";
47 }
48
49 struct KeyState {
50 bool up;
51 bool down;
52 int64_t timestamp;
53 };
54
55 Frame* g_hosFrame = nullptr;
56 AnimationLabel* g_animationLabel = nullptr;
57 TextLabel* g_updateInfoLabel = nullptr;
58 struct KeyState g_keys[KEY_MAX + 1] = {};
59
GetCurrentTime()60 static int64_t GetCurrentTime()
61 {
62 timespec tm {};
63 clock_gettime(CLOCK_MONOTONIC, &tm);
64 return tm.tv_sec * SEC_TO_MSEC + (tm.tv_nsec / NSEC_TO_MSEC);
65 }
66
HandleStates()67 void ChargerThread::HandleStates()
68 {
69 HandleChargingState();
70 HandlePowerKeyState();
71 HandleScreenState();
72 }
73
UpdateWaitInterval()74 int32_t ChargerThread::UpdateWaitInterval()
75 {
76 int64_t currentTime = GetCurrentTime();
77 int64_t nextWait = INT64_MAX;
78 int64_t timeout = INVALID;
79
80 if (pluginWait_ != INVALID) {
81 nextWait = pluginWait_ - currentTime;
82 }
83
84 if (keyWait_ != INVALID && keyWait_ < nextWait) {
85 nextWait = keyWait_;
86 }
87
88 if (backlightWait_ != INVALID && backlightWait_ < nextWait) {
89 nextWait = backlightWait_;
90 }
91
92 if (nextWait != INVALID && nextWait != INT64_MAX) {
93 if (nextWait - currentTime > 0) {
94 timeout = nextWait - currentTime;
95 } else {
96 timeout = 0;
97 }
98 }
99
100 return static_cast<int32_t>(timeout);
101 }
102
AnimationInit()103 void ChargerThread::AnimationInit()
104 {
105 BATTERY_HILOGD(FEATURE_CHARGING, "start init animation");
106 int32_t screenH = 0;
107 int32_t screenW = 0;
108 auto* sfDev = new SurfaceDev(SurfaceDev::DevType::DRM_DEVICE);
109 sfDev->GetScreenSize(screenW, screenH);
110 View::BRGA888Pixel bgColor {0x00, 0x00, 0x00, 0xff};
111
112 g_hosFrame = new Frame(screenW, screenH, View::PixelFormat::BGRA888, sfDev);
113 g_hosFrame->SetBackgroundColor(&bgColor);
114
115 g_animationLabel = new AnimationLabel(90, 240, 360, 960 >> 1, g_hosFrame);
116 g_animationLabel->SetBackgroundColor(&bgColor);
117 LoadImages(g_animationLabel);
118
119 g_updateInfoLabel = new TextLabel(screenW / 3, 340, screenW / 3, 100, g_hosFrame);
120 g_updateInfoLabel->SetOutLineBold(false, false);
121 g_updateInfoLabel->SetBackgroundColor(&bgColor);
122
123 BATTERY_HILOGD(FEATURE_CHARGING, "finish init animation");
124 }
125
LoadImages(AnimationLabel * animationLabel)126 void ChargerThread::LoadImages(AnimationLabel* animationLabel)
127 {
128 BATTERY_HILOGD(FEATURE_CHARGING, "start load images");
129 char nameBuf[MAX_IMG_NAME_SIZE];
130 for (int32_t i = 0; i < MAX_IMG_COUNT; i++) {
131 if (memset_s(nameBuf, MAX_IMG_NAME_SIZE, 0, MAX_IMG_NAME_SIZE) != EOK) {
132 BATTERY_HILOGW(FEATURE_CHARGING, "memset_s failed");
133 return;
134 }
135
136 if (i < LOOP_TOP_PICTURES) {
137 if (snprintf_s(nameBuf, MAX_IMG_NAME_SIZE, MAX_IMG_NAME_SIZE - 1,
138 "/vendor/etc/charger/resources/loop0000%d.png", i) == -1) {
139 BATTERY_HILOGW(FEATURE_CHARGING, "snprintf_s failed, index=%{public}d", i);
140 return;
141 }
142 } else {
143 if (snprintf_s(nameBuf, MAX_IMG_NAME_SIZE, MAX_IMG_NAME_SIZE - 1,
144 "/vendor/etc/charger/resources/loop000%d.png", i) == -1) {
145 BATTERY_HILOGW(FEATURE_CHARGING, "snprintf_s failed, index=%{public}d", i);
146 return;
147 }
148 }
149
150 animationLabel->AddImg(nameBuf);
151 }
152 animationLabel->AddStaticImg(nameBuf);
153 }
154
UpdateAnimation(const int32_t & capacity)155 void ChargerThread::UpdateAnimation(const int32_t& capacity)
156 {
157 BATTERY_HILOGD(FEATURE_CHARGING, "start update animation, capacity=%{public}d", capacity);
158 AnimationLabel::needStop_ = false;
159
160 struct FocusInfo info {false, false};
161 struct Bold bold {false, false};
162 View::BRGA888Pixel bgColor {0x00, 0x00, 0x00, 0xff};
163 std::string displaySoc = " " + std::to_string(capacity) + "%";
164 TextLabelInit(g_updateInfoLabel, displaySoc, bold, info, bgColor);
165 g_animationLabel->UpdateLoop();
166 }
167
CycleMatters()168 void ChargerThread::CycleMatters()
169 {
170 if (!started_) {
171 started_ = true;
172 backlightWait_ = GetCurrentTime() - 1;
173 }
174
175 provider_->ParseCapacity(&capacity_);
176 provider_->ParseChargeState(&chargeState_);
177 BATTERY_HILOGI(FEATURE_CHARGING, "chargeState_=%{public}d, capacity_=%{public}d", chargeState_, capacity_);
178
179 UpdateEpollInterval(chargeState_);
180 }
181
UpdateBatteryInfo(void * arg)182 void ChargerThread::UpdateBatteryInfo(void* arg)
183 {
184 BATTERY_HILOGD(FEATURE_CHARGING, "start update battery info by provider");
185 int32_t temperature = 0;
186 provider_->ParseTemperature(&temperature);
187 provider_->ParseCapacity(&capacity_);
188 provider_->ParseChargeState(&chargeState_);
189 BATTERY_HILOGD(FEATURE_CHARGING, "temperature=%{public}d, capacity_=%{public}d, chargeState_=%{public}d",
190 temperature, capacity_, chargeState_);
191
192 HandleTemperature(temperature);
193 HandleCapacity(capacity_);
194
195 led_->UpdateColor(chargeState_, capacity_);
196 if (backlight_->GetScreenState()) {
197 UpdateAnimation(capacity_);
198 }
199 }
200
HandleCapacity(const int32_t & capacity)201 void ChargerThread::HandleCapacity(const int32_t& capacity)
202 {
203 const int32_t DEFAULT_CAPACITY_CONF = -1;
204 auto lowCapacity = BatteryConfig::GetInstance().GetInt("soc.shutdown", DEFAULT_CAPACITY_CONF);
205 BATTERY_HILOGD(FEATURE_CHARGING, "capacity=%{public}d, lowCapacity=%{public}d", capacity, lowCapacity);
206 if ((capacity <= lowCapacity) &&
207 ((chargeState_ == PowerSupplyProvider::CHARGE_STATE_NONE) ||
208 (chargeState_ == PowerSupplyProvider::CHARGE_STATE_RESERVED))) {
209 BATTERY_HILOGW(FEATURE_CHARGING, "low capacity, shutdown device");
210 DoReboot(SHUTDOWN_CMD.c_str());
211 }
212 }
213
HandleTemperature(const int32_t & temperature)214 void ChargerThread::HandleTemperature(const int32_t& temperature)
215 {
216 const int32_t DEFAULT_UPPER_TEMP_CONF = INT32_MAX;
217 const int32_t DEFAULT_LOWER_TEMP_CONF = INT32_MIN;
218 auto& batteryConfig = BatteryConfig::GetInstance();
219 auto highTemp = batteryConfig.GetInt("temperature.high", DEFAULT_UPPER_TEMP_CONF);
220 auto lowTemp = batteryConfig.GetInt("temperature.low", DEFAULT_LOWER_TEMP_CONF);
221 BATTERY_HILOGD(FEATURE_CHARGING, "temperature=%{public}d, lowTemp=%{public}d, highTemp=%{public}d",
222 temperature, lowTemp, highTemp);
223
224 if (((temperature <= lowTemp) || (temperature >= highTemp)) && (lowTemp != highTemp)) {
225 BATTERY_HILOGW(FEATURE_CHARGING, "temperature out of range, shutdown device");
226 DoReboot(SHUTDOWN_CMD.c_str());
227 }
228 }
229
SetKeyWait(struct KeyState & key,int64_t timeout)230 void ChargerThread::SetKeyWait(struct KeyState& key, int64_t timeout)
231 {
232 int64_t nextMoment = key.timestamp + timeout;
233 if (keyWait_ == INVALID || nextMoment < keyWait_) {
234 keyWait_ = nextMoment;
235 }
236 }
237
HandleChargingState()238 void ChargerThread::HandleChargingState()
239 {
240 int64_t now = GetCurrentTime();
241 BATTERY_HILOGD(FEATURE_CHARGING, "chargeState_=%{public}d, now=%{public}" PRId64 "", chargeState_, now);
242 if ((chargeState_ == PowerSupplyProvider::CHARGE_STATE_NONE) ||
243 (chargeState_ == PowerSupplyProvider::CHARGE_STATE_RESERVED)) {
244 if (pluginWait_ == INVALID) {
245 BATTERY_HILOGD(FEATURE_CHARGING, "wait plugin");
246 backlightWait_ = now - 1;
247 backlight_->TurnOnScreen();
248 led_->TurnOff();
249 AnimationLabel::needStop_ = true;
250 pluginWait_ = now + SHUTDOWN_TIME_MS;
251 } else if (now >= pluginWait_) {
252 BATTERY_HILOGI(FEATURE_CHARGING, "shutdown device, charger unplugged, pluginWait_=%{public}" PRId64 "",
253 pluginWait_);
254 DoReboot(SHUTDOWN_CMD.c_str());
255 } else {
256 BATTERY_HILOGD(FEATURE_CHARGING, "ShutDownDevice timer already in scheduled.");
257 }
258 } else {
259 if (pluginWait_ != INVALID) {
260 BATTERY_HILOGI(FEATURE_CHARGING, "update capacity_=%{public}d", capacity_);
261 backlightWait_ = now - 1;
262 backlight_->TurnOnScreen();
263 led_->UpdateColor(chargeState_, capacity_);
264 AnimationLabel::needStop_ = true;
265 UpdateAnimation(capacity_);
266 }
267 pluginWait_ = INVALID;
268 }
269 }
270
HandleScreenState()271 void ChargerThread::HandleScreenState()
272 {
273 if (backlightWait_ != INVALID && GetCurrentTime() > backlightWait_ + BACKLIGHT_OFF_TIME_MS) {
274 BATTERY_HILOGI(FEATURE_CHARGING, "turn off screen");
275 backlight_->TurnOffScreen();
276 AnimationLabel::needStop_ = true;
277 backlightWait_ = INVALID;
278 }
279 }
280
SetKeyState(int32_t code,int32_t value,int64_t now)281 void ChargerThread::SetKeyState(int32_t code, int32_t value, int64_t now)
282 {
283 BATTERY_HILOGD(FEATURE_CHARGING, "now=%{public}" PRId64 "", now);
284 bool down;
285 if (!!value) {
286 down = true;
287 } else {
288 down = false;
289 }
290
291 if (code > KEY_MAX) {
292 return;
293 }
294
295 if (g_keys[code].down == down) {
296 return;
297 }
298
299 if (down) {
300 g_keys[code].timestamp = now;
301 }
302
303 g_keys[code].down = down;
304 g_keys[code].up = true;
305 }
306
HandlePowerKeyState()307 void ChargerThread::HandlePowerKeyState()
308 {
309 auto now = GetCurrentTime();
310 BATTERY_HILOGD(FEATURE_CHARGING, "now=%{public}" PRId64 "", now);
311 HandlePowerKey(KEY_POWER, now);
312
313 BATTERY_HILOGD(FEATURE_CHARGING, "keyWait_=%{public}" PRId64 "", keyWait_);
314 if (keyWait_ != INVALID && now > keyWait_) {
315 keyWait_ = INVALID;
316 }
317 }
318
HandlePowerKey(int32_t keycode,int64_t now)319 void ChargerThread::HandlePowerKey(int32_t keycode, int64_t now)
320 {
321 KeyState key = g_keys[keycode];
322 if (keycode == KEY_POWER) {
323 if (key.down) {
324 BATTERY_HILOGD(FEATURE_CHARGING, "power key down");
325 int64_t rebootTime = key.timestamp + REBOOT_TIME;
326 if (now >= rebootTime) {
327 BATTERY_HILOGD(FEATURE_CHARGING, "reboot machine");
328 backlight_->TurnOffScreen();
329 AnimationLabel::needStop_ = true;
330 vibrate_->HandleVibration(VIBRATE_TIME_MS);
331 DoReboot(REBOOT_CMD.c_str());
332 } else {
333 SetKeyWait(key, REBOOT_TIME);
334 backlight_->TurnOnScreen();
335 AnimationLabel::needStop_ = true;
336 UpdateAnimation(capacity_);
337 backlightWait_ = now - 1;
338 BATTERY_HILOGD(FEATURE_CHARGING, "turn on the screen");
339 }
340 } else {
341 if (key.up) {
342 BATTERY_HILOGD(FEATURE_CHARGING, "power key up");
343 backlight_->TurnOnScreen();
344 AnimationLabel::needStop_ = true;
345 UpdateAnimation(capacity_);
346 backlightWait_ = now - 1;
347 }
348 }
349 }
350 }
351
HandleInputEvent(const struct input_event * iev)352 void ChargerThread::HandleInputEvent(const struct input_event* iev)
353 {
354 input_event ev {};
355 ev.type = iev->type;
356 ev.code = iev->code;
357 ev.value = iev->value;
358 BATTERY_HILOGD(FEATURE_CHARGING, "ev.type=%{public}d, ev.code=%{public}d, ev.value=%{public}d",
359 ev.type, ev.code, ev.value);
360
361 if (ev.type != EV_KEY) {
362 return;
363 }
364 SetKeyState(ev.code, ev.value, GetCurrentTime());
365 }
366
EventPkgCallback(const InputEventPackage ** pkgs,uint32_t count,uint32_t devIndex)367 void ChargerThread::EventPkgCallback(const InputEventPackage** pkgs, uint32_t count, uint32_t devIndex)
368 {
369 (void)devIndex;
370 BATTERY_HILOGD(FEATURE_CHARGING, "start key event callback");
371 if (pkgs == nullptr || *pkgs == nullptr) {
372 BATTERY_HILOGW(FEATURE_CHARGING, "pkgs or *pkgs is nullptr");
373 return;
374 }
375 for (uint32_t i = 0; i < count; i++) {
376 struct input_event ev = {
377 .type = static_cast<__u16>(pkgs[i]->type),
378 .code = static_cast<__u16>(pkgs[i]->code),
379 .value = pkgs[i]->value,
380 };
381 HandleInputEvent(&ev);
382 }
383 }
384
InitInput()385 void ChargerThread::InitInput()
386 {
387 BATTERY_HILOGD(FEATURE_CHARGING, "start init input");
388 IInputInterface* inputInterface = nullptr;
389 int32_t ret = GetInputInterface(&inputInterface);
390 if (ret != INPUT_SUCCESS) {
391 BATTERY_HILOGW(FEATURE_CHARGING, "get input driver interface failed, ret=%{public}d", ret);
392 return;
393 }
394
395 const uint32_t DEVICE_INDEX = 1;
396 ret = inputInterface->iInputManager->OpenInputDevice(DEVICE_INDEX);
397 if (ret != INPUT_SUCCESS) {
398 BATTERY_HILOGD(FEATURE_CHARGING, "open device failed, index=%{public}u, ret=%{public}d", DEVICE_INDEX, ret);
399 return;
400 }
401
402 uint32_t devType = InputDevType::INDEV_TYPE_UNKNOWN;
403 ret = inputInterface->iInputController->GetDeviceType(DEVICE_INDEX, &devType);
404 if (ret != INPUT_SUCCESS) {
405 BATTERY_HILOGW(FEATURE_CHARGING, "get device type failed, index=%{public}u, ret=%{public}d", DEVICE_INDEX, ret);
406 return;
407 }
408
409 InputEventCb callback = {
410 .EventPkgCallback = EventPkgCallback
411 };
412 ret = inputInterface->iInputReporter->RegisterReportCallback(DEVICE_INDEX, &callback);
413 if (ret != INPUT_SUCCESS) {
414 BATTERY_HILOGW(FEATURE_CHARGING, "register callback failed, index=%{public}u, ret=%{public}d", DEVICE_INDEX,
415 ret);
416 return;
417 }
418
419 BATTERY_HILOGD(FEATURE_CHARGING, "finish init input, index=%{public}u, type=%{public}u", DEVICE_INDEX, devType);
420 }
421
Init()422 void ChargerThread::Init()
423 {
424 BATTERY_HILOGD(FEATURE_CHARGING, "start init charger thread");
425 BatteryConfig::GetInstance().ParseConfig();
426
427 provider_ = std::make_unique<PowerSupplyProvider>();
428 if (provider_ == nullptr) {
429 BATTERY_HILOGE(FEATURE_CHARGING, "make_unique PowerSupplyProvider return nullptr");
430 return;
431 }
432 provider_->InitBatteryPath();
433 provider_->InitPowerSupplySysfs();
434
435 vibrate_ = std::make_unique<BatteryVibrate>();
436 if (vibrate_ == nullptr) {
437 BATTERY_HILOGE(FEATURE_CHARGING, "make_unique BatteryVibrate return nullptr");
438 return;
439 }
440
441 if (!vibrate_->InitVibration()) {
442 BATTERY_HILOGW(FEATURE_CHARGING, "InitVibration failed, vibration does not work");
443 }
444
445 backlight_ = std::make_unique<BatteryBacklight>();
446 if (backlight_ == nullptr) {
447 BATTERY_HILOGE(FEATURE_CHARGING, "make_unique BatteryBacklight return nullptr");
448 return;
449 }
450 backlight_->InitBacklightSysfs();
451 backlight_->TurnOnScreen();
452
453 led_ = std::make_unique<BatteryLed>();
454 if (led_ == nullptr) {
455 BATTERY_HILOGE(FEATURE_CHARGING, "make_unique BatteryLed return nullptr");
456 return;
457 }
458 led_->InitLight();
459 led_->TurnOff();
460
461 AnimationInit();
462 InitInput();
463 }
464
Run(void * service)465 void ChargerThread::Run(void* service)
466 {
467 BATTERY_HILOGI(FEATURE_CHARGING, "start run charger thread");
468 Init();
469 UpdateBatteryInfo(nullptr);
470 std::make_unique<std::thread>(&ChargerThread::LoopingThreadEntry, this, service)->join();
471 }
472 } // namespace V1_1
473 } // namespace Battery
474 } // namespace HDI
475 } // namespace OHOS
476