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