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