1 如何避免app被lmk杀掉
公司的项目可能有一些核心app(java app或native app),不想因为low memory被lmk杀掉。
粗糙一些的做法是在lmkd中添加白名单,白名单的应用永远不会被lmkd杀死。
// lmkd.c
static int kill_one_process(struct proc* procp, int min_oom_score) {
...
taskname = proc_get_name(pid);
if (!taskname) {
goto out;
}
tasksize = proc_get_size(pid);
if (tasksize <= 0) {
goto out;
}
// 自己实现的is_in_white_list函数
if (is_in_white_list(taskname)) {
ALOGI("%s (%d) in the white list.", taskname, pid);
goto out;
}
...
out:
pid_remove(pid);
return result;
}
上面代码是使用白名单的位置。
2 动态添加lmkd白名单
我的平台是Android 10的版本。
遵循第1节的思路,还是添加白名单。但是要求动态添加,就需要lmkd暴露一个接口。
参考原生Android的实现,java层是通过ProcessList这样一个class和lmkd,通过local socket进行通信的。
所以我添加了一个新的cmd,从ProcessList向lmkd发送字符串(包名,即白名单)。
这里说一下lmkd中init的时候,使用了epoll的机制,我的理解就是epoll会向内核注册,内核负责监听fd(如socket的fd),fd有变化了才会通知lmkd。
这里就有一个问题:
// lmkd.h
/*
* Max number of targets in LMK_TARGET command.
*/
#define MAX_TARGETS 6
/*
* Max packet length in bytes.
* Longest packet is LMK_TARGET followed by MAX_TARGETS
* of minfree and oom_adj_score values
*/
#define CTRL_PACKET_MAX_SIZE (sizeof(int) * (MAX_TARGETS * 2 + 1))
/* LMKD packet - first int is lmk_cmd followed by payload */
typedef int LMKD_CTRL_PACKET[CTRL_PACKET_MAX_SIZE / sizeof(int)];
// lmkd.c
static void ctrl_command_handler(int dsock_idx) {
LMKD_CTRL_PACKET packet;
int len;
len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE);
...
}
简单来说,问题就是,原生用于读socket的buffer size太小了,
buffer size = 4 *(6 * 2 + 1) = 52 字节
减去同于标识cmd的int的大小,最多可以用的pay load的大小就是48字节,用来传递包名有可能就不够用。
而epoll机制又要求你只能read一次fd,如果想第二次read,内核不通知fd有变化,read函数就会一直阻塞。
经过分析代码,可以对数据结构LMKD_CTRL_PACKET
进行扩容:
#define MAX_TARGETS_EXT 16
#define CTRL_PACKET_MAX_SIZE (sizeof(int) * (MAX_TARGETS_EXT * 2 + 1))
这样方案是可行的。
另外,动态白名单我想用支持动态扩容的容器存放。但是Android 10中,lmkd的源码是.c的后缀,没办法用c++的set容器。这里需要从c代码调到cpp代码。Android 12,lmk使用c++写的,可能不存在这个问题。
标签:CTRL,int,MAX,PACKET,lmkd,避免,白名单 From: https://www.cnblogs.com/yulisuo/p/17464204.html