Fix bugs reported by Coverity and SVACE
[platform/core/api/resource.git] / src / plugin / plugin.c
1 /* MIT License
2  *
3  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is furnished
10  * to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21  * THE SOFTWARE. */
22
23 #include "plugin.h"
24 #include "cpu-boosting-type.h"
25 #include "cpu-boosting-private.h"
26
27 #include <errno.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <sys/un.h>
34 #ifndef gettid
35 #include <sys/syscall.h>
36
37 #ifdef SYS_gettid
38 #define gettid() (pid_t) syscall(SYS_gettid)
39 #else
40 #error "SYS_gettid unavailable on this system"
41 #endif
42 #endif
43
44 #define MAX_THREAD_NUM  131072                  /* This value is based on the max value of pid_max */
45 #define SOCK_PATH               "/run/.resourced.socket"
46
47 static int resource_create_and_connect_sock(void)
48 {
49         int sock;
50         socklen_t len;
51         struct sockaddr_un sockaddr;
52
53         sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
54         if (sock < 0) {
55                 _E("[CPU-BOOSTING-PLUGIN] Failed to allocate a socket");
56                 return -1;
57         }
58
59         sockaddr.sun_family = AF_UNIX;
60         strncpy(sockaddr.sun_path, SOCK_PATH, strlen(SOCK_PATH) + 1);
61         len = sizeof(sockaddr);
62
63         if (connect(sock, (struct sockaddr *)&sockaddr, len) < 0) {
64                 _E("[CPU-BOOSTING-PLUGIN] Failed to connect to the resourced module");
65                 close(sock);
66                 return -1;
67         }
68
69         return sock;
70 }
71
72 static inline bool resource_pid_input_is_valid(resource_pid_t pid)
73 {
74         if (pid.pid < 0) {
75                 _E("[CPU-BOOSTING-PLUGIN] pid should be euqal or larger than 0");
76                 return false;
77         }
78
79         if (pid.pid == 0 && pid.tid != NULL) {
80                 if (pid.tid_count <= 0) {
81                         _E("[CPU-BOOSTING-PLUGIN] tid count should be larger than 0");
82                         return false;
83                 }
84
85                 for (int i = 0; i < pid.tid_count; i++) {
86                         if (pid.tid[i] <= 0) {
87                                 _E("[CPU-BOOSTING-PLUGIN] Thread (id = %d) should be larger than 0",
88                                   pid.tid[i]);
89                                 return false;
90                         }
91                 }
92         }
93
94         return true;
95 }
96
97 static inline bool resource_cpu_boosting_level_input_is_valid(cpu_boosting_level_e level)
98 {
99         if (level < CPU_BOOSTING_LEVEL_STRONG || level > CPU_BOOSTING_LEVEL_WEAK) {
100                 _E("[CPU-BOOSTING-PLUGIN] cpu boosting level should be located between %d and %d, but current level = %d", CPU_BOOSTING_LEVEL_STRONG, CPU_BOOSTING_LEVEL_WEAK, level);
101                 return false;
102         }
103
104         return true;
105 }
106
107 static int resource_cpu_boosting_send_command (cpu_boosting_input_t input, int sock)
108 {
109         int byte;
110         pid_t tid;
111
112         if (input.pid.pid != 0)
113                 input.body_len = 0;
114         else {
115                 if (input.pid.tid == NULL) {
116                         tid = gettid();
117                         input.pid.tid = &tid;
118                         input.pid.tid_count = 1;
119                 }
120
121                 input.body_len = input.pid.tid_count * sizeof(pid_t);
122         }
123
124         byte = send(sock, (const void *)&input, sizeof(input), 0);
125         if (byte != sizeof(input)) {
126                 _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
127                 _E("[CPU-BOOSTING-PLUGIN] client input size is %u, but sent size is %d",
128                                 (unsigned int)sizeof(input), byte);
129                 return -1;
130         }
131
132         if (input.body_len > 0) {
133                 switch (input.command) {
134                         case CPU_BOOSTING_COMMAND_SET:
135                         case CPU_BOOSTING_COMMAND_CLEAR:
136                         case CPU_BOOSTING_COMMAND_GET:
137                         case CPU_BOOSTING_COMMAND_REGISTER_DESTINATION:
138                                 byte = send(sock, (const void *)input.pid.tid, input.body_len, 0);
139                                 if (byte != input.body_len) {
140                                         _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
141                                         _E("[CPU-BOOSTING-PLUGIN] client input size is %d, but sent size is %d",
142                                                         input.body_len, byte);
143                                         return -1;
144                                 }
145                                 break;
146                 }
147         }
148
149         if (input.dest && input.dest_len > 0) {
150                 byte = send(sock, (const void *)input.dest, input.dest_len, 0);
151                 if (byte != input.dest_len) {
152                         _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
153                         _E("[CPU-BOOSTING-PLUGIN] client input size is %d, but sent size is %d",
154                                         input.dest_len, byte);
155                         return -1;
156                 }
157         }
158
159         return 0;
160 }
161
162 API int resource_set_cpu_boosting (resource_pid_t pid,
163                 cpu_boosting_level_e level, cpu_boosting_flag_e flags, int timeout_msec)
164 {
165         int ret;
166         int sock;
167         cpu_boosting_input_t input;
168
169         if (!resource_pid_input_is_valid(pid))
170                 return -1;
171
172         if (!resource_cpu_boosting_level_input_is_valid(level))
173                 return -1;
174
175         if ((sock = resource_create_and_connect_sock()) < 0)
176                 return -1;
177
178         memset(&input, 0, sizeof(input));
179         input.command = CPU_BOOSTING_COMMAND_SET;
180         input.pid = pid;
181         input.level = level;
182         input.flags = flags;
183         input.timeout_msec = timeout_msec;
184
185         ret = resource_cpu_boosting_send_command(input, sock);
186         close(sock);
187
188         return ret;
189 }
190
191 API int resource_clear_cpu_boosting (resource_pid_t pid)
192 {
193         int ret;
194         int sock;
195         cpu_boosting_input_t input;
196
197         if (!resource_pid_input_is_valid(pid))
198                 return -1;
199
200         if ((sock = resource_create_and_connect_sock()) < 0)
201                 return -1;
202
203         memset(&input, 0, sizeof(input));
204         input.command = CPU_BOOSTING_COMMAND_CLEAR;
205         input.pid = pid;
206         input.level = CPU_BOOSTING_LEVEL_NONE;
207
208         ret = resource_cpu_boosting_send_command(input, sock);
209         close(sock);
210
211         return ret;
212 }
213
214 API int resource_get_cpu_boosting_level (resource_pid_t pid,
215                 cpu_boosting_level_info_t *level)
216 {
217         int ret;
218         int byte;
219         int sock;
220         bool retry = false;
221         cpu_boosting_output_t output;
222         cpu_boosting_input_t input;
223
224         if (!resource_pid_input_is_valid(pid))
225                 return -1;
226
227         if ((sock = resource_create_and_connect_sock()) < 0)
228                 return -1;
229
230         memset(&input, 0, sizeof(input));
231         input.command = CPU_BOOSTING_COMMAND_GET;
232         input.pid = pid;
233         input.level = CPU_BOOSTING_LEVEL_NONE;
234
235         ret = resource_cpu_boosting_send_command(input, sock);
236         if (ret < 0)
237                 goto close_sock;
238
239         struct timeval tv;
240         tv.tv_sec = 3;
241         tv.tv_usec = 0;
242         if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(tv)) < 0)
243                 _E("[CPU-BOOSTING-PLUGIN] Failed to set timeout of receive (error = %m)");
244
245         memset(&output, 0, sizeof(output));
246 retry_header:
247         byte = recv(sock, (void *)&output, sizeof(output), 0);
248         if (byte != sizeof(output)) {
249                 if (byte < 0) {
250                         if (errno == EAGAIN && retry == false) {
251                                 retry = true;
252                                 sleep(1);
253                                 goto retry_header;
254                         }
255
256                         _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
257                 }
258                 else
259                         _E("[CPU-BOOSTING-PLUGIN] client output size is %u, but received size is %d",
260                                         (unsigned int)sizeof(output), byte);
261                 ret = -1;
262                 goto close_sock;
263         }
264
265         if (output.level.tid_count > 0 && output.level.tid_count < MAX_THREAD_NUM) {
266                 level->tid_level = (int *)calloc(output.level.tid_count, sizeof(int));
267                 if (level->tid_level == NULL) {
268                         _E("[CPU-BOOSTING-PLUGIN] Failed to allocate memory");
269                         ret = -1;
270                         goto close_sock;
271                 }
272                 else
273                         level->tid_count = output.level.tid_count;
274
275 retry_body:
276                 byte = recv(sock, (void *)level->tid_level, level->tid_count * sizeof(int), 0);
277                 if (byte != level->tid_count * sizeof(int)) {
278                         if (byte < 0) {
279                                 if (errno == EAGAIN && retry == false) {
280                                         retry = true;
281                                         sleep(1);
282                                         goto retry_body;
283                                 }
284
285                                 _E("[CPU-BOOSTING-PLUGIN] error is based on %m");
286                         }
287                         else
288                                 _E("[CPU-BOOSTING-PLUGIN] client output size is %u, but received size is %d",
289                                                 level->tid_count * (unsigned int)sizeof(int), byte);
290
291                         free(level->tid_level);
292                         ret = -1;
293                         goto close_sock;
294                 }
295
296                 if (!output.success) {
297                         _E("[CPU-BOOSTING-PLUGIN] Failed to get boosting from the server");
298                         free(level->tid_level);
299                         ret = -1;
300                 }
301         }
302         else {
303                 _E("[CPU-BOOSTING-PLUGIN] Returned tid_count is out of scope");
304                 ret = -1;
305                 goto close_sock;
306         }
307
308 close_sock:
309         close(sock);
310
311         return ret;
312 }
313
314 API int resource_set_cpu_inheritance (pid_t source_tid, const char *dest_process, int timeout_msec)
315 {
316         int ret;
317         int sock;
318         cpu_boosting_input_t input;
319
320         if (source_tid < 0)
321                 return -1;
322         else if (source_tid == 0)
323                 source_tid = gettid();
324
325         if (dest_process == NULL)
326                 return -1;
327
328         if ((sock = resource_create_and_connect_sock()) < 0)
329                 return -1;
330
331         memset(&input, 0, sizeof(input));
332         input.command = CPU_BOOSTING_COMMAND_SET_INHERITANCE;
333         input.pid.pid = source_tid;
334         input.timeout_msec = timeout_msec;
335         input.dest = dest_process;
336         input.dest_len = strlen(dest_process);
337
338         ret = resource_cpu_boosting_send_command(input, sock);
339         close(sock);
340
341         return ret;
342 }
343
344 API int resource_clear_cpu_inheritance (pid_t source_tid, const char *dest_process)
345 {
346         int ret;
347         int sock;
348         cpu_boosting_input_t input;
349
350         if (source_tid < 0)
351                 return -1;
352         else if (source_tid == 0)
353                 source_tid = gettid();
354
355         if (dest_process == NULL)
356                 return -1;
357
358         if ((sock = resource_create_and_connect_sock()) < 0)
359                 return -1;
360
361         memset(&input, 0, sizeof(input));
362         input.command = CPU_BOOSTING_COMMAND_CLEAR_INHERITANCE;
363         input.pid.pid = source_tid;
364         input.dest = dest_process;
365         input.dest_len = strlen(dest_process);
366
367         ret = resource_cpu_boosting_send_command(input, sock);
368         close(sock);
369
370         return ret;
371 }
372
373 API int resource_register_cpu_inheritance_destination (const char *dest_process, resource_pid_t pid)
374 {
375         int ret;
376         int sock;
377         cpu_boosting_input_t input;
378
379         if (!resource_pid_input_is_valid(pid))
380                 return -1;
381
382         if (dest_process == NULL)
383                 return -1;
384
385         if ((sock = resource_create_and_connect_sock()) < 0)
386                 return -1;
387
388         memset(&input, 0, sizeof(input));
389         input.command = CPU_BOOSTING_COMMAND_REGISTER_DESTINATION;
390         input.pid = pid;
391         input.dest = dest_process;
392         input.dest_len = strlen(dest_process);
393
394         ret = resource_cpu_boosting_send_command(input, sock);
395         close(sock);
396
397         return ret;
398 }
399
400 API int resource_unregister_cpu_inheritance_destination (const char *dest_process)
401 {
402         int ret;
403         int sock;
404         cpu_boosting_input_t input;
405
406         if (dest_process == NULL)
407                 return -1;
408
409         if ((sock = resource_create_and_connect_sock()) < 0)
410                 return -1;
411
412         memset(&input, 0, sizeof(input));
413         input.command = CPU_BOOSTING_COMMAND_UNREGISTER_DESTINATION;
414         input.pid.pid = -1;
415         input.dest = dest_process;
416         input.dest_len = strlen(dest_process);
417
418         ret = resource_cpu_boosting_send_command(input, sock);
419         close(sock);
420
421         return ret;
422 }
423
424 void __CONSTRUCTOR__ cpu_boosting_plugin_init(void)
425 {
426         _D("[CPU-BOOSTING-PLUGIN] CPU boosting plugin Module is loaded");
427 }
428
429 void __DESTRUCTOR__ cpu_boosting_plugin_exit(void)
430 {
431         _D("[CPU-BOOSTING-PLUGIN] CPU boosting plugin Module is unloaded");
432 }