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#ifndef GNU_SOURCE
17#define GNU_SOURCE
18#endif
19#include <cerrno>
20#include <cstdio>
21#include <unistd.h>
22#include <sys/ioctl.h>
23#include <fcntl.h>
24#include <concurrent_task_log.h>
25
26#include "qos_interface.h"
27
28static int TrivalOpenRtgNode(void)
29{
30    char fileName[] = "/proc/self/sched_rtg_ctrl";
31    int fd = open(fileName, O_RDWR);
32    if (fd < 0) {
33        CONCUR_LOGE("[Interface] task %{public}d belong to user %{public}d open rtg node failed, errno = %{public}d",
34            getpid(), getuid(), errno);
35    }
36    return fd;
37}
38
39static int TrivalOpenAuthCtrlNode(void)
40{
41    char fileName[] = "/dev/auth_ctrl";
42    int fd = open(fileName, O_RDWR);
43    if (fd < 0) {
44        CONCUR_LOGE("[Interface] task %{public}d belong to user %{public}d open auth node failed, errno = %{public}d",
45            getpid(), getuid(), errno);
46    }
47    return fd;
48}
49
50static int TrivalOpenQosCtrlNode(void)
51{
52    char fileName[] = "/proc/thread-self/sched_qos_ctrl";
53    int fd = open(fileName, O_RDWR);
54    if (fd < 0) {
55        CONCUR_LOGE("[Interface] task %{public}d belong to user %{public}d open qos node failed, errno = %{public}d",
56            getpid(), getuid(), errno);
57    }
58    return fd;
59}
60
61int EnableRtg(bool flag)
62{
63    struct RtgEnableData enableData;
64    char configStr[] = "load_freq_switch:1;sched_cycle:1;frame_max_util:1024";
65    int ret;
66
67    enableData.enable = flag;
68    enableData.len = sizeof(configStr);
69    enableData.data = configStr;
70    int fd = TrivalOpenRtgNode();
71    if (fd < 0) {
72        return fd;
73    }
74
75    ret = ioctl(fd, CMD_ID_SET_ENABLE, &enableData);
76    if (ret < 0) {
77        printf("set rtg config enable failed.\n");
78    }
79
80    close(fd);
81
82    return 0;
83};
84
85int AuthEnable(unsigned int pid, unsigned int uaFlag, unsigned int status)
86{
87    struct AuthCtrlData data;
88    int fd;
89    int ret;
90
91    fd = TrivalOpenAuthCtrlNode();
92    if (fd < 0) {
93        return fd;
94    }
95
96    data.pid = pid;
97    data.rtgUaFlag = uaFlag;
98    data.qosUaFlag = AF_QOS_DELEGATED;
99    data.status = status;
100    data.type = static_cast<unsigned int>(AuthManipulateType::AUTH_ENABLE);
101
102    ret = ioctl(fd, BASIC_AUTH_CTRL_OPERATION, &data);
103#ifdef QOS_DEBUG
104    if (ret < 0) {
105        printf("auth enable failed for pid %u with status %u\n", pid, status);
106    }
107#endif
108    close(fd);
109    return ret;
110}
111
112int AuthSwitch(unsigned int pid, unsigned int rtgFlag, unsigned int qosFlag, unsigned int status)
113{
114    struct AuthCtrlData data;
115    int fd;
116    int ret;
117
118    fd = TrivalOpenAuthCtrlNode();
119    if (fd < 0) {
120        return fd;
121    }
122
123    data.pid = pid;
124    data.rtgUaFlag = rtgFlag;
125    data.qosUaFlag = qosFlag;
126    data.status = status;
127    data.type = static_cast<unsigned int>(AuthManipulateType::AUTH_SWITCH);
128
129    ret = ioctl(fd, BASIC_AUTH_CTRL_OPERATION, &data);
130#ifdef QOS_DEBUG
131    if (ret < 0) {
132        printf("auth switch failed for pid %u with status %u\n", pid, status);
133    }
134#endif
135    close(fd);
136    return ret;
137}
138
139int AuthDelete(unsigned int pid)
140{
141    struct AuthCtrlData data;
142    int fd;
143    int ret;
144
145    fd = TrivalOpenAuthCtrlNode();
146    if (fd < 0) {
147        return fd;
148    }
149
150    data.pid = pid;
151    data.type = static_cast<unsigned int>(AuthManipulateType::AUTH_DELETE);
152
153    ret = ioctl(fd, BASIC_AUTH_CTRL_OPERATION, &data);
154#ifdef QOS_DEBUG
155    if (ret < 0) {
156        printf("auth delete failed for pid %u\n", pid);
157    }
158#endif
159    close(fd);
160    return ret;
161}
162
163int AuthPause(unsigned int pid)
164{
165    struct AuthCtrlData data;
166    int fd;
167    int ret;
168
169    fd = TrivalOpenAuthCtrlNode();
170    if (fd < 0) {
171        return fd;
172    }
173
174    data.pid = pid;
175    data.type = static_cast<unsigned int>(AuthManipulateType::AUTH_SWITCH);
176    data.rtgUaFlag = 0;
177    data.qosUaFlag = AF_QOS_DELEGATED;
178    data.status = static_cast<unsigned int>(AuthStatus::AUTH_STATUS_BACKGROUND);
179
180    ret = ioctl(fd, BASIC_AUTH_CTRL_OPERATION, &data);
181#ifdef QOS_DEBUG
182    if (ret < 0) {
183        printf("auth pause failed for pid %u\n", pid);
184    }
185#endif
186    close(fd);
187    return ret;
188}
189
190int AuthGet(unsigned int pid)
191{
192    struct AuthCtrlData data;
193    int fd;
194    int ret;
195
196    fd = TrivalOpenAuthCtrlNode();
197    if (fd < 0) {
198        return fd;
199    }
200
201    data.pid = pid;
202    data.type = static_cast<unsigned int>(AuthManipulateType::AUTH_GET);
203
204    ret = ioctl(fd, BASIC_AUTH_CTRL_OPERATION, &data);
205    if (ret < 0) {
206        close(fd);
207        return ret;
208    }
209    close(fd);
210
211    return static_cast<int>(data.status);
212}
213
214int AuthEnhance(unsigned int pid, bool enhanceStatus)
215{
216    int ret = 0;
217#ifdef QOS_EXT_ENABLE
218    struct AuthCtrlData data;
219    int fd = TrivalOpenAuthCtrlNode();
220    if (fd < 0) {
221        return fd;
222    }
223
224    data.pid = pid;
225    data.enhanceStatus = enhanceStatus;
226    ret = ioctl(fd, ENHANCE_AUTH_CTRL_OPERATION, &data);
227    close(fd);
228#endif
229    return ret;
230}
231
232int QosApply(unsigned int level)
233{
234    int tid = gettid();
235    int ret;
236
237    ret = QosApplyForOther(level, tid);
238    return ret;
239}
240
241int QosApplyForOther(unsigned int level, int tid)
242{
243    struct QosCtrlData data;
244    int fd;
245
246    int ret;
247
248    fd = TrivalOpenQosCtrlNode();
249    if (fd < 0) {
250        return fd;
251    }
252
253    data.level = level;
254    data.type = static_cast<unsigned int>(QosManipulateType::QOS_APPLY);
255    data.pid = tid;
256
257    ret = ioctl(fd, QOS_CTRL_BASIC_OPERATION, &data);
258    if (ret < 0) {
259        CONCUR_LOGE("[Interface] task %{public}d apply qos failed, errno = %{public}d", tid, errno);
260    }
261    close(fd);
262    return ret;
263}
264
265int QosLeave(void)
266{
267    struct QosCtrlData data;
268    int fd;
269    int ret;
270
271    fd = TrivalOpenQosCtrlNode();
272    if (fd < 0) {
273        return fd;
274    }
275
276    data.type = static_cast<unsigned int>(QosManipulateType::QOS_LEAVE);
277    data.pid = gettid();
278
279    ret = ioctl(fd, QOS_CTRL_BASIC_OPERATION, &data);
280    if (ret < 0) {
281        CONCUR_LOGE("[Interface] task %{public}d leave qos failed, errno = %{public}d", gettid(), errno);
282    }
283    close(fd);
284    return ret;
285}
286
287int QosLeaveForOther(int tid)
288{
289    struct QosCtrlData data;
290    int fd;
291    int ret;
292
293    fd = TrivalOpenQosCtrlNode();
294    if (fd < 0) {
295        return fd;
296    }
297
298    data.type = static_cast<unsigned int>(QosManipulateType::QOS_LEAVE);
299    data.pid = tid;
300
301    ret = ioctl(fd, QOS_CTRL_BASIC_OPERATION, &data);
302    if (ret < 0) {
303        CONCUR_LOGE("[Interface] task %{public}d leave qos failed, errno = %{public}d", tid, errno);
304    }
305    close(fd);
306    return ret;
307}
308
309int QosPolicySet(const struct QosPolicyDatas *policyDatas)
310{
311    int fd;
312    int ret;
313
314    fd = TrivalOpenQosCtrlNode();
315    if (fd < 0) {
316        return fd;
317    }
318
319    ret = ioctl(fd, QOS_CTRL_POLICY_OPERATION, policyDatas);
320    if (ret < 0) {
321        CONCUR_LOGE("[Interface] set qos policy failed, errno = %{public}d", errno);
322    }
323    close(fd);
324    return ret;
325}
326
327int QosGet(int &level)
328{
329    int tid = gettid();
330    return QosGetForOther(tid, level);
331}
332
333int QosGetForOther(int tid, int &level)
334{
335    int fd;
336    int ret = 0;
337
338    fd = TrivalOpenQosCtrlNode();
339    if (fd < 0) {
340        return fd;
341    }
342
343    struct QosCtrlData data;
344    data.type = static_cast<unsigned int>(QosManipulateType::QOS_GET);
345    data.pid = tid;
346    data.qos = -1;
347
348    ret = ioctl(fd, QOS_CTRL_BASIC_OPERATION, &data);
349    if (ret < 0) {
350        CONCUR_LOGE("[Interface] task %{public}d get qos failed, errno = %{public}d", tid, errno);
351    }
352    level = data.qos;
353
354    close(fd);
355    return ret;
356}