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