1 /*
2  * Copyright (c) 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 "battery_thread.h"
17 #include <cerrno>
18 #include <regex>
19 #include <sys/epoll.h>
20 #include <sys/socket.h>
21 #include <sys/timerfd.h>
22 #include <unistd.h>
23 #include <linux/netlink.h>
24 #include "battery_config.h"
25 #include "battery_log.h"
26 
27 namespace OHOS {
28 namespace HDI {
29 namespace Battery {
30 namespace V2_0 {
31 namespace {
32 constexpr int32_t UEVENT_BUFF_SIZE = (64 * 1024);
33 constexpr int32_t UEVENT_RESERVED_SIZE = 2;
34 constexpr int32_t UEVENT_MSG_LEN = (2 * 1024);
35 constexpr int32_t TIMER_FAST_SEC = 2;
36 constexpr int32_t SEC_TO_MSEC = 1000;
37 const std::string POWER_SUPPLY = "SUBSYSTEM=power_supply";
38 }
39 static sptr<IBatteryCallback> g_callback;
40 
~BatteryThread()41 BatteryThread::~BatteryThread()
42 {
43     BATTERY_HILOGW(COMP_HDI, "enter %{public}s", __func__);
44     isRunning_ = false;
45     if (batteryThread_ != nullptr && batteryThread_->joinable()) {
46         batteryThread_->join();
47     }
48 }
49 
InitCallback(const sptr<IBatteryCallback>& callback)50 void BatteryThread::InitCallback(const sptr<IBatteryCallback>& callback)
51 {
52     g_callback = callback;
53 }
54 
OpenUeventSocket()55 int32_t BatteryThread::OpenUeventSocket()
56 {
57     int32_t bufferSize = UEVENT_BUFF_SIZE;
58     struct sockaddr_nl address = {
59         .nl_family = AF_NETLINK,
60         .nl_pid = getpid(),
61         .nl_groups = 0xffffffff
62     };
63 
64     int32_t fd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
65     if (fd == INVALID_FD) {
66         BATTERY_HILOGE(COMP_HDI, "open uevent socket failed, fd is invalid");
67         return INVALID_FD;
68     }
69 
70     int32_t ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
71     if (ret < 0) {
72         BATTERY_HILOGE(COMP_HDI, "set socket opt failed, ret: %{public}d", ret);
73         close(fd);
74         return INVALID_FD;
75     }
76 
77     ret = bind(fd, reinterpret_cast<const struct sockaddr*>(&address), sizeof(struct sockaddr_nl));
78     if (ret < 0) {
79         BATTERY_HILOGE(COMP_HDI, "bind socket address failed, ret: %{public}d", ret);
80         close(fd);
81         return INVALID_FD;
82     }
83     return fd;
84 }
85 
RegisterCallback(int32_t fd, EventType et)86 int32_t BatteryThread::RegisterCallback(int32_t fd, EventType et)
87 {
88     struct epoll_event ev = {0};
89 
90     ev.events = EPOLLIN;
91     if (et == EVENT_TIMER_FD) {
92         ev.events |= EPOLLWAKEUP;
93     }
94 
95     ev.data.ptr = reinterpret_cast<void*>(this);
96     ev.data.fd = fd;
97     if (epoll_ctl(epFd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
98         BATTERY_HILOGE(COMP_HDI, "epoll_ctl failed, error num =%{public}d", errno);
99         return HDF_FAILURE;
100     }
101     return HDF_SUCCESS;
102 }
103 
UpdateEpollInterval(const int32_t chargeState)104 void BatteryThread::UpdateEpollInterval(const int32_t chargeState)
105 {
106     if ((chargeState != PowerSupplyProvider::CHARGE_STATE_NONE) &&
107         (chargeState != PowerSupplyProvider::CHARGE_STATE_RESERVED)) {
108         epollInterval_ = TIMER_FAST_SEC * SEC_TO_MSEC;
109     } else {
110         epollInterval_ = -1;
111     }
112 }
113 
InitUevent()114 int32_t BatteryThread::InitUevent()
115 {
116     auto& batteryConfig = BatteryConfig::GetInstance();
117     batteryConfig.ParseConfig();
118     powerUeventMap_ = batteryConfig.GetUeventList();
119 
120     ueventFd_ = OpenUeventSocket();
121     if (ueventFd_ == INVALID_FD) {
122         BATTERY_HILOGE(COMP_HDI, "open uevent socket failed, fd is invalid");
123         return HDF_ERR_BAD_FD;
124     }
125 
126     fcntl(ueventFd_, F_SETFL, O_NONBLOCK);
127     callbacks_.insert(std::make_pair(ueventFd_, &BatteryThread::UeventCallback));
128 
129     if (RegisterCallback(ueventFd_, EVENT_UEVENT_FD)) {
130         BATTERY_HILOGE(COMP_HDI, "register Uevent event failed");
131         return HDF_ERR_BAD_FD;
132     }
133     return HDF_SUCCESS;
134 }
135 
Init([[maybe_unused]] void* service)136 int32_t BatteryThread::Init([[maybe_unused]] void* service)
137 {
138     provider_ = std::make_unique<PowerSupplyProvider>();
139     if (provider_ != nullptr) {
140         provider_->InitBatteryPath();
141         provider_->InitPowerSupplySysfs();
142     }
143 
144     epFd_ = epoll_create1(EPOLL_CLOEXEC);
145     if (epFd_ == INVALID_FD) {
146         BATTERY_HILOGE(COMP_HDI, "epoll create failed, epFd_ is invalid");
147         return HDF_ERR_BAD_FD;
148     }
149 
150     InitUevent();
151 
152     return HDF_SUCCESS;
153 }
154 
UpdateWaitInterval()155 int32_t BatteryThread::UpdateWaitInterval()
156 {
157     return HDF_FAILURE;
158 }
159 
UeventCallback(void* service)160 void BatteryThread::UeventCallback(void* service)
161 {
162     char msg[UEVENT_MSG_LEN + UEVENT_RESERVED_SIZE] = { 0 };
163 
164     ssize_t len = recv(ueventFd_, msg, UEVENT_MSG_LEN, 0);
165     if (len < 0 || len >= UEVENT_MSG_LEN) {
166         BATTERY_HILOGI(COMP_HDI, "recv return msg is invalid, len: %{public}zd", len);
167         return;
168     }
169 
170     // msg separator
171     msg[len] = '\0';
172     msg[len + 1] = '\0';
173     std::string powerUevent;
174     if (!MatchPowerUevent(msg, powerUevent)) {
175         return;
176     }
177     BATTERY_HILOGD(FEATURE_BATT_INFO, "PowerUevent msg:%{public}s", powerUevent.c_str());
178     UpdateBatteryInfo(service, powerUevent);
179 }
180 
UpdateBatteryInfo(void* service, const std::string& powerUevent)181 void BatteryThread::UpdateBatteryInfo(void* service, const std::string& powerUevent)
182 {
183     BatteryInfo event = {};
184     std::unique_ptr<BatterydInfo> batteryInfo = std::make_unique<BatterydInfo>();
185     if (batteryInfo == nullptr) {
186         BATTERY_HILOGE(FEATURE_BATT_INFO, "make_unique BatterydInfo error");
187         return;
188     }
189 
190     provider_->UpdateInfoByReadSysFile(batteryInfo.get());
191     event.capacity = batteryInfo->capacity_;
192     event.voltage= batteryInfo->voltage_;
193     event.temperature = batteryInfo->temperature_;
194     event.healthState = batteryInfo->healthState_;
195     event.pluggedType = batteryInfo->pluggedType_;
196     event.pluggedMaxCurrent = batteryInfo->pluggedMaxCurrent_;
197     event.pluggedMaxVoltage = batteryInfo->pluggedMaxVoltage_;
198     event.chargeState = batteryInfo->chargeState_;
199     event.chargeCounter = batteryInfo->chargeCounter_;
200     event.present = batteryInfo->present_;
201     event.technology = batteryInfo->technology_;
202     event.curNow = batteryInfo->curNow_;
203     event.remainEnergy = batteryInfo->remainEnergy_;
204     event.totalEnergy = batteryInfo->totalEnergy_;
205     event.uevent = powerUevent;
206 
207     if (g_callback != nullptr) {
208         g_callback->Update(event);
209     } else {
210         BATTERY_HILOGI(FEATURE_BATT_INFO, "g_callback is nullptr");
211     }
212 
213     BATTERY_HILOGI(COMP_DRV, "battery c=%{public}d, v=%{public}d, c=%{public}d, t=%{public}d, "
214         "h=%{public}d, pt=%{public}d, cs=%{public}d, pmc=%{public}d, "
215         "pmv=%{public}d, cc=%{public}d, p=%{public}d, re=%{public}d, te=%{public}d",
216         event.capacity, event.voltage, event.curNow, event.temperature, event.healthState,
217         event.pluggedType, event.chargeState, event.pluggedMaxCurrent, event.pluggedMaxVoltage,
218         event.chargeCounter, event.present, event.remainEnergy, event.totalEnergy);
219 }
220 
MatchPowerUevent(const char* msg, std::string& powerUevent)221 bool BatteryThread::MatchPowerUevent(const char* msg, std::string& powerUevent)
222 {
223     while (*msg) {
224         if (!strcmp(msg, POWER_SUPPLY.c_str())) {
225             powerUevent = POWER_SUPPLY;
226             return true;
227         }
228         if (CheckPowerUevent(msg, powerUevent)) {
229             return true;
230         }
231         while (*msg++) {} // move to next
232     }
233 
234     return false;
235 }
236 
CheckPowerUevent(const char* msg, std::string& powerUevent)237 bool BatteryThread::CheckPowerUevent(const char* msg, std::string& powerUevent)
238 {
239     auto iter = powerUeventMap_.find(msg);
240     if (iter != powerUeventMap_.end()) {
241         while (*msg++) {}
242         for (auto& uevent : iter->second) {
243             std::regex r(uevent.first);
244             if (std::regex_match(msg, r)) {
245                 powerUevent = msg;
246                 powerUevent += "$" + uevent.second;
247                 return true;
248             }
249         }
250     }
251     return false;
252 }
253 
LoopingThreadEntry(void* arg)254 void BatteryThread::LoopingThreadEntry(void* arg)
255 {
256     int32_t nevents = 0;
257     size_t size = callbacks_.size();
258     struct epoll_event events[size];
259 
260     while (isRunning_) {
261         if (!nevents) {
262             CycleMatters();
263         }
264 
265         HandleStates();
266 
267         int32_t timeout = epollInterval_;
268         int32_t waitTimeout = UpdateWaitInterval();
269         if ((timeout < 0) || (waitTimeout > 0 && waitTimeout < timeout)) {
270             timeout = waitTimeout;
271         }
272 
273         nevents = epoll_wait(epFd_, events, static_cast<int32_t>(size), timeout);
274         if (nevents <= 0) {
275             continue;
276         }
277 
278         for (int32_t n = 0; n < nevents; ++n) {
279             if (events[n].data.ptr) {
280                 auto* func = const_cast<BatteryThread*>(this);
281                 (callbacks_.find(events[n].data.fd)->second)(func, arg);
282             }
283         }
284     }
285 }
286 
StartThread(void* service)287 void BatteryThread::StartThread(void* service)
288 {
289     Init(service);
290     Run(service);
291 }
292 
Run(void* service)293 void BatteryThread::Run(void* service)
294 {
295     batteryThread_ = std::make_unique<std::thread>([this, service] { this->LoopingThreadEntry(service); });
296     pthread_setname_np(batteryThread_->native_handle(), "battery_thread");
297 }
298 } // namespace V2_0
299 } // namespace Battery
300 } // namespace HDI
301 } // namespace OHOS
302