• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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