blob: e7fb7e5b886ae4d5d5a89580522408b03eeb6093 [file] [log] [blame]
Ram Chandrasekar14a48f52021-04-06 13:25:32 -07001/*
2 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
Manaf Meethalavalappu Pallikunhiab1e3c52022-05-14 01:53:29 +05303 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
Ram Chandrasekar14a48f52021-04-06 13:25:32 -07004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution.
14 * * Neither the name of The Linux Foundation nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 *
19 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
29 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
Bavyasritha Alahari0a344f42023-04-26 17:16:51 -070032 /* Changes from Qualcomm Innovation Center are provided under the following license:
33
34Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
35SPDX-License-Identifier: BSD-3-Clause-Clear */
36
Ram Chandrasekar14a48f52021-04-06 13:25:32 -070037#include <unistd.h>
38#include <linux/thermal.h>
39#include <android-base/logging.h>
40#include <android-base/properties.h>
41#include <android-base/stringprintf.h>
42
43#include "thermalMonitorNetlink.h"
44
Bavyasritha Alahari0a344f42023-04-26 17:16:51 -070045namespace aidl {
Ram Chandrasekar14a48f52021-04-06 13:25:32 -070046namespace android {
47namespace hardware {
48namespace thermal {
Ram Chandrasekar14a48f52021-04-06 13:25:32 -070049
50using pollCB = std::function<bool()>;
51using familyCB = std::function<int(struct nl_msg *, void *)>;
52
53void thermal_listen(struct nl_sock *soc, const pollCB &stopCB)
54{
55 while (!stopCB())
56 nl_recvmsgs_default(soc);
57
58 LOG(INFO) << "thermal_listen_event Exit" << std::endl;
59 return;
60}
61
62int thermal_event_cb(struct nl_msg *n, void *data)
63{
64 ThermalMonitor *t = (ThermalMonitor *)data;
65 return t->event_parse(n, NULL);
66}
67
68int thermal_sample_cb(struct nl_msg *n, void *data)
69{
70 ThermalMonitor *t = (ThermalMonitor *)data;
71 return t->sample_parse(n, NULL);
72}
73
74int thermal_family_cb(struct nl_msg *n, void *data)
75{
76 ThermalMonitor *t = (ThermalMonitor *)data;
77 return t->family_msg_cb(n, NULL);
78}
79
80ThermalMonitor::ThermalMonitor(const eventMonitorCB &inp_event_cb,
Manaf Meethalavalappu Pallikunhiab1e3c52022-05-14 01:53:29 +053081 const eventMonitorCB &inp_sample_cb,
82 const eventCreateMonitorCB &inp_event_create_cb):
Ram Chandrasekar14a48f52021-04-06 13:25:32 -070083 event_group(-1),
84 sample_group(-1),
85 event_cb(inp_event_cb),
Manaf Meethalavalappu Pallikunhiab1e3c52022-05-14 01:53:29 +053086 sample_cb(inp_sample_cb),
87 event_create_cb(inp_event_create_cb)
Ram Chandrasekar14a48f52021-04-06 13:25:32 -070088{
89 monitor_shutdown = false;
90}
91
92ThermalMonitor::~ThermalMonitor()
93{
94 monitor_shutdown = true;
95 event_th.join();
96 sample_th.join();
97 if (sample_soc)
98 nl_socket_free(sample_soc);
99 if (event_soc)
100 nl_socket_free(event_soc);
101}
102
103int ThermalMonitor::event_parse(struct nl_msg *n, void *data)
104{
105 struct nlmsghdr *nl_hdr = nlmsg_hdr(n);
106 struct genlmsghdr *hdr = genlmsg_hdr(nl_hdr);
107 struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
108 int tzn = -1, trip = -1;
Manaf Meethalavalappu Pallikunhiab1e3c52022-05-14 01:53:29 +0530109 const char *tz_name = "";
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700110
111 genlmsg_parse(nl_hdr, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
112
113 switch (hdr->cmd) {
114 case THERMAL_GENL_EVENT_TZ_TRIP_UP:
115 case THERMAL_GENL_EVENT_TZ_TRIP_DOWN:
116 if (attrs[THERMAL_GENL_ATTR_TZ_ID])
117 tzn = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
118
119 if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
120 trip = nla_get_u32(
121 attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
Manaf Meethalavalappu Pallikunhiab1e3c52022-05-14 01:53:29 +0530122 LOG(DEBUG) << "thermal_nl_event: TZ:" << tzn << " Trip:"
123 << trip << "event:" << (int)hdr->cmd << std::endl;
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700124 event_cb(tzn, trip);
125 break;
Manaf Meethalavalappu Pallikunhiab1e3c52022-05-14 01:53:29 +0530126 case THERMAL_GENL_EVENT_TZ_CREATE:
127 if (attrs[THERMAL_GENL_ATTR_TZ_ID])
128 tzn = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
129 if (attrs[THERMAL_GENL_ATTR_TZ_NAME])
130 tz_name = nla_get_string(attrs[THERMAL_GENL_ATTR_TZ_NAME]);
131 LOG(DEBUG) << "thermal_nl_event: TZ_CREATE: TZ:" << tzn << " TZ_NAME:"
132 << tz_name << "event:" << (int)hdr->cmd << std::endl;
133 event_create_cb(tzn, tz_name);
134 break;
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700135 }
136
137 return 0;
138
139}
140
141int ThermalMonitor::sample_parse(struct nl_msg *n, void *data)
142{
143 struct nlmsghdr *nl_hdr = nlmsg_hdr(n);
144 struct genlmsghdr *hdr = genlmsg_hdr(nl_hdr);
145 struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
146 int tzn = -1, temp = -1;
147
148 genlmsg_parse(nl_hdr, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
149
150 switch (hdr->cmd) {
151 case THERMAL_GENL_SAMPLING_TEMP:
152 if (attrs[THERMAL_GENL_ATTR_TZ_ID])
153 tzn = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
154
155 if (attrs[THERMAL_GENL_ATTR_TZ_TEMP])
156 temp = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]);
157
Rashid Zafare10611c2023-06-21 12:09:36 -0700158 LOG(DEBUG) << "thermal_sample_event: TZ:" << tzn << " temp:"
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700159 << temp << std::endl;
160 sample_cb(tzn, temp);
161 break;
162 }
163
164 return 0;
165
166}
167
168int ThermalMonitor::family_msg_cb(struct nl_msg *msg, void *data)
169{
170 struct nlattr *tb[CTRL_ATTR_MAX + 1];
171 struct genlmsghdr *gnlh = genlmsg_hdr(nlmsg_hdr(msg));
172 struct nlattr *mc_group;
173 int rem_mcgrp;
174
175 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
176 genlmsg_attrlen(gnlh, 0), NULL);
177
178 if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
179 LOG(ERROR) << "Multicast group not available\n";
180 return -1;
181 }
182
183 nla_for_each_nested(mc_group, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
184
185 struct nlattr *nl_group[CTRL_ATTR_MCAST_GRP_MAX + 1];
186
187 nla_parse(nl_group, CTRL_ATTR_MCAST_GRP_MAX,
188 (struct nlattr *)nla_data(mc_group),
189 nla_len(mc_group), NULL);
190
191 if (!nl_group[CTRL_ATTR_MCAST_GRP_NAME] ||
192 !nl_group[CTRL_ATTR_MCAST_GRP_ID])
193 continue;
194 std::string family((char *)nla_data(
195 nl_group[CTRL_ATTR_MCAST_GRP_NAME]));
196 LOG(DEBUG) << "Family:" << family << std::endl;
197 if (family == THERMAL_GENL_EVENT_GROUP_NAME)
198 event_group = nla_get_u32(
199 nl_group[CTRL_ATTR_MCAST_GRP_ID]);
200
201 if (family == THERMAL_GENL_SAMPLING_GROUP_NAME)
202 sample_group = nla_get_u32(
203 nl_group[CTRL_ATTR_MCAST_GRP_ID]);
204 }
205
206 return 0;
207}
208
209int ThermalMonitor::send_nl_msg(struct nl_msg *msg)
210{
211 int ret = 0;
212
213 ret = nl_send_auto(event_soc, msg);
214 if (ret < 0) {
215 LOG(ERROR) << "Error sending NL message\n";
216 return ret;
217 }
218 nl_socket_disable_seq_check(event_soc);
219 nl_socket_modify_cb(event_soc, NL_CB_VALID, NL_CB_CUSTOM,
220 thermal_family_cb, this);
221 ret = nl_recvmsgs_default(event_soc);
222
223 return ret;
224}
225
226int ThermalMonitor::fetch_group_id(void)
227{
228 struct nl_msg *msg;
229 int ctrlid, ret = 0;
230
231 msg = nlmsg_alloc();
232 if (!msg)
233 return -1;
234
235 ctrlid = genl_ctrl_resolve(event_soc, "nlctrl");
236 genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
237
238 nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, THERMAL_GENL_FAMILY_NAME);
239 send_nl_msg(msg);
240
241 nlmsg_free(msg);
242
243 if (event_group != -1 && sample_group != -1) {
Rashid Zafare10611c2023-06-21 12:09:36 -0700244 LOG(DEBUG) << "Netlink event: " << event_group <<
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700245 " Sample:" << sample_group << std::endl;
246 ret = nl_socket_add_membership(event_soc, event_group);
247 if (ret) {
Rashid Zafare10611c2023-06-21 12:09:36 -0700248 LOG(ERROR) << "Netlink event Socket membership add error\n";
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700249 return ret;
250 }
251
252 ret = nl_socket_add_membership(sample_soc, sample_group);
253 if (ret) {
Rashid Zafare10611c2023-06-21 12:09:36 -0700254 LOG(ERROR) << "Netlink sample Socket membership add error\n";
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700255 return ret;
256 }
257 }
258 return 0;
259}
260
261void ThermalMonitor::start()
262{
263 struct nl_msg *msg;
264
265 event_soc = nl_socket_alloc();
266 if (!event_soc) {
Rashid Zafare10611c2023-06-21 12:09:36 -0700267 LOG(ERROR) << "Netlink Event socket alloc failed\n";
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700268 return;
269 }
270
271 if (genl_connect(event_soc)) {
Rashid Zafare10611c2023-06-21 12:09:36 -0700272 LOG(ERROR) << "Netlink Event socket connect failed\n";
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700273 nl_socket_free(event_soc);
274 event_soc = nullptr;
275 return;
276 }
Rashid Zafare10611c2023-06-21 12:09:36 -0700277
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700278 sample_soc = nl_socket_alloc();
279 if (!sample_soc) {
Rashid Zafare10611c2023-06-21 12:09:36 -0700280 LOG(ERROR) << "Netlink Sample socket alloc failed\n";
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700281 nl_socket_free(event_soc);
282 event_soc = nullptr;
283 return;
284 }
285
286 if (genl_connect(sample_soc)) {
Rashid Zafare10611c2023-06-21 12:09:36 -0700287 LOG(ERROR) << "Netlink Sample socket connect failed\n";
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700288 nl_socket_free(sample_soc);
289 nl_socket_free(event_soc);
290 event_soc = nullptr;
291 sample_soc = nullptr;
292 return;
293 }
294 if (fetch_group_id())
295 return;
Rashid Zafare10611c2023-06-21 12:09:36 -0700296 LOG(DEBUG) << "Netlink connection established.\n";
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700297 nl_socket_disable_seq_check(sample_soc);
298 nl_socket_modify_cb(sample_soc, NL_CB_VALID, NL_CB_CUSTOM,
299 thermal_sample_cb, this);
300 nl_socket_disable_seq_check(event_soc);
301 nl_socket_modify_cb(event_soc, NL_CB_VALID, NL_CB_CUSTOM,
302 thermal_event_cb, this);
303 event_th = std::thread(thermal_listen, event_soc,
304 std::bind(&ThermalMonitor::stopPolling, this));
305
306 sample_th = std::thread(thermal_listen, sample_soc,
307 std::bind(&ThermalMonitor::stopPolling, this));
308}
309
Ram Chandrasekar14a48f52021-04-06 13:25:32 -0700310} // namespace thermal
311} // namespace hardware
312} // namespace android
Bavyasritha Alahari0a344f42023-04-26 17:16:51 -0700313} // namespace aidl