blob: 376410b193964cd13b02f5562767dcb8589510bf [file] [log] [blame]
Todd Poynor58d58072013-07-09 19:35:14 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
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#define LOG_TAG "lowmemorykiller"
18
19#include <errno.h>
20#include <signal.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <time.h>
25#include <unistd.h>
26#include <arpa/inet.h>
27#include <sys/epoll.h>
28#include <sys/eventfd.h>
29#include <sys/socket.h>
30#include <sys/types.h>
31#include <cutils/log.h>
32#include <cutils/sockets.h>
33
34#define MEMCG_SYSFS_PATH "/dev/memcg/"
35#define MEMPRESSURE_WATCH_LEVEL "medium"
36#define ZONEINFO_PATH "/proc/zoneinfo"
37#define LINE_MAX 128
38
39#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
40#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
41
42#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
43
44enum lmk_cmd {
45 LMK_TARGET,
46 LMK_PROCPRIO,
47 LMK_PROCREMOVE,
48};
49
50#define MAX_TARGETS 6
51/*
52 * longest is LMK_TARGET followed by MAX_TARGETS each minfree and minkillprio
53 * values
54 */
55#define CTRL_PACKET_MAX (sizeof(int) * (MAX_TARGETS * 2 + 1))
56
57/* default to old in-kernel interface if no memory pressure events */
58static int use_inkernel_interface = 1;
59
60/* memory pressure level medium event */
61static int mpevfd;
62
63/* control socket listen and data */
64static int ctrl_lfd;
65static int ctrl_dfd = -1;
66static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
67
68/* 1 memory pressure level, 1 ctrl listen socket, 1 ctrl data socket */
69#define MAX_EPOLL_EVENTS 3
70static int epollfd;
71static int maxevents;
72
73#define OOM_DISABLE (-17)
74/* inclusive */
75#define OOM_ADJUST_MIN (-16)
76#define OOM_ADJUST_MAX 15
77
78static int lowmem_adj[MAX_TARGETS];
79static int lowmem_minfree[MAX_TARGETS];
80static int lowmem_targets_size;
81
82struct sysmeminfo {
83 int nr_free_pages;
84 int nr_file_pages;
85 int nr_shmem;
86 int totalreserve_pages;
87};
88
89struct adjslot_list {
90 struct adjslot_list *next;
91 struct adjslot_list *prev;
92};
93
94struct proc {
95 struct adjslot_list asl;
96 int pid;
97 int oomadj;
98 struct proc *pidhash_next;
99};
100
101#define PIDHASH_SZ 1024
102static struct proc *pidhash[PIDHASH_SZ];
103#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
104
105#define ADJTOSLOT(adj) (adj + -OOM_ADJUST_MIN)
106static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_ADJUST_MAX) + 1];
107
108/*
109 * Wait 1-2 seconds for the death report of a killed process prior to
110 * considering killing more processes.
111 */
112#define KILL_TIMEOUT 2
113/* Time of last process kill we initiated, stop me before I kill again */
114static time_t kill_lasttime;
115
116/* PAGE_SIZE / 1024 */
117static long page_k;
118
119static struct proc *pid_lookup(int pid) {
120 struct proc *procp;
121
122 for (procp = pidhash[pid_hashfn(pid)]; procp && procp->pid != pid;
123 procp = procp->pidhash_next)
124 ;
125
126 return procp;
127}
128
129static void adjslot_insert(struct adjslot_list *head, struct adjslot_list *new)
130{
131 struct adjslot_list *next = head->next;
132 new->prev = head;
133 new->next = next;
134 next->prev = new;
135 head->next = new;
136}
137
138static void adjslot_remove(struct adjslot_list *old)
139{
140 struct adjslot_list *prev = old->prev;
141 struct adjslot_list *next = old->next;
142 next->prev = prev;
143 prev->next = next;
144}
145
146static struct adjslot_list *adjslot_tail(struct adjslot_list *head) {
147 struct adjslot_list *asl = head->prev;
148
149 return asl == head ? NULL : asl;
150}
151
152static void proc_slot(struct proc *procp) {
153 int adjslot = ADJTOSLOT(procp->oomadj);
154
155 adjslot_insert(&procadjslot_list[adjslot], &procp->asl);
156}
157
158static void proc_unslot(struct proc *procp) {
159 adjslot_remove(&procp->asl);
160}
161
162static void proc_insert(struct proc *procp) {
163 int hval = pid_hashfn(procp->pid);
164
165 procp->pidhash_next = pidhash[hval];
166 pidhash[hval] = procp;
167 proc_slot(procp);
168}
169
170static int pid_remove(int pid) {
171 int hval = pid_hashfn(pid);
172 struct proc *procp;
173 struct proc *prevp;
174
175 for (procp = pidhash[hval], prevp = NULL; procp && procp->pid != pid;
176 procp = procp->pidhash_next)
177 prevp = procp;
178
179 if (!procp)
180 return -1;
181
182 if (!prevp)
183 pidhash[hval] = procp->pidhash_next;
184 else
185 prevp->pidhash_next = procp->pidhash_next;
186
187 proc_unslot(procp);
188 free(procp);
189 return 0;
190}
191
192static void writefilestring(char *path, char *s) {
193 int fd = open(path, O_WRONLY);
194 int len = strlen(s);
195 int ret;
196
197 if (fd < 0) {
198 ALOGE("Error opening %s; errno=%d", path, errno);
199 return;
200 }
201
202 ret = write(fd, s, len);
203 if (ret < 0) {
204 ALOGE("Error writing %s; errno=%d", path, errno);
205 } else if (ret < len) {
206 ALOGE("Short write on %s; length=%d", path, ret);
207 }
208
209 close(fd);
210}
211
212static void cmd_procprio(int pid, int oomadj) {
213 struct proc *procp;
214 char path[80];
215 char val[20];
216
217 if (oomadj < OOM_DISABLE || oomadj > OOM_ADJUST_MAX) {
218 ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
219 return;
220 }
221
222 snprintf(path, sizeof(path), "/proc/%d/oom_adj", pid);
223 snprintf(val, sizeof(val), "%d", oomadj);
224 writefilestring(path, val);
225
226 if (use_inkernel_interface)
227 return;
228
229 procp = pid_lookup(pid);
230 if (!procp) {
231 procp = malloc(sizeof(struct proc));
232 if (!procp) {
233 // Oh, the irony. May need to rebuild our state.
234 return;
235 }
236
237 procp->pid = pid;
238 procp->oomadj = oomadj;
239 proc_insert(procp);
240 } else {
241 proc_unslot(procp);
242 procp->oomadj = oomadj;
243 proc_slot(procp);
244 }
245}
246
247static void cmd_procremove(int pid) {
248 struct proc *procp;
249
250 if (use_inkernel_interface)
251 return;
252
253 pid_remove(pid);
254 kill_lasttime = 0;
255}
256
257static void cmd_target(int ntargets, int *params) {
258 int i;
259
260 if (ntargets > (int)ARRAY_SIZE(lowmem_adj))
261 return;
262
263 for (i = 0; i < ntargets; i++) {
264 lowmem_minfree[i] = ntohl(*params++);
265 lowmem_adj[i] = ntohl(*params++);
266 }
267
268 lowmem_targets_size = ntargets;
269
270 if (use_inkernel_interface) {
271 char minfreestr[128];
272 char killpriostr[128];
273
274 minfreestr[0] = '\0';
275 killpriostr[0] = '\0';
276
277 for (i = 0; i < lowmem_targets_size; i++) {
278 char val[40];
279
280 if (i) {
281 strlcat(minfreestr, ",", sizeof(minfreestr));
282 strlcat(killpriostr, ",", sizeof(killpriostr));
283 }
284
285 snprintf(val, sizeof(val), "%d", lowmem_minfree[i]);
286 strlcat(minfreestr, val, sizeof(minfreestr));
287 snprintf(val, sizeof(val), "%d", lowmem_adj[i]);
288 strlcat(killpriostr, val, sizeof(killpriostr));
289 }
290
291 writefilestring(INKERNEL_MINFREE_PATH, minfreestr);
292 writefilestring(INKERNEL_ADJ_PATH, killpriostr);
293 }
294}
295
296static void ctrl_data_close(void) {
297 ALOGI("Closing Activity Manager data connection");
298 close(ctrl_dfd);
299 ctrl_dfd = -1;
300 maxevents--;
301}
302
303static int ctrl_data_read(char *buf, size_t bufsz) {
304 int ret = 0;
305
306 ret = read(ctrl_dfd, buf, bufsz);
307
308 if (ret == -1) {
309 ALOGE("control data socket read failed; errno=%d", errno);
310 } else if (ret == 0) {
311 ALOGE("Got EOF on control data socket");
312 ret = -1;
313 }
314
315 return ret;
316}
317
318static void ctrl_command_handler(void) {
319 int ibuf[CTRL_PACKET_MAX / sizeof(int)];
320 int len;
321 int cmd = -1;
322 int nargs;
323 int targets;
324
325 len = ctrl_data_read((char *)ibuf, CTRL_PACKET_MAX);
326 if (len <= 0)
327 return;
328
329 nargs = len / sizeof(int) - 1;
330 if (nargs < 0)
331 goto wronglen;
332
333 cmd = ntohl(ibuf[0]);
334
335 switch(cmd) {
336 case LMK_TARGET:
337 targets = nargs / 2;
338 if (nargs & 0x1 || targets > (int)ARRAY_SIZE(lowmem_adj))
339 goto wronglen;
340 cmd_target(targets, &ibuf[1]);
341 break;
342 case LMK_PROCPRIO:
343 if (nargs != 2)
344 goto wronglen;
345 cmd_procprio(ntohl(ibuf[1]), ntohl(ibuf[2]));
346 break;
347 case LMK_PROCREMOVE:
348 if (nargs != 1)
349 goto wronglen;
350 cmd_procremove(ntohl(ibuf[1]));
351 break;
352 default:
353 ALOGE("Received unknown command code %d", cmd);
354 return;
355 }
356
357 return;
358
359wronglen:
360 ALOGE("Wrong control socket read length cmd=%d len=%d", cmd, len);
361}
362
363static void ctrl_data_handler(uint32_t events) {
364 if (events & EPOLLHUP) {
365 ALOGI("ActivityManager disconnected");
366 if (!ctrl_dfd_reopened)
367 ctrl_data_close();
368 } else if (events & EPOLLIN) {
369 ctrl_command_handler();
370 }
371}
372
373static void ctrl_connect_handler(uint32_t events) {
374 struct sockaddr addr;
375 socklen_t alen;
376 struct epoll_event epev;
377
378 if (ctrl_dfd >= 0) {
379 ctrl_data_close();
380 ctrl_dfd_reopened = 1;
381 }
382
383 alen = sizeof(addr);
384 ctrl_dfd = accept(ctrl_lfd, &addr, &alen);
385
386 if (ctrl_dfd < 0) {
387 ALOGE("lmkd control socket accept failed; errno=%d", errno);
388 return;
389 }
390
391 ALOGI("ActivityManager connected");
392 maxevents++;
393 epev.events = EPOLLIN;
394 epev.data.ptr = (void *)ctrl_data_handler;
395 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ctrl_dfd, &epev) == -1) {
396 ALOGE("epoll_ctl for data connection socket failed; errno=%d", errno);
397 ctrl_data_close();
398 return;
399 }
400}
401
402static int zoneinfo_parse_protection(char *cp) {
403 int max = 0;
404 int zoneval;
405
406 if (*cp++ != '(')
407 return 0;
408
409 do {
410 zoneval = strtol(cp, &cp, 0);
411 if ((*cp != ',') && (*cp != ')'))
412 return 0;
413 if (zoneval > max)
414 max = zoneval;
415 } while (cp = strtok(NULL, " "));
416
417 return max;
418}
419
420static void zoneinfo_parse_line(char *line, struct sysmeminfo *mip) {
421 char *cp = line;
422 char *ap;
423
424 cp = strtok(line, " ");
425 if (!cp)
426 return;
427
428 ap = strtok(NULL, " ");
429 if (!ap)
430 return;
431
432 if (!strcmp(cp, "nr_free_pages"))
433 mip->nr_free_pages += strtol(ap, NULL, 0);
434 else if (!strcmp(cp, "nr_file_pages"))
435 mip->nr_file_pages += strtol(ap, NULL, 0);
436 else if (!strcmp(cp, "nr_shmem"))
437 mip->nr_shmem += strtol(ap, NULL, 0);
438 else if (!strcmp(cp, "high"))
439 mip->totalreserve_pages += strtol(ap, NULL, 0);
440 else if (!strcmp(cp, "protection:"))
441 mip->totalreserve_pages += zoneinfo_parse_protection(ap);
442}
443
444static int zoneinfo_parse(struct sysmeminfo *mip) {
445 FILE *f;
446 char *cp;
447 char line[LINE_MAX];
448
449 memset(mip, 0, sizeof(struct sysmeminfo));
450 f = fopen(ZONEINFO_PATH, "r");
451 if (!f) {
452 ALOGE("%s open: errno=%d", ZONEINFO_PATH, errno);
453 return -1;
454 }
455
456 while (fgets(line, LINE_MAX, f))
457 zoneinfo_parse_line(line, mip);
458
459 fclose(f);
460 return 0;
461}
462
463static int proc_get_size(int pid) {
464 char path[PATH_MAX];
465 char line[LINE_MAX];
466 FILE *f;
467 int rss = 0;
468 int total;
469
470 snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
471 f = fopen(path, "r");
472 if (!f)
473 return -1;
474 if (!fgets(line, LINE_MAX, f)) {
475 fclose(f);
476 return -1;
477 }
478
479 sscanf(line, "%d %d ", &total, &rss);
480 fclose(f);
481 return rss;
482}
483
484static char *proc_get_name(int pid) {
485 char path[PATH_MAX];
486 static char line[LINE_MAX];
487 FILE *f;
488 char *cp;
489
490 snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
491 f = fopen(path, "r");
492 if (!f)
493 return NULL;
494 if (!fgets(line, LINE_MAX, f)) {
495 fclose(f);
496 return NULL;
497 }
498
499 cp = strchr(line, ' ');
500 if (cp)
501 *cp = '\0';
502
503 return line;
504}
505
506static struct proc *proc_adj_lru(int oomadj) {
507 return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
508}
509
510static void mp_event(uint32_t events) {
511 int i;
512 int ret;
513 unsigned long long evcount;
514 struct sysmeminfo mi;
515 int other_free;
516 int other_file;
517 int minfree = 0;
518 int min_score_adj = OOM_ADJUST_MAX + 1;
519
520 ret = read(mpevfd, &evcount, sizeof(evcount));
521 if (ret < 0)
522 ALOGE("Error reading memory pressure event fd; errno=%d",
523 errno);
524
525 if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
526 return;
527
528 if (zoneinfo_parse(&mi) < 0)
529 return;
530
531 other_free = mi.nr_free_pages - mi.totalreserve_pages;
532 other_file = mi.nr_file_pages - mi.nr_shmem;
533
534 for (i = 0; i < lowmem_targets_size; i++) {
535 minfree = lowmem_minfree[i];
536 if (other_free < minfree && other_file < minfree) {
537 min_score_adj = lowmem_adj[i];
538 break;
539 }
540 }
541
542 if (min_score_adj == OOM_ADJUST_MAX + 1)
543 return;
544
545 for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
546 struct proc *procp;
547
548 retry:
549 procp = proc_adj_lru(i);
550
551 if (procp) {
552 int pid = procp->pid;
553 char *taskname;
554 int tasksize;
555 int r;
556
557 taskname = proc_get_name(pid);
558 if (!taskname) {
559 pid_remove(pid);
560 goto retry;
561 }
562
563 tasksize = proc_get_size(pid);
564 if (tasksize < 0) {
565 pid_remove(pid);
566 goto retry;
567 }
568
569 ALOGI("Killing '%s' (%d), adj %d\n"
570 " to free %ldkB because cache %ldkB is below limit %ldkB for oom_adj %d\n"
571 " Free memory is %ldkB %s reserved",
572 taskname, pid, procp->oomadj, tasksize * page_k,
573 other_file * page_k, minfree * page_k, min_score_adj,
574 other_free * page_k, other_free >= 0 ? "above" : "below");
575 r = kill(pid, SIGKILL);
576 pid_remove(pid);
577
578 if (r) {
579 ALOGE("kill(%d): errno=%d", procp->pid, errno);
580 goto retry;
581 } else {
582 time(&kill_lasttime);
583 break;
584 }
585 }
586 }
587}
588
589static int init_mp(char *levelstr, void *event_handler)
590{
591 int mpfd;
592 int evfd;
593 int evctlfd;
594 char buf[256];
595 struct epoll_event epev;
596 int ret;
597
598 mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY);
599 if (mpfd < 0) {
600 ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
601 goto err_open_mpfd;
602 }
603
604 evctlfd = open(MEMCG_SYSFS_PATH "cgroup.event_control", O_WRONLY);
605 if (evctlfd < 0) {
606 ALOGI("No kernel memory cgroup event control (errno=%d)", errno);
607 goto err_open_evctlfd;
608 }
609
610 evfd = eventfd(0, EFD_NONBLOCK);
611 if (evfd < 0) {
612 ALOGE("eventfd failed for level %s; errno=%d", levelstr, errno);
613 goto err_eventfd;
614 }
615
616 ret = snprintf(buf, sizeof(buf), "%d %d %s", evfd, mpfd, levelstr);
617 if (ret >= (ssize_t)sizeof(buf)) {
618 ALOGE("cgroup.event_control line overflow for level %s", levelstr);
619 goto err;
620 }
621
622 ret = write(evctlfd, buf, strlen(buf) + 1);
623 if (ret == -1) {
624 ALOGE("cgroup.event_control write failed for level %s; errno=%d",
625 levelstr, errno);
626 goto err;
627 }
628
629 epev.events = EPOLLIN;
630 epev.data.ptr = event_handler;
631 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, evfd, &epev);
632 if (ret == -1) {
633 ALOGE("epoll_ctl for level %s failed; errno=%d", levelstr, errno);
634 goto err;
635 }
636 maxevents++;
637 mpevfd = evfd;
638 return 0;
639
640err:
641 close(evfd);
642err_eventfd:
643 close(evctlfd);
644err_open_evctlfd:
645 close(mpfd);
646err_open_mpfd:
647 return -1;
648}
649
650static int init(void) {
651 struct epoll_event epev;
652 int i;
653 int ret;
654
655 page_k = sysconf(_SC_PAGESIZE);
656 if (page_k == -1)
657 page_k = PAGE_SIZE;
658 page_k /= 1024;
659
660 epollfd = epoll_create(MAX_EPOLL_EVENTS);
661 if (epollfd == -1) {
662 ALOGE("epoll_create failed (errno=%d)", errno);
663 return -1;
664 }
665
666 ctrl_lfd = android_get_control_socket("lmkd");
667 if (ctrl_lfd < 0) {
668 ALOGE("get lmkd control socket failed");
669 return -1;
670 }
671
672 ret = listen(ctrl_lfd, 1);
673 if (ret < 0) {
674 ALOGE("lmkd control socket listen failed (errno=%d)", errno);
675 return -1;
676 }
677
678 epev.events = EPOLLIN;
679 epev.data.ptr = (void *)ctrl_connect_handler;
680 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ctrl_lfd, &epev) == -1) {
681 ALOGE("epoll_ctl for lmkd control socket failed (errno=%d)", errno);
682 return -1;
683 }
684 maxevents++;
685
686 use_inkernel_interface = !access(INKERNEL_MINFREE_PATH, W_OK);
687
688 if (use_inkernel_interface) {
689 ALOGI("Using in-kernel low memory killer interface");
690 } else {
691 ret = init_mp(MEMPRESSURE_WATCH_LEVEL, (void *)&mp_event);
692 if (ret)
693 ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
694 }
695
696 for (i = 0; i <= ADJTOSLOT(OOM_ADJUST_MAX); i++) {
697 procadjslot_list[i].next = &procadjslot_list[i];
698 procadjslot_list[i].prev = &procadjslot_list[i];
699 }
700
701 return 0;
702}
703
704static void mainloop(void) {
705 while (1) {
706 struct epoll_event events[maxevents];
707 int nevents;
708 int i;
709
710 ctrl_dfd_reopened = 0;
711 nevents = epoll_wait(epollfd, events, maxevents, -1);
712
713 if (nevents == -1) {
714 if (errno == EINTR)
715 continue;
716 ALOGE("epoll_wait failed (errno=%d)", errno);
717 continue;
718 }
719
720 for (i = 0; i < nevents; ++i) {
721 if (events[i].events & EPOLLERR)
722 ALOGD("EPOLLERR on event #%d", i);
723 if (events[i].data.ptr)
724 (*(void (*)(uint32_t))events[i].data.ptr)(events[i].events);
725 }
726 }
727}
728
729int main(int argc, char **argv) {
730 if (!init())
731 mainloop();
732
733 ALOGI("exiting");
734 return 0;
735}