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