1 /*
2 * Copyright (c) 2021-2023 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 #include "battery_config.h"
18 #include "charger_log.h"
19 #include "charger_animation.h"
20 #include "init_reboot.h"
21 #include "v1_0/iinput_interfaces.h"
22 #include <cinttypes>
23 #include <linux/netlink.h>
24 #include <parameters.h>
25 #include <securec.h>
26
27 namespace OHOS {
28 namespace PowerMgr {
29 namespace {
30 constexpr int32_t SEC_TO_MSEC = 1000;
31 constexpr int32_t NSEC_TO_MSEC = 1000000;
32 constexpr int32_t REBOOT_TIME = 2000;
33 constexpr int32_t BACKLIGHT_OFF_TIME_MS = 10000;
34 constexpr int32_t VIBRATE_TIME_MS = 75;
35 const std::string REBOOT_CMD = "";
36 const std::string SHUTDOWN_CMD = "shutdown";
37 constexpr uint32_t INDEV_TYPE_UNKNOWN = 39;
38 } // namespace
39
40 std::unique_ptr<ChargerAnimation> ChargerThread::animation_ = nullptr;
41 bool ChargerThread::isChargeStateChanged_ = false;
42 bool ChargerThread::isConfigParse_ = false;
43 int32_t ChargerThread::lackPowerCapacity_ = -1;
44 sptr<HDI::Input::V1_0::IInputCallback> g_callback {nullptr};
45 sptr<HDI::Input::V1_0::IInputInterfaces> ChargerThread::inputInterface = nullptr;
46
47 struct KeyState {
48 bool isUp;
49 bool isDown;
50 int64_t timestamp;
51 };
52 struct KeyState g_keys[KEY_MAX + 1] = {};
53
GetCurrentTime()54 static int64_t GetCurrentTime()
55 {
56 timespec tm {};
57 clock_gettime(CLOCK_MONOTONIC, &tm);
58 return tm.tv_sec * SEC_TO_MSEC + (tm.tv_nsec / NSEC_TO_MSEC);
59 }
60
EventPkgCallback(const std::vector<HDI::Input::V1_0::EventPackage> & pkgs,uint32_t devIndex)61 int32_t ChargerThread::HdfInputEventCallback::EventPkgCallback(
62 const std::vector<HDI::Input::V1_0::EventPackage>& pkgs, uint32_t devIndex)
63 {
64 (void)devIndex;
65 if (pkgs.empty()) {
66 BATTERY_HILOGE(FEATURE_CHARGING, "pkgs is empty");
67 return HDF_FAILURE;
68 }
69 for (uint32_t i = 0; i < pkgs.size(); i++) {
70 struct input_event ev = {
71 .type = static_cast<__u16>(pkgs[i].type),
72 .code = static_cast<__u16>(pkgs[i].code),
73 .value = pkgs[i].value,
74 };
75 HandleInputEvent(&ev);
76 }
77 return HDF_SUCCESS;
78 }
79
HotPlugCallback(const HotPlugEvent & event)80 int32_t ChargerThread::HdfInputEventCallback::HotPlugCallback(const HotPlugEvent &event)
81 {
82 return HDF_SUCCESS;
83 }
84
SetKeyState(int32_t code,int32_t value,int64_t now)85 void ChargerThread::HdfInputEventCallback::SetKeyState(int32_t code, int32_t value, int64_t now)
86 {
87 bool isDown = !!value;
88
89 if (code > KEY_MAX) {
90 BATTERY_HILOGW(FEATURE_CHARGING, "code lager than KEY_MAX: %{public}d", code);
91 return;
92 }
93
94 if (g_keys[code].isDown == isDown) {
95 BATTERY_HILOGW(FEATURE_CHARGING, "PowerKey is already down");
96 return;
97 }
98
99 if (isDown) {
100 g_keys[code].timestamp = now;
101 }
102
103 g_keys[code].isDown = isDown;
104 g_keys[code].isUp = true;
105 }
106
HandleInputEvent(const struct input_event * iev)107 void ChargerThread::HdfInputEventCallback::HandleInputEvent(const struct input_event* iev)
108 {
109 input_event ev {};
110 ev.type = iev->type;
111 ev.code = iev->code;
112 ev.value = iev->value;
113 BATTERY_HILOGD(FEATURE_CHARGING, "ev.type=%{public}u, ev.code=%{public}u, ev.value=%{public}d",
114 ev.type, ev.code, ev.value);
115
116 if (ev.type != EV_KEY) {
117 BATTERY_HILOGW(FEATURE_CHARGING, "Wrong type");
118 return;
119 }
120 SetKeyState(ev.code, ev.value, GetCurrentTime());
121 }
122
HandleStates()123 void ChargerThread::HandleStates()
124 {
125 HandleChargingState();
126 HandlePowerKeyState();
127 HandleScreenState();
128 }
129
UpdateWaitInterval()130 int32_t ChargerThread::UpdateWaitInterval()
131 {
132 int64_t currentTime = GetCurrentTime();
133 int64_t nextWait = INT64_MAX;
134 int64_t timeout = INVALID;
135
136 if (keyWait_ != INVALID && keyWait_ < nextWait) {
137 nextWait = keyWait_;
138 }
139
140 if (backlightWait_ != INVALID && backlightWait_ < nextWait) {
141 nextWait = backlightWait_;
142 }
143
144 if (nextWait != INVALID && nextWait != INT64_MAX) {
145 if (nextWait - currentTime > 0) {
146 timeout = nextWait - currentTime;
147 } else {
148 timeout = 0;
149 }
150 }
151
152 return static_cast<int32_t>(timeout);
153 }
154
CycleMatters()155 void ChargerThread::CycleMatters()
156 {
157 if (!started_) {
158 started_ = true;
159 backlightWait_ = GetCurrentTime() - 1;
160 }
161
162 UpdateBatteryInfo(nullptr);
163 BATTERY_HILOGD(FEATURE_CHARGING, "chargeState_=%{public}d, capacity_=%{public}d", chargeState_, capacity_);
164 UpdateEpollInterval(chargeState_);
165 }
166
UpdateBatteryInfo(void * arg)167 void ChargerThread::UpdateBatteryInfo(void* arg)
168 {
169 BATTERY_HILOGD(FEATURE_CHARGING, "start update battery info by provider");
170 int32_t temperature = 0;
171 provider_->ParseTemperature(&temperature);
172 provider_->ParseCapacity(&capacity_);
173 int32_t oldChargeState = chargeState_;
174 provider_->ParseChargeState(&chargeState_);
175 BATTERY_HILOGD(FEATURE_CHARGING, "temperature=%{public}d, capacity_=%{public}d, chargeState_=%{public}d",
176 temperature, capacity_, chargeState_);
177 if (chargeState_ != oldChargeState) {
178 isChargeStateChanged_ = true;
179 } else {
180 isChargeStateChanged_ = false;
181 }
182
183 HandleTemperature(temperature);
184 HandleCapacity(capacity_);
185
186 led_->UpdateColor(chargeState_, capacity_);
187
188 if (backlight_->GetScreenState() == BatteryBacklight::SCREEN_ON) {
189 UpdateAnimation(chargeState_, capacity_);
190 }
191 }
192
HandleTemperature(const int32_t & temperature)193 void ChargerThread::HandleTemperature(const int32_t& temperature)
194 {
195 const int32_t DEFAULT_UPPER_TEMP_CONF = INT32_MAX;
196 const int32_t DEFAULT_LOWER_TEMP_CONF = INT32_MIN;
197 auto& batteryConfig = BatteryConfig::GetInstance();
198 auto highTemp = batteryConfig.GetInt("temperature.high", DEFAULT_UPPER_TEMP_CONF);
199 auto lowTemp = batteryConfig.GetInt("temperature.low", DEFAULT_LOWER_TEMP_CONF);
200 BATTERY_HILOGD(FEATURE_CHARGING, "temperature=%{public}d, lowTemp=%{public}d, highTemp=%{public}d", temperature,
201 lowTemp, highTemp);
202
203 if (((temperature <= lowTemp) || (temperature >= highTemp)) && (lowTemp != highTemp)) {
204 BATTERY_HILOGW(FEATURE_CHARGING, "temperature out of range, shutdown device");
205 DoReboot(SHUTDOWN_CMD.c_str());
206 }
207 }
208
HandleCapacity(const int32_t & capacity)209 void ChargerThread::HandleCapacity(const int32_t& capacity)
210 {
211 if (capacity > lackPowerCapacity_ &&
212 (chargeState_ == PowerSupplyProvider::CHARGE_STATE_DISABLE ||
213 chargeState_ == PowerSupplyProvider::CHARGE_STATE_NONE)) {
214 BATTERY_HILOGW(FEATURE_CHARGING, "Not Charging, Shutdown system");
215 DoReboot(SHUTDOWN_CMD.c_str());
216 }
217 }
218
UpdateAnimation(const int32_t & chargeState,const int32_t & capacity)219 void ChargerThread::UpdateAnimation(const int32_t& chargeState, const int32_t& capacity)
220 {
221 BATTERY_HILOGD(FEATURE_CHARGING, "start update animation, capacity=%{public}d", capacity);
222 if ((chargeState == PowerSupplyProvider::CHARGE_STATE_NONE) ||
223 (chargeState == PowerSupplyProvider::CHARGE_STATE_RESERVED)) {
224 BATTERY_HILOGD(FEATURE_CHARGING, "Unknown charge state");
225 return;
226 }
227
228 if (capacity <= lackPowerCapacity_) {
229 if (chargeState == PowerSupplyProvider::CHARGE_STATE_ENABLE) { // Charging state
230 BATTERY_HILOGD(FEATURE_CHARGING, "Lack power");
231 animation_->AnimationStop();
232 animation_->LackPowerNotChargingPromptStop();
233 animation_->LackPowerChargingPromptStart();
234 } else if (chargeState == PowerSupplyProvider::CHARGE_STATE_DISABLE) { // Not charging state
235 BATTERY_HILOGD(FEATURE_CHARGING, "Lack power, please connect charger");
236 animation_->AnimationStop();
237 animation_->LackPowerChargingPromptStop();
238 animation_->LackPowerNotChargingPromptStart();
239 } else {
240 BATTERY_HILOGD(FEATURE_CHARGING, "capacity=%{public}d, chargeState=%{public}d", capacity, chargeState);
241 }
242 } else if (chargeState == PowerSupplyProvider::CHARGE_STATE_ENABLE ||
243 chargeState == PowerSupplyProvider::CHARGE_STATE_FULL) { // Charging state
244 BATTERY_HILOGD(FEATURE_CHARGING, "Display animation according capacity");
245 animation_->LackPowerChargingPromptStop();
246 animation_->LackPowerNotChargingPromptStop();
247 animation_->AnimationStart(capacity);
248 }
249 }
250
InitAnimation()251 void ChargerThread::InitAnimation()
252 {
253 animation_ = std::make_unique<ChargerAnimation>();
254 animation_->InitConfig();
255 }
256
SetKeyWait(struct KeyState & key,int64_t timeout)257 void ChargerThread::SetKeyWait(struct KeyState& key, int64_t timeout)
258 {
259 int64_t nextMoment = key.timestamp + timeout;
260 if (keyWait_ == INVALID || nextMoment < keyWait_) {
261 keyWait_ = nextMoment;
262 }
263 }
264
HandleChargingState()265 void ChargerThread::HandleChargingState()
266 {
267 if ((chargeState_ == PowerSupplyProvider::CHARGE_STATE_NONE) ||
268 (chargeState_ == PowerSupplyProvider::CHARGE_STATE_RESERVED)) {
269 return;
270 }
271
272 if (isChargeStateChanged_) {
273 BATTERY_HILOGD(FEATURE_CHARGING, "Charging State has changed");
274 backlight_->TurnOnScreen();
275 backlightWait_ = GetCurrentTime() - 1;
276 UpdateAnimation(chargeState_, capacity_);
277 isChargeStateChanged_ = false;
278 }
279 }
280
HandleScreenState()281 void ChargerThread::HandleScreenState()
282 {
283 if (backlightWait_ != INVALID && GetCurrentTime() > backlightWait_ + BACKLIGHT_OFF_TIME_MS) {
284 backlight_->TurnOffScreen();
285 animation_->AnimationStop();
286 animation_->LackPowerChargingPromptStop();
287 animation_->LackPowerNotChargingPromptStop();
288 backlightWait_ = INVALID;
289 }
290 }
291
HandlePowerKeyState()292 void ChargerThread::HandlePowerKeyState()
293 {
294 auto now = GetCurrentTime();
295 HandlePowerKey(KEY_POWER, now);
296
297 BATTERY_HILOGD(FEATURE_CHARGING, "keyWait_=%{public}" PRId64 "", keyWait_);
298 if (keyWait_ != INVALID && now > keyWait_) {
299 keyWait_ = INVALID;
300 }
301 }
302
HandlePowerKey(int32_t keycode,int64_t now)303 void ChargerThread::HandlePowerKey(int32_t keycode, int64_t now)
304 {
305 if (keycode == KEY_POWER) {
306 static bool turnOnByKeydown = false;
307 if (g_keys[keycode].isDown) {
308 int64_t rebootTime = g_keys[keycode].timestamp + REBOOT_TIME;
309 if (now >= rebootTime) {
310 BATTERY_HILOGW(FEATURE_CHARGING, "reboot machine");
311 backlight_->TurnOffScreen();
312 vibrate_->HandleVibration(VIBRATE_TIME_MS);
313 DoReboot(REBOOT_CMD.c_str());
314 } else if (backlight_->GetScreenState() == BatteryBacklight::SCREEN_OFF) {
315 SetKeyWait(g_keys[keycode], REBOOT_TIME);
316 backlight_->TurnOnScreen();
317 UpdateAnimation(chargeState_, capacity_);
318 backlightWait_ = now - 1;
319 turnOnByKeydown = true;
320 }
321 } else if (g_keys[keycode].isUp) {
322 if (backlight_->GetScreenState() == BatteryBacklight::SCREEN_ON && !turnOnByKeydown) {
323 backlight_->TurnOffScreen();
324 animation_->AnimationStop();
325 animation_->LackPowerChargingPromptStop();
326 animation_->LackPowerNotChargingPromptStop();
327 backlightWait_ = INVALID;
328 } else {
329 backlight_->TurnOnScreen();
330 backlightWait_ = now - 1;
331 UpdateAnimation(chargeState_, capacity_);
332 }
333 g_keys[keycode].isUp = false;
334 turnOnByKeydown = false;
335 }
336 }
337 }
338
InitInput()339 void ChargerThread::InitInput()
340 {
341 inputInterface = nullptr;
342 inputInterface = HDI::Input::V1_0::IInputInterfaces::Get(true);
343 if (inputInterface == nullptr) {
344 BATTERY_HILOGE(FEATURE_CHARGING, "inputInterface is null");
345 return;
346 }
347
348 const uint32_t POWERKEY_INPUT_DEVICE = 2;
349 int32_t ret = inputInterface->OpenInputDevice(POWERKEY_INPUT_DEVICE);
350 if (ret != HDF_SUCCESS) {
351 BATTERY_HILOGE(FEATURE_CHARGING, "open device failed, index=%{public}u, ret=%{public}d",
352 POWERKEY_INPUT_DEVICE, ret);
353 return;
354 }
355
356 uint32_t devType = INDEV_TYPE_UNKNOWN;
357 ret = inputInterface->GetDeviceType(POWERKEY_INPUT_DEVICE, devType);
358 if (ret != HDF_SUCCESS) {
359 BATTERY_HILOGE(
360 FEATURE_CHARGING, "get device type failed, index=%{public}u, ret=%{public}d", POWERKEY_INPUT_DEVICE, ret);
361 return;
362 }
363
364 /* first param is powerkey input device, refer to device node '/dev/hdf_input_event2', so pass 2 */
365 if (g_callback == nullptr) {
366 g_callback = new (std::nothrow) HdfInputEventCallback();
367 }
368 if (g_callback == nullptr) {
369 BATTERY_HILOGE(FEATURE_CHARGING, "The callback_ is nullptr");
370 return;
371 }
372 ret = inputInterface->RegisterReportCallback(POWERKEY_INPUT_DEVICE, g_callback);
373 if (ret != HDF_SUCCESS) {
374 BATTERY_HILOGE(FEATURE_CHARGING, "register callback failed, index=%{public}u, ret=%{public}d",
375 POWERKEY_INPUT_DEVICE, ret);
376 return;
377 }
378 }
379
InitLackPowerCapacity()380 void ChargerThread::InitLackPowerCapacity()
381 {
382 if (!isConfigParse_) {
383 isConfigParse_ = BatteryConfig::GetInstance().ParseConfig();
384 }
385
386 auto& batteryConfig = BatteryConfig::GetInstance();
387 lackPowerCapacity_ = batteryConfig.GetInt("soc.shutdown");
388 BATTERY_HILOGD(FEATURE_CHARGING, "lackPowerCapacity_ = %{public}d", lackPowerCapacity_);
389 }
390
InitBatteryFileSystem()391 void ChargerThread::InitBatteryFileSystem()
392 {
393 provider_ = std::make_unique<PowerSupplyProvider>();
394 if (provider_ == nullptr) {
395 BATTERY_HILOGE(FEATURE_CHARGING, "make_unique PowerSupplyProvider return nullptr");
396 return;
397 }
398 provider_->InitBatteryPath();
399 provider_->InitPowerSupplySysfs();
400 }
401
InitVibration()402 void ChargerThread::InitVibration()
403 {
404 vibrate_ = std::make_unique<BatteryVibrate>();
405 if (vibrate_ == nullptr) {
406 BATTERY_HILOGE(FEATURE_CHARGING, "make_unique BatteryVibrate return nullptr");
407 return;
408 }
409
410 if (!vibrate_->InitVibration()) {
411 BATTERY_HILOGW(FEATURE_CHARGING, "InitVibration failed, vibration does not work");
412 }
413 }
414
InitBacklight()415 void ChargerThread::InitBacklight()
416 {
417 backlight_ = std::make_unique<BatteryBacklight>();
418 if (backlight_ == nullptr) {
419 BATTERY_HILOGE(FEATURE_CHARGING, "make_unique BatteryBacklight return nullptr");
420 return;
421 }
422 backlight_->TurnOnScreen();
423 }
424
InitLed()425 void ChargerThread::InitLed()
426 {
427 led_ = std::make_unique<BatteryLed>();
428 if (led_ == nullptr) {
429 BATTERY_HILOGE(FEATURE_CHARGING, "make_unique BatteryLed return nullptr");
430 return;
431 }
432
433 if (!isConfigParse_) {
434 isConfigParse_ = BatteryConfig::GetInstance().ParseConfig();
435 }
436 led_->InitLight();
437 led_->TurnOff();
438 }
439
Init()440 void ChargerThread::Init()
441 {
442 BATTERY_HILOGD(FEATURE_CHARGING, "start init charger thread");
443 InitLackPowerCapacity();
444 InitBatteryFileSystem();
445 InitVibration();
446 InitBacklight();
447 InitLed();
448 InitAnimation();
449 InitInput();
450 }
451
Run(void * service)452 void ChargerThread::Run(void* service)
453 {
454 BATTERY_HILOGI(FEATURE_CHARGING, "start run charger thread");
455 Init();
456 std::make_unique<std::thread>([this, service] { this->LoopingThreadEntry(service); })->join();
457 }
458 } // namespace PowerMgr
459 } // namespace OHOS
460