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