9a6faee2ed12f2df29a7522ae0017db558137fc1
[framework/system/system-server.git] / ss_procmgr.c
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdio.h>
19 #include <stdbool.h>
20 #include <unistd.h>
21 #include <dirent.h>
22 #include <sys/types.h>
23
24 #include <sysman.h>
25 #include "include/ss_data.h"
26 #include "ss_queue.h"
27 #include "ss_log.h"
28
29 #define LIMITED_BACKGRD_NUM 15
30 #define MAX_BACKGRD_OOMADJ (OOMADJ_BACKGRD_UNLOCKED + LIMITED_BACKGRD_NUM)
31
32 int get_app_oomadj(int pid, int *oomadj)
33 {
34         if (pid < 0)
35                 return -1;
36
37         char buf[PATH_MAX];
38         FILE *fp = NULL;
39
40         snprintf(buf, sizeof(buf), "/proc/%d/oom_adj", pid);
41         fp = fopen(buf, "r");
42         if (fp == NULL)
43                 return -1;
44         if (fgets(buf, PATH_MAX, fp) == NULL) {
45                 fclose(fp);
46                 return -1;
47         }
48         (*oomadj) = atoi(buf);
49         fclose(fp);
50         return 0;
51 }
52
53 int set_app_oomadj(pid_t pid, int new_oomadj)
54 {
55         char buf[PATH_MAX];
56         FILE *fp;
57         int old_oomadj;
58         char exe_name[PATH_MAX];
59
60         if (sysman_get_cmdline_name(pid, exe_name, PATH_MAX) < 0)
61                 snprintf(exe_name, sizeof(exe_name), "Unknown (maybe dead)");
62
63         snprintf(buf, sizeof(buf), "/proc/%d/oom_adj", pid);
64         fp = fopen(buf, "r");
65         if (fp == NULL)
66                 return -1;
67         if (fgets(buf, PATH_MAX, fp) == NULL) {
68                 fclose(fp);
69                 return -1;
70         }
71         old_oomadj = atoi(buf);
72         fclose(fp);
73         PRT_TRACE_EM("Process %s, pid %d, old_oomadj %d", exe_name, pid,
74                      old_oomadj);
75
76         if (old_oomadj < OOMADJ_APP_LIMIT)
77                 return 0;
78
79         PRT_TRACE_EM("Process %s, pid %d, new_oomadj %d", exe_name, pid,
80                      new_oomadj);
81         snprintf(buf, sizeof(buf), "/proc/%d/oom_adj", pid);
82         fp = fopen(buf, "w");
83         if (fp == NULL)
84                 return -1;
85
86         fprintf(fp, "%d", new_oomadj);
87         fclose(fp);
88
89         return 0;
90 }
91
92 int set_oomadj_action(int argc, char **argv)
93 {
94         int pid = -1;
95         int new_oomadj = -20;
96
97         if (argc < 2)
98                 return -1;
99         if ((pid = atoi(argv[0])) < 0 || (new_oomadj = atoi(argv[1])) <= -20)
100                 return -1;
101
102         char buf[255];
103         FILE *fp;
104
105         PRT_TRACE_EM("OOMADJ_SET : pid %d, new_oomadj %d", pid, new_oomadj);
106         snprintf(buf, sizeof(buf), "/proc/%d/oom_adj", pid);
107         fp = fopen(buf, "w");
108         if (fp == NULL)
109                 return -1;
110         fprintf(fp, "%d", new_oomadj);
111         fclose(fp);
112
113         return 0;
114 }
115
116 static int update_backgrd_app_oomadj(pid_t pid, int new_oomadj)
117 {
118         char buf[PATH_MAX];
119         FILE* fp;
120
121         snprintf(buf, sizeof(buf), "/proc/%d/oom_adj", pid);
122         fp = fopen(buf, "w");
123         if (fp == NULL)
124                 return -1;
125
126         fprintf(fp, "%d", new_oomadj);
127         fclose(fp);
128
129         return 0;
130 }
131
132 int check_and_set_old_backgrd()
133 {
134         int pid = -1;
135         DIR *dp;
136         struct dirent *dentry;
137         FILE *fp;
138         char buf[PATH_MAX];
139         int token =0;
140         int oom_adj, new_oomadj, i;
141         pid_t buckets[MAX_BACKGRD_OOMADJ][LIMITED_BACKGRD_NUM];
142
143         dp = opendir("/proc");
144         if (!dp) {
145                 PRT_TRACE_EM("BACKGRD MANAGE : fail to open /proc : %s", strerror(errno));
146                 return -1;
147         }
148
149         memset(buckets, 0, sizeof(buckets));
150         while ((dentry = readdir(dp)) != NULL) {
151                 if (!isdigit(dentry->d_name[0]))
152                         continue;
153
154                 pid = atoi(dentry->d_name);
155
156                 snprintf(buf, sizeof(buf), "/proc/%d/oom_adj", pid);
157                 fp = fopen(buf, "r");
158                 if (fp == NULL)
159                         continue;
160                 if (fgets(buf, sizeof(buf), fp) == NULL) {
161                         fclose(fp);
162                         continue;
163                 }
164                 oom_adj = atoi(buf);
165                 if (oom_adj < MAX_BACKGRD_OOMADJ && oom_adj >= OOMADJ_BACKGRD_UNLOCKED) {
166                         pid_t *bucket = buckets[oom_adj];
167                         for (i = 0; i < LIMITED_BACKGRD_NUM; i++) {
168                                 if (!bucket[i])
169                                         break;
170                         }
171                         if (i >= LIMITED_BACKGRD_NUM)
172                                 PRT_TRACE_EM("BACKGRB MANAGE : background applications(oom_adj %d) exceeds limitation", i);
173                         else
174                                 bucket[i] = pid;
175                 }
176                 fclose(fp);
177         }
178         closedir(dp);
179
180         new_oomadj = OOMADJ_BACKGRD_UNLOCKED + 1;
181         for (oom_adj = OOMADJ_BACKGRD_UNLOCKED; oom_adj < MAX_BACKGRD_OOMADJ; oom_adj++) {
182                 for (i = 0; i < LIMITED_BACKGRD_NUM; i++) {
183                         pid = buckets[oom_adj][i];
184                         if (!pid)
185                                 break;
186                         if (new_oomadj >= MAX_BACKGRD_OOMADJ) {
187                                 PRT_TRACE("BACKGRD MANAGE : kill the process %d (oom_adj %d)", pid, MAX_BACKGRD_OOMADJ);
188                                 kill(pid, SIGTERM);
189                         }
190                         else {
191                                 if (new_oomadj != oom_adj)
192                                         update_backgrd_app_oomadj(pid, new_oomadj);
193                                 new_oomadj++;
194                         }
195                 }
196         }
197
198         return 0;
199 }
200
201 int set_active_action(int argc, char **argv)
202 {
203         int pid = -1;
204         int ret = 0;
205         int oomadj = 0;
206
207         if (argc < 1)
208                 return -1;
209         if ((pid = atoi(argv[0])) < 0)
210                 return -1;
211
212         if (get_app_oomadj(pid, &oomadj) < 0)
213                 return -1;
214
215         switch (oomadj) {
216         case OOMADJ_FOREGRD_LOCKED:
217         case OOMADJ_BACKGRD_LOCKED:
218         case OOMADJ_SU:
219                 ret = 0;
220                 break;
221         case OOMADJ_FOREGRD_UNLOCKED:
222                 ret = set_app_oomadj((pid_t) pid, OOMADJ_FOREGRD_LOCKED);
223                 break;
224         case OOMADJ_BACKGRD_UNLOCKED:
225                 ret = set_app_oomadj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
226                 break;
227         case OOMADJ_INIT:
228                 ret = set_app_oomadj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
229                 break;
230         default:
231                 if(oomadj > OOMADJ_BACKGRD_UNLOCKED) {
232                         ret = set_app_oomadj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
233                 } else {
234                         PRT_TRACE_EM("Unknown oomadj value (%d) !", oomadj);
235                         ret = -1;
236                 }
237                 break;
238         }
239         return ret;
240 }
241
242 int set_inactive_action(int argc, char **argv)
243 {
244         int pid = -1;
245         int ret = 0;
246         int oomadj = 0;
247
248         if (argc < 1)
249                 return -1;
250         if ((pid = atoi(argv[0])) < 0)
251                 return -1;
252
253         if (get_app_oomadj(pid, &oomadj) < 0)
254                 return -1;
255
256         switch (oomadj) {
257         case OOMADJ_FOREGRD_UNLOCKED:
258         case OOMADJ_BACKGRD_UNLOCKED:
259         case OOMADJ_SU:
260                 ret = 0;
261                 break;
262         case OOMADJ_FOREGRD_LOCKED:
263                 ret = set_app_oomadj((pid_t) pid, OOMADJ_FOREGRD_UNLOCKED);
264                 break;
265         case OOMADJ_BACKGRD_LOCKED:
266                 check_and_set_old_backgrd();
267                 ret = set_app_oomadj((pid_t) pid, OOMADJ_BACKGRD_UNLOCKED);
268                 break;
269         case OOMADJ_INIT:
270                 check_and_set_old_backgrd();
271                 ret = set_app_oomadj((pid_t) pid, OOMADJ_BACKGRD_UNLOCKED);
272                 break;
273         default:
274                 if(oomadj > OOMADJ_BACKGRD_UNLOCKED) {
275                         ret = 0;
276                 } else {
277                         PRT_TRACE_EM("Unknown oomadj value (%d) !", oomadj);
278                         ret = -1;
279                 }
280                 break;
281
282         }
283         return ret;
284 }
285
286 int set_foregrd_action(int argc, char **argv)
287 {
288         int pid = -1;
289         int ret = 0;
290         int oomadj = 0;
291
292         if (argc < 1)
293                 return -1;
294         if ((pid = atoi(argv[0])) < 0)
295                 return -1;
296
297         if (get_app_oomadj(pid, &oomadj) < 0)
298                 return -1;
299
300         switch (oomadj) {
301         case OOMADJ_FOREGRD_LOCKED:
302         case OOMADJ_FOREGRD_UNLOCKED:
303         case OOMADJ_SU:
304                 ret = 0;
305                 break;
306         case OOMADJ_BACKGRD_LOCKED:
307                 ret = set_app_oomadj((pid_t) pid, OOMADJ_FOREGRD_LOCKED);
308                 break;
309         case OOMADJ_BACKGRD_UNLOCKED:
310                 ret = set_app_oomadj((pid_t) pid, OOMADJ_FOREGRD_UNLOCKED);
311                 break;
312         case OOMADJ_INIT:
313                 ret = set_app_oomadj((pid_t) pid, OOMADJ_FOREGRD_UNLOCKED);
314                 break;
315         default:
316                 if(oomadj > OOMADJ_BACKGRD_UNLOCKED) {
317                         ret = set_app_oomadj((pid_t) pid, OOMADJ_FOREGRD_UNLOCKED);
318                 } else {                
319                         PRT_TRACE_EM("Unknown oomadj value (%d) !", oomadj);
320                         ret = -1;                                       
321                 }
322                 break;
323
324         }
325         return ret;
326 }
327
328 int set_backgrd_action(int argc, char **argv)
329 {
330         int pid = -1;
331         int ret = 0;
332         int oomadj = 0;
333
334         if (argc < 1)
335                 return -1;
336         if ((pid = atoi(argv[0])) < 0)
337                 return -1;
338
339         if (get_app_oomadj(pid, &oomadj) < 0)
340                 return -1;
341
342         switch (oomadj) {
343         case OOMADJ_BACKGRD_LOCKED:
344         case OOMADJ_BACKGRD_UNLOCKED:
345         case OOMADJ_SU:
346                 ret = 0;
347                 break;
348         case OOMADJ_FOREGRD_LOCKED:
349                 ret = set_app_oomadj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
350                 break;
351         case OOMADJ_FOREGRD_UNLOCKED:
352                 check_and_set_old_backgrd();
353                 ret = set_app_oomadj((pid_t) pid, OOMADJ_BACKGRD_UNLOCKED);
354                 break;
355         case OOMADJ_INIT:
356                 check_and_set_old_backgrd();
357                 ret = set_app_oomadj((pid_t) pid, OOMADJ_BACKGRD_UNLOCKED);
358                 break;
359         default:
360                 if(oomadj > OOMADJ_BACKGRD_UNLOCKED) {
361                         ret = 0;
362                 } else {                
363                         PRT_TRACE_EM("Unknown oomadj value (%d) !", oomadj);
364                         ret = -1;                                       
365                 }
366                 break;
367         }
368         return ret;
369 }
370
371 int ss_process_manager_init(void)
372 {
373         ss_action_entry_add_internal(PREDEF_FOREGRD, set_foregrd_action, NULL,
374                                      NULL);
375         ss_action_entry_add_internal(PREDEF_BACKGRD, set_backgrd_action, NULL,
376                                      NULL);
377         ss_action_entry_add_internal(PREDEF_ACTIVE, set_active_action, NULL,
378                                      NULL);
379         ss_action_entry_add_internal(PREDEF_INACTIVE, set_inactive_action, NULL,
380                                      NULL);
381         ss_action_entry_add_internal(OOMADJ_SET, set_oomadj_action, NULL, NULL);
382         return 0;
383 }