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
26namespace OHOS {
27namespace PowerMgr {
28namespace {
29constexpr int32_t UEVENT_BUFF_SIZE = (64 * 1024);
30constexpr int32_t UEVENT_RESERVED_SIZE = 2;
31constexpr int32_t UEVENT_MSG_LEN = (2 * 1024);
32constexpr int32_t TIMER_FAST_SEC = 2;
33constexpr int32_t SEC_TO_MSEC = 1000;
34const std::string POWER_SUPPLY = "SUBSYSTEM=power_supply";
35}
36
37int32_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
68int32_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
86void 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
96int32_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
114int32_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
133int32_t BatteryThread::UpdateWaitInterval()
134{
135    return HDF_FAILURE;
136}
137
138void 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
157void BatteryThread::UpdateBatteryInfo(void* service) {}
158
159bool 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
171int32_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
204void BatteryThread::StartThread(void* service)
205{
206    Init(service);
207    Run(service);
208}
209
210void BatteryThread::Run(void* service) {}
211} // namespace PowerMgr
212} // namespace OHOS
213