Compare commits

..

42 Commits

Author SHA1 Message Date
Martin Liu 767ae2336a lmkd: Introduce update zoneinfo memevent
This change adds support for the zoneinfo memevent, allowing lmkd
to react to memory zone changes and update watermarks dynamically,
reducing the need for polling.

Polling is retained as a fallback for kernels without support.

Bug: 396115949
Test: build and verify on kernel with/without memevent supported
Change-Id: I7bc746a0e9dbdc48cfaf80c38c2ead5b5116d20b
Merged-In: I7bc746a0e9dbdc48cfaf80c38c2ead5b5116d20b
Signed-off-by: Martin Liu <liumartin@google.com>
2025-03-23 06:35:16 +00:00
Greg Kaiser 4636a7dcd5 lmkd: Update documentation of a couple defaults
We updated a couple of these default values in the code in previous CLs:
- https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/1358623
- https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/1314688

We now update the README.md to reflect those code changes.

Bug: 405461921
Test: N/A
Change-Id: If802c1cbd9bcc0a88fc7870213b98ef062676d58
2025-03-21 15:57:14 -07:00
Greg Kaiser e51c5fead2 lmkd: Speed up proc_get_heaviest() in one case
When a proc list for an oomadj is non-empty, we currently read
from disk to get the size of every process in our list, so we
can know which is the largest/heaviest process.

However, if there's only a single process in our list, we already
know it's going to be our heaviest [*].  So we don't need to do
the (relatively expensive) disk access to figure out its size,
and can just directly return this process.

[*] There's the case where our attempt to read from /proc fails
for the process.  The old code would then instantly remove this
stale pid (and return NULL if that was the only process in the
list).  This new code will end up returning this stale process
instead.  Since proc_get_heaviest() is meant to be used in the
same way as proc_adj_tail(), and proc_adj_tail() returns
processes without checking if they are stale, we don't consider
this an issue.  (Note that in the current code, the only calling
site of proc_get_heaviest() will remove this stale process when
it calls kill_one_process().)

Bug: 405391096
Test: TreeHugger
Change-Id: Iaf2f5c57dcbf2d4e45c2545a8322736b5985337c
2025-03-21 10:25:45 -07:00
Martin Liu 7f1fb15cb7 lmkd: Introduce vendor lmk kill memevent am: 3a3d11f70a
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3489410

Change-Id: I481e6a558e520771369917c5fdf74a59b25020da
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2025-02-12 17:31:54 -08:00
Martin Liu 3a3d11f70a lmkd: Introduce vendor lmk kill memevent
This change allows vendors to trigger LMKD kill events with custom
reasons and minimum score adjustments. This enables experimentation
with custom heuristics and data collection for evaluation before
upstreaming changes to AOSP.

Bug: 385050909
Test: build and check the vendor kill event
Change-Id: If9b51ed9603f0e10e6fc4671fb6da26548f41aaf
Merged-In: If9b51ed9603f0e10e6fc4671fb6da26548f41aaf
Signed-off-by: Martin Liu <liumartin@google.com>
2025-02-11 14:21:57 +00:00
Treehugger Robot da6d947875 Merge "[Native Lint] Destination buffer is not null terminated explicitly. (strncpy)" into main am: 98ebe895e4
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3282994

Change-Id: Icfc5a72138a8a64fa24f1fff1261ed9b91f988db
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2025-01-16 10:56:40 -08:00
Treehugger Robot 98ebe895e4 Merge "[Native Lint] Destination buffer is not null terminated explicitly. (strncpy)" into main 2025-01-16 10:25:35 -08:00
Suren Baghdasaryan 810b69632d lmkd: fallback to reading procfs stats when failing to read cgroup stats am: dcd968db5e
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3454703

Change-Id: Ie11f16434a6192cceb2bbafd82a22931c29e93b9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2025-01-15 15:39:05 -08:00
Suren Baghdasaryan dcd968db5e lmkd: fallback to reading procfs stats when failing to read cgroup stats
If cgroup interface is unavailable and can't be used to obtain memory
stats we can fall back to reading procfs stats. Such failure would
indicate a misconfigured device with ro.config.per_app_memcg set but
memory cgroup not being mounted or enabled correctly. However stats
reporting should not suffer because of this misconfiguration. Allow
lmkd to fall back to reading stats from procfs interface when this
happens.

Bug: 388926998
Change-Id: Idfc777022c842b45a2640f04edb70de7ca6feac8
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
2025-01-15 13:32:43 -08:00
Abdelrahman Daim 96f09654e4 [Native Lint] Destination buffer is not null terminated explicitly. (strncpy)
Summary: As a good practice, let's make sure that the "kill_desc" buffer is always null-terminated, even if its size changes in the future.

Test: Successful build on master.

Change-Id: I68a0dc346ea26126a1581994f9c508980a6ac408
Signed-off-by: Abdelrahman Daim <adaim@meta.com>
2025-01-08 04:08:23 -08:00
Elliott Hughes 9201a73bba Stop redefining __NR_process_mrelease. am: 50e484b980 am: efa3f840cf
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3390119

Change-Id: I820ec03b21398202a0310440ace09cd8b4a69034
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-12-04 15:57:23 +00:00
Elliott Hughes efa3f840cf Stop redefining __NR_process_mrelease. am: 50e484b980
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3390119

Change-Id: Id3d0bffe3836b81e1afb83a0d9f07b83109c238a
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-12-04 15:21:14 +00:00
Elliott Hughes 50e484b980 Stop redefining __NR_process_mrelease.
Change-Id: Icc7ba982b3f47802685e8af40045367c627bf133
2024-12-03 19:13:32 +00:00
Treehugger Robot 6353dc6926 Merge "lmkd: count the number of times LMKD wakes up" into main am: 6a886a90ae am: 0b971a7057
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3259917

Change-Id: I3cfd3e6eb072b87201bb02a37ce1b35bf6065931
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-11-19 18:39:33 +00:00
Treehugger Robot 0b971a7057 Merge "lmkd: count the number of times LMKD wakes up" into main am: 6a886a90ae
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3259917

Change-Id: I5e53f6a45862babc5cdb0c47f8b532a1681124ac
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-11-19 17:52:58 +00:00
Treehugger Robot 6a886a90ae Merge "lmkd: count the number of times LMKD wakes up" into main 2024-11-19 17:29:23 +00:00
Treehugger Robot c2c7eb96e8 Merge "lmkd: Fix first poll of an event occuring sooner than intended." into main am: c1104f8127 am: b4a726f7a3
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3333495

Change-Id: I55c13586d691217977fd9510ec4b5d5648f9c477
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-11-19 01:57:52 +00:00
Divyanand Rangu ce5bc38327 lmkd: fix higher event being reset by lower and polling start am: c7eca43006 am: 534bf94822
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3322634

Change-Id: I7a7a4c767384868cfd4bb909941db83c8d480886
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-11-19 01:56:30 +00:00
Treehugger Robot b4a726f7a3 Merge "lmkd: Fix first poll of an event occuring sooner than intended." into main am: c1104f8127
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3333495

Change-Id: I8dd0c81573fae5a116c2846f843d7d1d59cf7aa1
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-11-19 01:34:48 +00:00
Divyanand Rangu 534bf94822 lmkd: fix higher event being reset by lower and polling start am: c7eca43006
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3322634

Change-Id: I4056be703d748fe559b0f41cdeec20cd790d4b6f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-11-19 01:34:02 +00:00
Treehugger Robot c1104f8127 Merge "lmkd: Fix first poll of an event occuring sooner than intended." into main 2024-11-19 01:22:56 +00:00
JohnHsu a63948e455 lmkd: count the number of times LMKD wakes up
LMKD was woken up when the memory pressure was high enough either in
either the psi or the vmpressure mechanism. The memory reclaim ability
is based on CPUs' capacity of a chip and it is different from each
others. This patch can count the number of lmkd wake up when meet the
memory pressure threshold instead of heavy-loading logging. To show the
count, we can just re-init the lmkd, and it will print in the android
logcat and reset the count to zero.

Test: Run APP rotation

Bug: 365748420
Signed-off-by: JohnHsu <john.hsu@mediatek.com>
Change-Id: I3980d2a90a910c64449b4ad2b005e4d0437097e8
2024-11-13 16:41:18 +08:00
Divyanand Rangu c7eca43006 lmkd: fix higher event being reset by lower and polling start
When both Medium and Critical events occur at same time,
depending on how the events are queued, the later event
resets the former event.
We'd want the subsequent polling (till next event is triggered)
to happen with higher event.
So, it is fine if Critical event overrides Medium, but not other
way around.

Let's see below scenario where both Medium and Critical events
occur (at T0) and handled one after other
T0: critical event handled.
T0 + 2ms: medium event handled.
T0 + 102ms: medium event polling check. //This should be critical poll

Bug: 376003899
Change-Id: I16ff3b999d7531435324a628ac17968fd4cae8cf
2024-11-06 23:37:41 +05:30
Divyanand Rangu d155efb41b lmkd: Fix first poll of an event occuring sooner than intended.
When a new event occurs (could be of same level or different,
doesn't matter) after a event-poll is handled, poll of new event
waits only for "100ms - time since last poll is handled".
But new poll should start after 100ms of last triggered event.
T0: event-1 triggered.
T100: event-1 polled
T120: event-2 triggered.
T200: event-2 polled. (This poll should happen 100ms after T120, i.e., T220)

Bug: 377418039
Change-Id: I10aace061668adfed2594581b94cb9f1e745820b
2024-11-05 13:47:16 +05:30
Xin Li 3cc43abcbf [automerger skipped] Mark 24Q4 as merged in aosp-main-future am: 1bea3fe953 -s ours
am skip reason: Merged-In I5f002ab4b6968aceacf342e0424a4b0e3dc260e9 with SHA-1 853e5ac45a is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/system/memory/lmkd/+/29935384

Change-Id: I6b983a24c306ce7bb69c3c6200476a6ba0339864
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-10-19 22:40:56 +00:00
Xin Li 1bea3fe953 Mark 24Q4 as merged in aosp-main-future
Bug: 373937381
Merged-In: I5f002ab4b6968aceacf342e0424a4b0e3dc260e9
Change-Id: I5e5ba692fc340f3c5633b73803c79ce59d0b7fc6
2024-10-17 11:03:40 -07:00
Jaskaran Singh 853e5ac45a lmkd: Ensure node stats are being parsed am: f32fe4d7d3 am: 811f97adba
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/2719093

Change-Id: I5f002ab4b6968aceacf342e0424a4b0e3dc260e9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-10-17 08:20:25 +00:00
Jaskaran Singh 811f97adba lmkd: Ensure node stats are being parsed am: f32fe4d7d3
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/2719093

Change-Id: I55a7f2f4aaf07fd589fac07cf5bbdd06485c6c97
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-10-17 07:57:22 +00:00
Jaskaran Singh f32fe4d7d3 lmkd: Ensure node stats are being parsed
The kernel will print node stats within the first populated zone in the
zoneinfo file. The LMKD tries parsing node stats when it reads the first
"Node %d, zone %8s" line in zoneinfo.

However if the first zone is empty, LMKD could iterate over to the next
populated zone i.e. the next "Node %d, zone %8s" line while attempting
to read node stats. It thus reads the incorrect zone name for this next
zone.

To fix this, ensure whether node stats are indeed being parsed by
checking for the "  per node-stats" line.

Bug: 292476676
Change-Id: I72cd111dac9032de506e1ab7f1c4dc96585a1e80
Signed-off-by: Jaskaran Singh <quic_jasksing@quicinc.com>
2024-10-16 15:36:51 +00:00
Suren Baghdasaryan 9d0787ef90 lmkd: fix handling of EPOLLHUP for pidfd am: 667fdbfe92 am: b018e55b7b
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3268491

Change-Id: I613ee58987d09da8aa418c124aaf32e19824c868
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-09-26 09:26:16 +00:00
Suren Baghdasaryan b018e55b7b lmkd: fix handling of EPOLLHUP for pidfd am: 667fdbfe92
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3268491

Change-Id: I5269030e5878ed1ed1c3926dc9e73411a5a1c7a3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-09-26 09:09:02 +00:00
Suren Baghdasaryan 667fdbfe92 lmkd: fix handling of EPOLLHUP for pidfd
Recent kernel change [1] cause pidfd_wait() to receive EPOLLHUP when the
task exits. Current LMKD implementation expects to receive EPOLLHUP only
when socket connection gets dropped, therefore it gets confused by this
new kernel behavior. Adjust LMKD handling of EPOLLHUP to detect the case
when this event is generated by pidfd.

[1] https://lore.kernel.org/all/20240202131226.GA26018@redhat.com/

Bug: 352286227
Change-Id: Ibcf349ee3cc73551541d64975f0292d53c41d5c2
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
2024-09-13 23:43:47 +00:00
David Stevens 7dff130d87 lmkd: Add hook for when there are no killable processes am: d256df3c5f am: 1683221f0d
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3249594

Change-Id: Ica82748265304f240cff3e2dc570fa12e9db4ac1
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-08-29 15:50:21 +00:00
Carlos Galo a54cb7c846 Revert "Adding io_uring for batching PROCS_PRIO cmd" am: 4c589f32f5 am: 760b3e2d40
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3226117

Change-Id: I3e5be93395a015ee19d79eacbbc3f315fd955626
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-08-20 21:44:50 +00:00
Suren Baghdasaryan 2606f9849b lmkd/tests: add 200ms wait for reaper to output its logs am: 753642e31a am: cad7196508
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3134321

Change-Id: I5e0ecf5684489208d36f1bb93f8a3b159077ebfa
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-08-12 21:24:46 +00:00
Suren Baghdasaryan f7b4db5219 lmkd/tests: handle kill reports being confused with reap reports am: 13b5b0ce06 am: 72c26015dd
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3134320

Change-Id: I5db5a175f9fdec7c5b1d48c21148c7f7bf3fc7ce
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-08-12 21:24:43 +00:00
Christopher Ferris a818a565ff Remove unused variable. am: b1d5c43490 am: ff8b8464d1
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3208315

Change-Id: I2f62da5664d711a6e055b2ec6f4feacfc4532050
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-08-07 02:22:19 +00:00
Carlos Galo 2e78891823 Report up-to-date RSS in LMK_PROCKILL cmd am: 1e50c6ecc4 am: 36f19297e5
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3164830

Change-Id: I5c7920d074c8c984595098b077fac2f58ca89803
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-07-24 20:22:21 +00:00
Treehugger Robot 540ed179a7 Merge "Remove usage of BPF_FD_JUST_USE_INT in favor of unique_fd" into main am: 0aeff477af am: 8e4290acac
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3133997

Change-Id: I1d6c3e4db93f4b5c21548fecabdd193a5b3e2d61
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-07-12 21:37:00 +00:00
Martin Liu 573cc5af1b lmkd: handle missing process' information case am: d10742025b am: eec2abfee7
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3150836

Change-Id: Ibf44e7ba338eea663b0c35d77c49c3e2d8679a3e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-06-27 22:07:16 +00:00
Suren Baghdasaryan cee3c2d01e Revert "lmkd: change default lowmem_min_oom_score for low-RAM devices" am: ee6412ebf0 am: 61adbf3b67
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3147096

Change-Id: I2ea9d2a9b877f966062fe9dee25e7e360f1b7ed0
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-06-25 22:35:07 +00:00
Suren Baghdasaryan 14f5d615b5 lmkd: change default lowmem_min_oom_score for low-RAM devices am: 686abc4e2b am: c98f8bdf4d
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/3123213

Change-Id: Id7c41a22d0d8f979348eec8cf972ddeba2b9c2e7
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2024-06-24 17:45:31 +00:00
6 changed files with 152 additions and 33 deletions

View File

@ -88,6 +88,10 @@ cc_library_static {
"liblog",
"libprocessgroup",
],
header_libs: [
"libmemevents_headers",
"libbase_headers",
],
}
cc_library_static {

View File

@ -60,14 +60,13 @@ properties:
any eligible task (fast decision). Default = false
- `ro.lmk.kill_timeout_ms`: duration in ms after a kill when no additional
kill will be done. Default = 0 (disabled)
kill will be done. Default = 100
- `ro.lmk.debug`: enable lmkd debug logs, Default = false
- `ro.lmk.swap_free_low_percentage`: level of free swap as a percentage of the
total swap space used as a threshold to consider
the system as swap space starved. Default for
low-RAM devices = 10, for high-end devices = 20
the system as swap space starved. Default = 10
- `ro.lmk.thrashing_limit`: number of workingset refaults as a percentage of
the file-backed pagecache size used as a threshold

149
lmkd.cpp
View File

@ -94,6 +94,7 @@ static inline void trace_kill_end() {}
#define PROC_STATUS_TGID_FIELD "Tgid:"
#define PROC_STATUS_RSS_FIELD "VmRSS:"
#define PROC_STATUS_SWAP_FIELD "VmSwap:"
#define NODE_STATS_MARKER " per-node stats"
#define PERCEPTIBLE_APP_ADJ 200
#define PREVIOUS_APP_ADJ 700
@ -210,8 +211,10 @@ static int mpevfd[VMPRESS_LEVEL_COUNT] = { -1, -1, -1 };
static bool pidfd_supported;
static int last_kill_pid_or_fd = -1;
static struct timespec last_kill_tm;
enum vmpressure_level prev_level = VMPRESS_LEVEL_LOW;
static bool monitors_initialized;
static bool boot_completed_handled = false;
static bool mem_event_update_zoneinfo_supported;
/* lmkd configurable parameters */
static bool debug_process_killing;
@ -245,6 +248,8 @@ static struct psi_threshold psi_thresholds[VMPRESS_LEVEL_COUNT] = {
{ PSI_FULL, 70 }, /* 70ms out of 1sec for complete stall */
};
static uint64_t mp_event_count;
static android_log_context ctx;
static Reaper reaper;
static int reaper_comm_fd[2];
@ -1859,6 +1864,15 @@ static int zoneinfo_parse(struct zoneinfo *zi) {
int node_id;
if (sscanf(line, "Node %d, zone %" STRINGIFY(LINE_MAX) "s", &node_id, zone_name) == 2) {
if (!node || node->id != node_id) {
line = strtok_r(NULL, "\n", &save_ptr);
if (strncmp(line, NODE_STATS_MARKER, strlen(NODE_STATS_MARKER)) != 0) {
/*
* per-node stats are only present in the first non-empty zone of
* the node.
*/
continue;
}
/* new node is found */
if (node) {
node->zone_count = zone_idx + 1;
@ -2220,6 +2234,10 @@ static struct proc *proc_get_heaviest(int oomadj) {
struct adjslot_list *curr = head->next;
struct proc *maxprocp = NULL;
int maxsize = 0;
if ((curr != head) && (curr->next == head)) {
// Our list only has one process.  No need to access procfs for its size.
return (struct proc *)curr;
}
while (curr != head) {
int pid = ((struct proc *)curr)->pid;
int tasksize = proc_get_size(pid);
@ -2625,6 +2643,8 @@ struct zone_watermarks {
long min_wmark;
};
static struct zone_watermarks watermarks;
/*
* Returns lowest breached watermark or WMARK_NONE.
*/
@ -2664,6 +2684,15 @@ void calc_zone_watermarks(struct zoneinfo *zi, struct zone_watermarks *watermark
}
}
static int update_zoneinfo_watermarks(struct zoneinfo *zi) {
if (zoneinfo_parse(zi) < 0) {
ALOGE("Failed to parse zoneinfo!");
return -1;
}
calc_zone_watermarks(zi, &watermarks);
return 0;
}
static int calc_swap_utilization(union meminfo *mi) {
int64_t swap_used = mi->field.total_swap - get_free_swap(mi);
int64_t total_swappable = mi->field.active_anon + mi->field.inactive_anon +
@ -2671,7 +2700,18 @@ static int calc_swap_utilization(union meminfo *mi) {
return total_swappable > 0 ? (swap_used * 100) / total_swappable : 0;
}
static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_params) {
enum event_source {
PSI,
VENDOR,
};
union psi_event_data {
enum vmpressure_level level;
mem_event_t vendor_event;
};
static void __mp_event_psi(enum event_source source, union psi_event_data data,
uint32_t events, struct polling_params *poll_params) {
enum reclaim_state {
NO_RECLAIM = 0,
KSWAPD_RECLAIM,
@ -2685,7 +2725,6 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
static int64_t init_pgrefill;
static bool killing;
static int thrashing_limit = thrashing_limit_pct;
static struct zone_watermarks watermarks;
static struct timespec wmark_update_tm;
static struct wakeup_info wi;
static struct timespec thrashing_reset_tm;
@ -2699,7 +2738,7 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
struct timespec curr_tm;
int64_t thrashing = 0;
bool swap_is_low = false;
enum vmpressure_level level = (enum vmpressure_level)data;
enum vmpressure_level level = (source == PSI) ? data.level: (enum vmpressure_level)0;
enum kill_reasons kill_reason = NONE;
bool cycle_after_kill = false;
enum reclaim_state reclaim = NO_RECLAIM;
@ -2716,12 +2755,37 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
long direct_reclaim_duration_ms;
bool in_kswapd_reclaim;
mp_event_count++;
if (debug_process_killing) {
if (source == PSI)
ALOGI("%s memory pressure event #%" PRIu64 " is triggered",
level_name[level], mp_event_count);
else
ALOGI("vendor kill event #%" PRIu64 " is triggered", mp_event_count);
}
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
ALOGE("Failed to get current time");
return;
}
if (source == PSI) {
if (events > 0 ) {
/* Ignore a lower event within the first polling window. */
if (level < prev_level) {
if (debug_process_killing)
ALOGI("Ignoring %s pressure event; occurred too soon.",
level_name[level]);
return;
}
prev_level = level;
} else {
/* Reset event level after the first polling window. */
prev_level = VMPRESS_LEVEL_LOW;
}
record_wakeup_time(&curr_tm, events ? Event : Polling, &wi);
}
bool kill_pending = is_kill_pending();
if (kill_pending && (kill_timeout_ms == 0 ||
@ -2788,7 +2852,8 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
init_pgscan_kswapd = vs.field.pgscan_kswapd;
init_pgrefill = vs.field.pgrefill;
reclaim = KSWAPD_RECLAIM;
} else if (workingset_refault_file == prev_workingset_refault) {
} else if ((workingset_refault_file == prev_workingset_refault) &&
(source == PSI)) {
/*
* Device is not thrashing and not reclaiming, bail out early until we see these stats
* changing
@ -2842,19 +2907,18 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
update_watermarks:
/*
* Refresh watermarks once per min in case user updated one of the margins.
* TODO: b/140521024 replace this periodic update with an API for AMS to notify LMKD
* that zone watermarks were changed by the system software.
* Refresh watermarks:
* 1. watermarks haven't been initialized (high_wmark == 0)
* 2. per min in case user updated one of the margins if mem_event update_zoneinfo is NOT
* supported.
*/
if (watermarks.high_wmark == 0 || get_time_diff_ms(&wmark_update_tm, &curr_tm) > 60000) {
if (watermarks.high_wmark == 0 || (!mem_event_update_zoneinfo_supported &&
get_time_diff_ms(&wmark_update_tm, &curr_tm) > 60000)) {
struct zoneinfo zi;
if (zoneinfo_parse(&zi) < 0) {
ALOGE("Failed to parse zoneinfo!");
if (update_zoneinfo_watermarks(&zi) < 0) {
return;
}
calc_zone_watermarks(&zi, &watermarks);
wmark_update_tm = curr_tm;
}
@ -2868,7 +2932,23 @@ update_watermarks:
* TODO: move this logic into a separate function
* Decide if killing a process is necessary and record the reason
*/
if (cycle_after_kill && wmark < WMARK_LOW) {
if (source == VENDOR) {
int vendor_kill_reason = data.vendor_event.event_data.vendor_kill.reason;
short vendor_kill_min_oom_score_adj =
data.vendor_event.event_data.vendor_kill.min_oom_score_adj;
if (vendor_kill_reason < 0 ||
vendor_kill_reason > VENDOR_KILL_REASON_END ||
vendor_kill_min_oom_score_adj < 0) {
ALOGE("Invalid vendor kill reason %d, min_oom_score_adj %d",
vendor_kill_reason, vendor_kill_min_oom_score_adj);
return;
}
kill_reason = (enum kill_reasons)(vendor_kill_reason + VENDOR_KILL_REASON_BASE);
min_score_adj = vendor_kill_min_oom_score_adj;
snprintf(kill_desc, sizeof(kill_desc),
"vendor kill with the reason %d, min_score_adj %d", kill_reason, min_score_adj);
} else if (cycle_after_kill && wmark < WMARK_LOW) {
/*
* Prevent kills not freeing enough memory which might lead to OOM kill.
* This might happen when a process is consuming memory faster than reclaim can
@ -2877,6 +2957,7 @@ update_watermarks:
min_score_adj = pressure_after_kill_min_score;
kill_reason = PRESSURE_AFTER_KILL;
strncpy(kill_desc, "min watermark is breached even after kill", sizeof(kill_desc));
kill_desc[sizeof(kill_desc) - 1] = '\0';
} else if (level == VMPRESS_LEVEL_CRITICAL && events != 0) {
/*
* Device is too busy reclaiming memory which might lead to ANR.
@ -2885,6 +2966,7 @@ update_watermarks:
*/
kill_reason = NOT_RESPONDING;
strncpy(kill_desc, "device is not responding", sizeof(kill_desc));
kill_desc[sizeof(kill_desc) - 1] = '\0';
} else if (swap_is_low && thrashing > thrashing_limit_pct) {
/* Page cache is thrashing while swap is low */
kill_reason = LOW_SWAP_AND_THRASHING;
@ -3032,6 +3114,11 @@ no_kill:
}
}
static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_params) {
union psi_event_data event_data = {.level = (enum vmpressure_level)data};
__mp_event_psi(PSI, event_data, events, poll_params);
}
static std::string GetCgroupAttributePath(const char* attr) {
std::string path;
if (!CgroupGetAttributePath(attr, &path)) {
@ -3066,8 +3153,10 @@ static void mp_event_common(int data, uint32_t events, struct polling_params *po
};
static struct wakeup_info wi;
mp_event_count++;
if (debug_process_killing) {
ALOGI("%s memory pressure event is triggered", level_name[level]);
ALOGI("%s memory pressure event #%" PRIu64 " is triggered",
level_name[level], mp_event_count);
}
if (!use_psi_monitors) {
@ -3354,7 +3443,7 @@ static MemcgVersion memcg_version() {
}
static void memevent_listener_notification(int data __unused, uint32_t events __unused,
struct polling_params* poll_params __unused) {
struct polling_params* poll_params) {
struct timespec curr_tm;
std::vector<mem_event_t> mem_events;
@ -3391,6 +3480,16 @@ static void memevent_listener_notification(int data __unused, uint32_t events __
kswapd_start_tm.tv_sec = 0;
kswapd_start_tm.tv_nsec = 0;
break;
case MEM_EVENT_VENDOR_LMK_KILL: {
union psi_event_data event_data = {.vendor_event = mem_event};
__mp_event_psi(VENDOR, event_data, 0, poll_params);
break;
}
case MEM_EVENT_UPDATE_ZONEINFO: {
struct zoneinfo zi;
update_zoneinfo_watermarks(&zi);
break;
}
}
}
}
@ -3425,6 +3524,17 @@ static bool init_memevent_listener_monitoring() {
return false;
}
if (!memevent_listener->registerEvent(MEM_EVENT_VENDOR_LMK_KILL)) {
ALOGI("Failed to register android_vendor_kill memevents");
}
if (!memevent_listener->registerEvent(MEM_EVENT_UPDATE_ZONEINFO)) {
mem_event_update_zoneinfo_supported = false;
ALOGI("update_zoneinfo memevents are not supported");
} else {
mem_event_update_zoneinfo_supported = true;
}
int memevent_listener_fd = memevent_listener->getRingBufferFd();
if (memevent_listener_fd < 0) {
memevent_listener.reset();
@ -3582,6 +3692,8 @@ static void kernel_event_handler(int data __unused, uint32_t events __unused,
}
static bool init_monitors() {
ALOGI("Wakeup counter is reset from %" PRIu64 " to 0", mp_event_count);
mp_event_count = 0;
/* Try to use psi monitor first if kernel has it */
use_psi_monitors = GET_LMK_PROPERTY(bool, "use_psi", true) &&
init_psi_monitors();
@ -3815,6 +3927,7 @@ static void call_handler(struct event_handler_info* handler_info,
*/
poll_params->poll_start_tm = curr_tm;
poll_params->poll_handler = handler_info;
poll_params->last_poll_tm = curr_tm;
break;
case POLLING_PAUSE:
poll_params->paused_handler = handler_info;
@ -3911,13 +4024,17 @@ static void mainloop(void) {
*/
for (i = 0, evt = &events[0]; i < nevents; ++i, evt++) {
if ((evt->events & EPOLLHUP) && evt->data.ptr) {
ALOGI("lmkd data connection dropped");
handler_info = (struct event_handler_info*)evt->data.ptr;
if (handler_info->handler == kill_done_handler) {
call_handler(handler_info, &poll_params, evt->events);
} else {
ALOGI("lmkd data connection dropped");
watchdog.start();
ctrl_data_close(handler_info->data);
watchdog.stop();
}
}
}
/* Second pass to handle all other events */
for (i = 0, evt = &events[0]; i < nevents; ++i, evt++) {

View File

@ -158,13 +158,12 @@ struct memory_stat *stats_read_memory_stat(bool per_app_memcg, int pid, uid_t ui
if (memory_stat_from_cgroup(&mem_st, pid, uid) == 0) {
return &mem_st;
}
} else {
}
if (memory_stat_from_procfs(&mem_st, pid) == 0) {
mem_st.rss_in_bytes = rss_bytes;
mem_st.swap_in_bytes = swap_bytes;
return &mem_st;
}
}
return NULL;
}

View File

@ -26,6 +26,7 @@
#include <sys/types.h>
#include <cutils/properties.h>
#include <memevents/memevents.h>
__BEGIN_DECLS
@ -66,6 +67,9 @@ enum kill_reasons {
LOW_FILECACHE_AFTER_THRASHING,
LOW_MEM,
DIRECT_RECL_STUCK,
/* reserve aosp kill 0 ~ 999 */
VENDOR_KILL_REASON_BASE = 1000,
VENDOR_KILL_REASON_END = VENDOR_KILL_REASON_BASE + NUM_VENDOR_LMK_KILL_REASON - 1,
KILL_REASON_COUNT
};

View File

@ -30,10 +30,6 @@
using namespace android::base;
#ifndef __NR_process_mrelease
#define __NR_process_mrelease 448
#endif
#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
#define LMKD_LOGCAT_MARKER "lowmemorykiller"