背景:
经常在系统内存出现低内存不够情况下会触发low memory kill掉相关的应用进程,其实本来这个就是系统的一种自我保护机制,lmk目的是为了保护系统的正常运行,根据系统内存情况和系统应用的优先级adj值,然后杀掉哪些adj值高的系统应用,adj值高代表优先级低。
但是有时候有一些客户需求场景等,就不希望自己系统应用被任何原因杀,针对这样的需求系统是否可以实现呢?是否可以排除自己的系统应用不被lmk杀呢?
答案当然是可以的。
(注意:虽然下面会给大家介绍相关的方案,但是还是建议大家要非常慎重使用该方案,一般情况下不要让自己系统应用不被杀,而是应该考虑完善自己系统应用功能,哪怕被杀了也可以正常保留相关数据和及时重启)
lmk杀进程相关知识
这块知识整体比较复杂,不过总结一下主要就分为以下几个部分:
1、systemserver进程的AMS,它的职责是:策略收集并更新各个app进程的adj值,并且把各个进程adj值通过socket传递给远端守护进程lmkd
2、远端lmkd守护进程,这块其实分为两个新老版本阶段
在老版本安卓kernel是有lmk模块,所以lmkd其实不负责任何的杀进程动作,只负责写入相关的进程adj值到字节节点
新版本安卓kernel统一没有了lmk模块,这个时候lmkd就需要负责相关的检查内存,遍历进程,杀进程等业务

那么这里大家了解整个lmk的杀进程流程后,如果你想你的进程不被杀应该在哪里进行处理呢?
可能大家都会想到如下两种方案:
1、让system_server进程针对对应包名把adj值强制调低,但是这样可能只能说大大提升自己不被杀概率
2、在lmkd守护进程中会执行真正的kill进程操作,那么是否可以在kill进程时候进行相关的白名单判断,然后过滤不让lmkd进行最后的kill操作。
相比彻底性而言肯定选方案2。
白名单方式避免进程被lmkd守护进程kill
lmkd进程代码修改点:
system/memory/lmkd/lmkd.cpp
最后杀进程会通过如下方法kill_one_process
/* Kill one process specified by procp. Returns the size (in pages) of the process killed */
static int kill_one_process(struct proc* procp, int min_oom_score, struct kill_info *ki,
union meminfo *mi, struct wakeup_info *wi, struct timespec *tm,
struct psi_data *pd) {
int pid = procp->pid;
int pidfd = procp->pidfd;
uid_t uid = procp->uid;
char *taskname;
int kill_result;
int result = -1;
struct memory_stat *mem_st;
struct kill_stat kill_st;
int64_t tgid;
int64_t rss_kb;
int64_t swap_kb;
char buf[PAGE_SIZE];
char desc[LINE_MAX];
if (!procp->valid || !read_proc_status(pid, buf, sizeof(buf))) {
goto out;
}
if (!parse_status_tag(buf, PROC_STATUS_TGID_FIELD, &tgid)) {
ALOGE("Unable to parse tgid from /proc/%d/status", pid);
goto out;
}
if (tgid != pid) {
ALOGE("Possible pid reuse detected (pid %d, tgid %" PRId64 ")!", pid, tgid);
goto out;
}
// Zombie processes will not have RSS / Swap fields.
if (!parse_status_tag(buf, PROC_STATUS_RSS_FIELD, &rss_kb)) {
goto out;
}
if (!parse_status_tag(buf, PROC_STATUS_SWAP_FIELD, &swap_kb)) {
goto out;
}
//这里会获取对应的进程名字
taskname = proc_get_name(pid, buf, sizeof(buf));
// taskname will point inside buf, do not reuse buf onwards.
if (!taskname) {
goto out;
}
//添加的判断白名单部分,看看taskname是否位于白名单中
if (is_in_white_list(taskname)) {
ALOGE(" not kill_one_process is_in_white_list taskname %s",taskname);
goto out;
}
//..省略部分
下面再看看is_in_white_list方法
bool is_in_white_list(char* task_name) {
char buf[500] = {};
int len = property_get("debug.whitelist.taskname", buf, "");
if (len > 0) {
if (strstr(buf,task_name)) {
ALOGE("is_in_white_list buf %s contain of task_name %s", buf,task_name);
return true;
}
}
return false;
}
这个方法非常简单,就是对相关属性进行获取,然后与传递来的task_name进程对应的比较既可以,整体代码就是这么简单哈。
实战验证情况:
测试验证需要:
1、准备好一个内存压力测试工具,具体如何准备和使用,前面文章已经讲解了
https://mp.weixin.qq.com/s/VCRKn-cPOnUI86-xOvtQYQ
2、设置对应的白名单包名,进程名字到prop
130|emulator_x86_64:/ # setprop debug.whitelist.taskname com.android.launcher3
3、启动压力测试,查看日志或者ps -A查看launcher进程其实一直没有被kill
可以看如下视频有实战验证效果
https://www.bilibili.com/video/BV1bfAsenErg/
更多framework实战干货,请关注下面“千里马学框架”
1644

被折叠的 条评论
为什么被折叠?



