如何避免重要app进程被系统lmk-lowmemorykiller杀掉-实战源码

背景:

经常在系统内存出现低内存不够情况下会触发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实战干货,请关注下面“千里马学框架”

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值