1 /*
2 * Copyright (c) 2022-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 "battery_thread.h"
17 #include <cerrno>
18 #include <sys/epoll.h>
19 #include <sys/socket.h>
20 #include <sys/timerfd.h>
21 #include <unistd.h>
22 #include <linux/netlink.h>
23 #include "hdf_base.h"
24 #include "charger_log.h"
25
26 namespace OHOS {
27 namespace PowerMgr {
28 namespace {
29 constexpr int32_t UEVENT_BUFF_SIZE = (64 * 1024);
30 constexpr int32_t UEVENT_RESERVED_SIZE = 2;
31 constexpr int32_t UEVENT_MSG_LEN = (2 * 1024);
32 constexpr int32_t TIMER_FAST_SEC = 2;
33 constexpr int32_t SEC_TO_MSEC = 1000;
34 const std::string POWER_SUPPLY = "SUBSYSTEM=power_supply";
35 }
36
OpenUeventSocket()37 int32_t BatteryThread::OpenUeventSocket()
38 {
39 int32_t bufferSize = UEVENT_BUFF_SIZE;
40 struct sockaddr_nl address = {
41 .nl_family = AF_NETLINK,
42 .nl_pid = getpid(),
43 .nl_groups = 0xffffffff
44 };
45
46 int32_t fd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
47 if (fd == INVALID_FD) {
48 BATTERY_HILOGE(FEATURE_CHARGING, "open uevent socket failed, fd is invalid");
49 return INVALID_FD;
50 }
51
52 int32_t ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
53 if (ret < 0) {
54 BATTERY_HILOGE(FEATURE_CHARGING, "set socket opt failed, ret: %{public}d", ret);
55 close(fd);
56 return INVALID_FD;
57 }
58
59 ret = bind(fd, reinterpret_cast<const struct sockaddr*>(&address), sizeof(struct sockaddr_nl));
60 if (ret < 0) {
61 BATTERY_HILOGE(FEATURE_CHARGING, "bind socket address failed, ret: %{public}d", ret);
62 close(fd);
63 return INVALID_FD;
64 }
65 return fd;
66 }
67
RegisterCallback(int32_t fd,EventType et)68 int32_t BatteryThread::RegisterCallback(int32_t fd, EventType et)
69 {
70 struct epoll_event ev = {0};
71
72 ev.events = EPOLLIN;
73 if (et == EVENT_TIMER_FD) {
74 ev.events |= EPOLLWAKEUP;
75 }
76
77 ev.data.ptr = reinterpret_cast<void*>(this);
78 ev.data.fd = fd;
79 if (epoll_ctl(epFd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
80 BATTERY_HILOGE(FEATURE_CHARGING, "epoll_ctl failed, error num =%{public}d", errno);
81 return HDF_FAILURE;
82 }
83 return HDF_SUCCESS;
84 }
85
UpdateEpollInterval(const int32_t chargeState)86 void BatteryThread::UpdateEpollInterval(const int32_t chargeState)
87 {
88 if ((chargeState != PowerSupplyProvider::CHARGE_STATE_NONE) &&
89 (chargeState != PowerSupplyProvider::CHARGE_STATE_RESERVED)) {
90 epollInterval_ = TIMER_FAST_SEC * SEC_TO_MSEC;
91 } else {
92 epollInterval_ = -1;
93 }
94 }
95
InitUevent()96 int32_t BatteryThread::InitUevent()
97 {
98 ueventFd_ = OpenUeventSocket();
99 if (ueventFd_ == INVALID_FD) {
100 BATTERY_HILOGE(FEATURE_CHARGING, "open uevent socket failed, fd is invalid");
101 return HDF_ERR_BAD_FD;
102 }
103
104 fcntl(ueventFd_, F_SETFL, O_NONBLOCK);
105 callbacks_.insert(std::make_pair(ueventFd_, &BatteryThread::UeventCallback));
106
107 if (RegisterCallback(ueventFd_, EVENT_UEVENT_FD)) {
108 BATTERY_HILOGE(FEATURE_CHARGING, "register Uevent event failed");
109 return HDF_ERR_BAD_FD;
110 }
111 return HDF_SUCCESS;
112 }
113
Init(void * service)114 int32_t BatteryThread::Init([[maybe_unused]] void* service)
115 {
116 provider_ = std::make_unique<PowerSupplyProvider>();
117 if (provider_ != nullptr) {
118 provider_->InitBatteryPath();
119 provider_->InitPowerSupplySysfs();
120 }
121
122 epFd_ = epoll_create1(EPOLL_CLOEXEC);
123 if (epFd_ == INVALID_FD) {
124 BATTERY_HILOGE(FEATURE_CHARGING, "epoll create failed, epFd_ is invalid");
125 return HDF_ERR_BAD_FD;
126 }
127
128 InitUevent();
129
130 return HDF_SUCCESS;
131 }
132
UpdateWaitInterval()133 int32_t BatteryThread::UpdateWaitInterval()
134 {
135 return HDF_FAILURE;
136 }
137
UeventCallback(void * service)138 void BatteryThread::UeventCallback(void* service)
139 {
140 char msg[UEVENT_MSG_LEN + UEVENT_RESERVED_SIZE] = { 0 };
141
142 ssize_t len = recv(ueventFd_, msg, UEVENT_MSG_LEN, 0);
143 if (len < 0 || len >= UEVENT_MSG_LEN) {
144 BATTERY_HILOGI(FEATURE_CHARGING, "recv return msg is invalid, len: %{public}zd", len);
145 return;
146 }
147
148 // msg separator
149 msg[len] = '\0';
150 msg[len + 1] = '\0';
151 if (!IsPowerSupplyEvent(msg)) {
152 return;
153 }
154 UpdateBatteryInfo(service);
155 }
156
UpdateBatteryInfo(void * service)157 void BatteryThread::UpdateBatteryInfo(void* service) {}
158
IsPowerSupplyEvent(const char * msg)159 bool BatteryThread::IsPowerSupplyEvent(const char* msg)
160 {
161 while (*msg) {
162 if (!strcmp(msg, POWER_SUPPLY.c_str())) {
163 return true;
164 }
165 while (*msg++) {} // move to next
166 }
167
168 return false;
169 }
170
LoopingThreadEntry(void * arg)171 int32_t BatteryThread::LoopingThreadEntry(void* arg)
172 {
173 int32_t nevents = 0;
174 size_t size = callbacks_.size();
175 struct epoll_event events[size];
176
177 while (true) {
178 if (!nevents) {
179 CycleMatters();
180 }
181
182 HandleStates();
183
184 int32_t timeout = epollInterval_;
185 int32_t waitTimeout = UpdateWaitInterval();
186 if ((timeout < 0) || (waitTimeout > 0 && waitTimeout < timeout)) {
187 timeout = waitTimeout;
188 }
189
190 nevents = epoll_wait(epFd_, events, static_cast<int32_t>(size), timeout);
191 if (nevents <= 0) {
192 continue;
193 }
194
195 for (int32_t n = 0; n < nevents; ++n) {
196 if (events[n].data.ptr) {
197 auto* func = const_cast<BatteryThread*>(this);
198 (callbacks_.find(events[n].data.fd)->second)(func, arg);
199 }
200 }
201 }
202 }
203
StartThread(void * service)204 void BatteryThread::StartThread(void* service)
205 {
206 Init(service);
207 Run(service);
208 }
209
Run(void * service)210 void BatteryThread::Run(void* service) {}
211 } // namespace PowerMgr
212 } // namespace OHOS
213