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 "rtg_interface.h"
17#include <sys/ioctl.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <securec.h>
21#include <cstdio>
22#include <string>
23#include <vector>
24#include <cerrno>
25#include "bits/ioctl.h"
26#include "rme_log_domain.h"
27
28#undef LOG_TAG
29#define LOG_TAG "rtg_interface"
30
31namespace OHOS {
32namespace RME {
33namespace {
34constexpr size_t MAX_LENGTH = 100;
35}
36
37const char RTG_SCHED_IPC_MAGIC = 0xAB;
38static int g_fd = -1;
39
40#define CMD_ID_SET_ENABLE \
41    _IOWR(RTG_SCHED_IPC_MAGIC, SET_ENABLE, struct rtg_enable_data)
42#define CMD_ID_SET_RTG \
43    _IOWR(RTG_SCHED_IPC_MAGIC, SET_RTG, struct rtg_str_data)
44#define CMD_ID_SET_CONFIG \
45    _IOWR(RTG_SCHED_IPC_MAGIC, SET_CONFIG, struct rtg_str_data)
46#define CMD_ID_SET_RTG_ATTR \
47    _IOWR(RTG_SCHED_IPC_MAGIC, SET_RTG_ATTR, struct rtg_str_data)
48#define CMD_ID_BEGIN_FRAME_FREQ \
49    _IOWR(RTG_SCHED_IPC_MAGIC, BEGIN_FRAME_FREQ, struct proc_state_data)
50#define CMD_ID_END_FRAME_FREQ \
51    _IOWR(RTG_SCHED_IPC_MAGIC, END_FRAME_FREQ, struct proc_state_data)
52#define CMD_ID_END_SCENE \
53    _IOWR(RTG_SCHED_IPC_MAGIC, END_SCENE, struct proc_state_data)
54#define CMD_ID_SET_MIN_UTIL \
55    _IOWR(RTG_SCHED_IPC_MAGIC, SET_MIN_UTIL, struct proc_state_data)
56#define CMD_ID_SET_MAX_UTIL \
57    _IOWR(RTG_SCHED_IPC_MAGIC, SET_MAX_UTIL, struct proc_state_data)
58#define CMD_ID_SET_MARGIN \
59    _IOWR(RTG_SCHED_IPC_MAGIC, SET_MARGIN, struct proc_state_data)
60#define CMD_ID_SEARCH_RTG \
61    _IOWR(RTG_SCHED_IPC_MAGIC, SEARCH_RTG, struct proc_state_data)
62#define CMD_ID_GET_ENABLE \
63    _IOWR(RTG_SCHED_IPC_MAGIC, GET_ENABLE, struct rtg_enable_data)
64
65__attribute__((constructor)) void BasicOpenRtgNode()
66{
67    char fileName[] = "/proc/self/sched_rtg_ctrl";
68    g_fd = open(fileName, O_RDWR);
69    if (g_fd < 0) {
70        RME_LOGI("rtg Open fail, errno = %{public}d(%{public}s), dev = %{public}s", errno, strerror(errno), fileName);
71        return;
72    }
73    RME_LOGI("rtg Open success");
74    return;
75}
76
77__attribute__((destructor)) void BasicCloseRtgNode()
78{
79    if (g_fd < 0) {
80        return;
81    }
82    RME_LOGI("rtg Close g_fd ret is %{public}d", g_fd);
83    close(g_fd);
84    g_fd = -1;
85}
86
87int EnableRtg(bool flag)
88{
89    int ret = 0;
90    struct rtg_enable_data enableData;
91    char configStr[] = "load_freq_switch:1;sched_cycle:1";
92    enableData.enable = flag;
93    enableData.len = sizeof(configStr);
94    enableData.data = configStr;
95    if (g_fd < 0) {
96        return g_fd;
97    }
98    ret = ioctl(g_fd, CMD_ID_SET_ENABLE, &enableData);
99    if (ret != 0) {
100        RME_LOGE("set rtg config to [%{public}d] failed, ret = %{public}d, errno = %{public}d (%{public}s)",
101            flag,
102            ret,
103            errno,
104            strerror(errno));
105    } else {
106        RME_LOGI("set rtg config to [%{public}d] success.", flag);
107    }
108    return 0;
109};
110
111int AddThreadToRtg(int tid, int grpId, int prioType, [[maybe_unused]] bool isBlue)
112{
113    if (g_fd < 0) {
114        return g_fd;
115    }
116    struct rtg_grp_data grp_data;
117    int ret;
118    (void)memset_s(&grp_data, sizeof(struct rtg_grp_data), 0, sizeof(struct rtg_grp_data));
119    grp_data.tid_num = 1;
120    grp_data.tids[0] = tid;
121    grp_data.grp_id = grpId;
122    grp_data.rtg_cmd = CMD_ADD_RTG_THREAD;
123    grp_data.prio_type = prioType;
124    ret = ioctl(g_fd, CMD_ID_SET_RTG, &grp_data);
125    if (ret != 0) {
126        RME_LOGE("add thread to rtg failed, grpId = %{public}d, ret = %{public}d, errno = %{public}d (%{public}s)",
127            grpId,
128            ret,
129            errno,
130            strerror(errno));
131    } else {
132        RME_LOGI("add thread to rtg success");
133    }
134    return ret;
135}
136
137int AddThreadsToRtg(vector<int> tids, int grpId, int prioType, [[maybe_unused]] bool isBlue)
138{
139    struct rtg_grp_data grp_data;
140    int ret;
141    if (g_fd < 0) {
142        return g_fd;
143    }
144    (void)memset_s(&grp_data, sizeof(struct rtg_grp_data), 0, sizeof(struct rtg_grp_data));
145    int num = static_cast<int>(tids.size());
146    if (num > MAX_TID_NUM) {
147        return -1;
148    }
149    grp_data.tid_num = num;
150    grp_data.grp_id = grpId;
151    grp_data.rtg_cmd = CMD_ADD_RTG_THREAD;
152    grp_data.prio_type = prioType;
153    for (int i = 0; i < num; i++) {
154        if (tids[i] < 0) {
155            return -1;
156        }
157        grp_data.tids[i] = tids[i];
158    }
159    ret = ioctl(g_fd, CMD_ID_SET_RTG, &grp_data);
160    if (ret == 0) {
161        RME_LOGI("add rtg grp success");
162    } else {
163        RME_LOGE("add thread to rtg failed, grpId = %{public}d, ret = %{public}d, errno = %{public}d (%{public}s)",
164            grpId,
165            ret,
166            errno,
167            strerror(errno));
168    }
169    return ret;
170};
171
172int RemoveRtgThread(int tid, [[maybe_unused]] bool isBlue)
173{
174    if (g_fd < 0) {
175        return g_fd;
176    }
177    struct rtg_grp_data grp_data;
178    int ret;
179    (void)memset_s(&grp_data, sizeof(struct rtg_grp_data), 0, sizeof(struct rtg_grp_data));
180    grp_data.tid_num = 1;
181    grp_data.tids[0] = tid;
182    grp_data.rtg_cmd = CMD_REMOVE_RTG_THREAD;
183    ret = ioctl(g_fd, CMD_ID_SET_RTG, &grp_data);
184    if (ret != 0) {
185        RME_LOGE("remove grp failed, ret = %{public}d, errno = %{public}d (%{public}s)", ret, errno, strerror(errno));
186    } else {
187        RME_LOGI("remove grp success.");
188    }
189    return ret;
190};
191
192int RemoveRtgThreads(vector<int> tids, [[maybe_unused]] bool isBlue)
193{
194    struct rtg_grp_data grp_data;
195    int ret;
196    if (g_fd < 0) {
197        return g_fd;
198    }
199    (void)memset_s(&grp_data, sizeof(struct rtg_grp_data), 0, sizeof(struct rtg_grp_data));
200    int num = static_cast<int>(tids.size());
201    if (num > MAX_TID_NUM) {
202        return -1;
203    }
204    grp_data.tid_num = num;
205    grp_data.rtg_cmd = CMD_REMOVE_RTG_THREAD;
206    for (int i = 0; i < num; i++) {
207        if (tids[i] < 0) {
208            return -1;
209        }
210        grp_data.tids[i] = tids[i];
211    }
212    ret = ioctl(g_fd, CMD_ID_SET_RTG, &grp_data);
213    if (ret < 0) {
214        RME_LOGE("remove grp threads failed, errno = %{public}d (%{public}s)", errno, strerror(errno));
215    } else {
216        RME_LOGI("remove grp threads success, get rtg id %{public}d.", ret);
217    }
218    return ret;
219}
220
221int DestroyRtgGrp(int grpId)
222{
223    if (g_fd < 0) {
224        return g_fd;
225    }
226    struct rtg_grp_data grp_data;
227    int ret;
228    (void)memset_s(&grp_data, sizeof(struct rtg_grp_data), 0, sizeof(struct rtg_grp_data));
229    grp_data.rtg_cmd = CMD_DESTROY_RTG_GRP;
230    grp_data.grp_id = grpId;
231    ret = ioctl(g_fd, CMD_ID_SET_RTG, &grp_data);
232    if (ret != 0) {
233        RME_LOGE("destroy rtg grp failed, grpId = %{public}d, ret = %{public}d, errno = %{public}d (%{public}s)",
234            grpId,
235            ret,
236            errno,
237            strerror(errno));
238    } else {
239        RME_LOGI("destroy rtg grp success, get rtg id:%{public}d, ret:%{public}d.", grpId, ret);
240    }
241    return ret;
242};
243
244int SetFrameRateAndPrioType(int rtgId, int rate, int rtgType)
245{
246    if (g_fd < 0) {
247        return g_fd;
248    }
249    int ret = 0;
250    char str_data[MAX_LENGTH] = {};
251    (void)sprintf_s(str_data, sizeof(str_data), "rtgId:%d;rate:%d;type:%d", rtgId, rate, rtgType);
252    struct rtg_str_data strData;
253    strData.len = strlen(str_data);
254    strData.data = str_data;
255
256    ret = ioctl(g_fd, CMD_ID_SET_RTG_ATTR, &strData);
257    if (ret != 0) {
258        RME_LOGE("set rtg attr failed (rtgId:%{public}d;rate:%{public}d;type:%{public}d), ret = %{public}d, errno = "
259                 "%{public}d (%{public}s)",
260            rtgId,
261            rate,
262            rtgType,
263            ret,
264            errno,
265            strerror(errno));
266    } else {
267        RME_LOGD("set rtg attr success.");
268    }
269    return ret;
270}
271
272int BeginFrameFreq(int stateParam)
273{
274    if (g_fd < 0) {
275        return g_fd;
276    }
277    int ret = 0;
278    struct proc_state_data state_data;
279    state_data.state_param = stateParam;
280
281    ret = ioctl(g_fd, CMD_ID_BEGIN_FRAME_FREQ, &state_data);
282    return ret;
283}
284
285int EndFrameFreq(int stateParam)
286{
287    if (g_fd < 0) {
288        return g_fd;
289    }
290    int ret = 0;
291    struct proc_state_data state_data;
292    state_data.state_param = stateParam;
293
294    ret = ioctl(g_fd, CMD_ID_END_FRAME_FREQ, &state_data);
295    return ret;
296}
297
298int EndScene(int grpId)
299{
300    int ret = 0;
301    if (g_fd < 0) {
302        RME_LOGE("Open fail /proc/self/sched_rtg_ctrl");
303        return g_fd;
304    }
305    struct proc_state_data state_data;
306    state_data.grp_id = grpId;
307
308    ret = ioctl(g_fd, CMD_ID_END_SCENE, &state_data);
309    if (ret == 0) {
310        RME_LOGI("set EndScene success.");
311    }
312    return ret;
313}
314
315int SetMinUtil(int stateParam)
316{
317    int ret = 0;
318    struct proc_state_data state_data;
319    state_data.state_param = stateParam;
320
321    if (g_fd < 0) {
322        return g_fd;
323    }
324    ret = ioctl(g_fd, CMD_ID_SET_MIN_UTIL, &state_data);
325    if (ret != 0) {
326        RME_LOGE("set min util failed, ret = %{public}d, errno = %{public}d (%{public}s)", ret, errno, strerror(errno));
327    } else {
328        RME_LOGI("set min util success, get ret %{public}d.", ret);
329    }
330    return ret;
331}
332
333int SetMaxUtil(int grpId, int stateParam)
334{
335    return 0;
336}
337
338int SetMargin(int stateParam)
339{
340    int ret = 0;
341    struct proc_state_data state_data;
342    state_data.state_param = stateParam;
343
344    if (g_fd < 0) {
345        return g_fd;
346    }
347    ret = ioctl(g_fd, CMD_ID_SET_MARGIN, &state_data);
348    return ret;
349}
350
351int SearchRtgForTid(int tid)
352{
353    if (g_fd < 0) {
354        return g_fd;
355    }
356    if (tid <= 0) {
357        RME_LOGI("Search tid err: invalid tid.");
358        return -1;
359    }
360    int ret = 0;
361    struct proc_state_data search_data;
362    (void)memset_s(&search_data, sizeof(struct proc_state_data), 0, sizeof(struct proc_state_data));
363    search_data.state_param = tid;
364    ret = ioctl(g_fd, CMD_ID_SEARCH_RTG, &search_data);
365    if (ret >= 0) {
366        RME_LOGD("Search tid %{public}d success with rtg_grp %{public}d", tid, ret);
367    }
368    return ret;
369}
370
371int GetRtgEnable()
372{
373    if (g_fd < 0) {
374        return g_fd;
375    }
376    int ret = 0;
377    struct rtg_enable_data enableData;
378    ret = ioctl(g_fd, CMD_ID_GET_ENABLE, &enableData);
379    if (ret < 0) {
380        RME_LOGE(
381            "get rtg enable failed, ret = %{public}d, errno = %{public}d (%{public}s)", ret, errno, strerror(errno));
382    }
383    return ret;
384}
385
386bool GetAppExpelAbility(const std::string &appBundleName)
387{
388    return false;
389}
390}  // namespace RME
391}  // namespace OHOS
392