Android LMKD 服务

8 阅读13分钟

Android LMKD 服务深度解析

源码路径: system/memory/lmkd/


1. LMKD 概述

1.1 什么是 LMKD

LMKD (Low Memory Killer Daemon) 是 Android 的用户态内存压力管理守护进程,负责在系统内存不足时选择并杀死低优先级进程以释放内存。

核心职责:

  1. 进程注册与管理 - 维护所有已注册进程的优先级信息
  2. 内存压力监控 - 通过 PSI (Pressure Stall Information) 监控内存压力
  3. 进程选择与杀死 - 根据 oom_adj 值选择合适的进程进行杀死
  4. 策略配置 - 接收 Framework 的 minfree/adj 配置

1.2 LMKD 架构图

┌─────────────────────────────────────────────────────────────┐
│                    ActivityManagerService                   │
│              (OomAdjuster 计算进程 adj 值)                    │
└─────────────────────────────────────────────────────────────┘
                           │
                           │ setOomAdj(pid, uid, adj)
                           │ writeLmkd(ByteBuffer)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                    LmkdConnection (Java)                    │
│           Framework 侧 socket 连接管理                        │
│    LocalSocket → "lmkd" socket (RESERVED namespace)         │
└─────────────────────────────────────────────────────────────┘
                           │
                           │ SOCK_SEQPACKET
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                     LMKD Daemon (C++)                       │
│                  system/memory/lmkd/lmkd.cpp                │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │ Socket Handler││ PSI Monitor │  │ Process Killer│        │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
└─────────────────────────────────────────────────────────────┘
                           │
                           │ pidfd_open() + kill()
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                      Target Process                         │
│                    (被选中的低优先级进程)                       │
└─────────────────────────────────────────────────────────────┘

2. LMKD 服务启动流程

2.1 Init 配置文件 (lmkd.rc)

文件路径: system/memory/lmkd/lmkd.rc

service lmkd /system/bin/lmkd
    class core
    user lmkd
    group lmkd system readproc
    capabilities DAC_OVERRIDE KILL IPC_LOCK SYS_NICE SYS_RESOURCE
    critical
    socket lmkd seqpacket+passcred 0660 system system
    task_profiles ServiceCapacityLow

on property:lmkd.reinit=1
    exec_background /system/bin/lmkd --reinit

# 系统启动完成后重新初始化
on property:sys.boot_completed=1 && property:lmkd.reinit=0
    setprop lmkd.reinit 1

关键配置说明:

配置项说明
class core属于核心服务类,启动优先级高
user lmkd以 lmkd 用户身份运行
group lmkd system readproc允许读取进程信息
capabilitiesDAC_OVERRIDE(文件权限), KILL(杀进程), IPC_LOCK(内存锁定), SYS_NICE(调度), SYS_RESOURCE(资源限制)
socket lmkd seqpacket+passcred 0660创建 SEQPACKET 类型 socket,传递 credentials
critical关键服务,崩溃后会被重启

2.2 Socket 创建机制

Init 进程在启动 lmkd 服务时,根据 socket lmkd ... 配置自动创建 socket:

// init 进程中的 socket 创建逻辑
// socket 名称: lmkd
// 类型: SOCK_SEQPACKET (有序可靠数据包)
// 权限: 0660 (system:system 可读写)
// passcred: 发送时附带进程 credentials (uid/pid)

Socket 特性:

  • SOCK_SEQPACKET: 有序、可靠、基于连接的数据包传输
  • passcred: 每条消息附带发送者的 credentials,用于权限验证
  • Namespace RESERVED: /dev/socket/lmkd (abstract socket)

2.3 main() 函数启动流程

文件路径: system/memory/lmkd/lmkd.cpp:4234

int main(int argc, char **argv) {
    // 1. 处理重新初始化请求
    if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
        if (property_set(LMKD_REINIT_PROP, "")) {
            ALOGE("Failed to reset " LMKD_REINIT_PROP " property");
        }
        return issue_reinit();  // 向已运行的 lmkd 发送重新初始化命令
    }

    // 2. 初始化配置属性
    if (!update_props()) {
        ALOGE("Failed to initialize props, exiting.");
        return -1;
    }

    // 3. 创建日志上下文
    ctx = create_android_logger(KILLINFO_LOG_TAG);

    // 4. 初始化核心功能
    if (!init()) {
        // 用户态模式下的特殊设置
        if (!use_inkernel_interface) {
            // 锁定内存,防止被 swap (需要 CAP_IPC_LOCK)
            if (mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT) && (errno != EINVAL)) {
                ALOGW("mlockall failed %s", strerror(errno));
            }

            // 设置实时调度优先级 (需要 CAP_NICE)
            struct sched_param param = { .sched_priority = 1 };
            if (sched_setscheduler(0, SCHED_FIFO, &param)) {
                ALOGW("set SCHED_FIFO failed %s", strerror(errno));
            }
        }

        // 5. 初始化 Reaper (进程杀死线程池)
        if (init_reaper()) {
            ALOGI("Process reaper initialized with %d threads in the pool",
                reaper.thread_cnt());
        }

        // 6. 初始化 Watchdog
        if (!watchdog.init()) {
            ALOGE("Failed to initialize the watchdog");
        }

        // 7. 进入主循环
        mainloop();
    }

    android_log_destroy(&ctx);
    ALOGI("exiting");
    return 0;
}

2.4 init() 函数 - 核心初始化

文件路径: system/memory/lmkd/lmkd.cpp:3882

static int init(void) {
    // 1. 创建 epoll 实例用于事件监听
    epollfd = epoll_create(MAX_EPOLL_EVENTS);
    if (epollfd == -1) {
        ALOGE("epoll_create failed (errno=%d)", errno);
        return -1;
    }

    // 2. 初始化数据连接状态
    for (int i = 0; i < MAX_DATA_CONN; i++) {
        data_sock[i].sock = -1;  // 标记为未连接
    }

    // 3. 获取 init 创建的控制 socket ★★★ 关键步骤
    ctrl_sock.sock = android_get_control_socket("lmkd");
    if (ctrl_sock.sock < 0) {
        ALOGE("get lmkd control socket failed");
        return -1;
    }

    // 4. 开始监听连接请求
    ret = listen(ctrl_sock.sock, MAX_DATA_CONN);
    if (ret < 0) {
        ALOGE("lmkd control socket listen failed (errno=%d)", errno);
        return -1;
    }

    // 5. 注册 socket 连接事件处理器到 epoll
    epev.events = EPOLLIN;
    ctrl_sock.handler_info.handler = ctrl_connect_handler;  // 连接处理函数
    epev.data.ptr = (void *)&(ctrl_sock.handler_info);
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ctrl_sock.sock, &epev) == -1) {
        ALOGE("epoll_ctl for lmkd control socket failed (errno=%d)", errno);
        return -1;
    }
    maxevents++;

    // 6. 检查是否使用内核 LMK 接口
    has_inkernel_module = !access(INKERNEL_MINFREE_PATH, W_OK);
    use_inkernel_interface = has_inkernel_module;

    if (use_inkernel_interface) {
        ALOGI("Using in-kernel low memory killer interface");
        // 使用内核接口的初始化...
    } else {
        // 用户态模式:初始化 PSI 监控器
        if (!init_monitors()) {
            return -1;
        }
        property_set("sys.lmk.reportkills", "1");
    }

    // 7. 初始化进程优先级哈希表
    for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
        procadjslot_list[i].next = &procadjslot_list[i];
        procadjslot_list[i].prev = &procadjslot_list[i];
    }

    // 8. 检查 pidfd 支持
    pidfd = TEMP_FAILURE_RETRY(pidfd_open(getpid(), 0));
    pidfd_supported = (pidfd >= 0 || errno != ENOSYS);
    ALOGI("Process polling is %s", pidfd_supported ? "supported" : "not supported");

    return 0;
}

2.5 mainloop() - 主事件循环

文件路径: system/memory/lmkd/lmkd.cpp:4043

static void mainloop(void) {
    struct event_handler_info* handler_info;
    struct polling_params poll_params;
    struct epoll_event *evt;

    poll_params.poll_handler = NULL;
    poll_params.paused_handler = NULL;

    while (1) {  // 无限循环
        struct epoll_event events[MAX_EPOLL_EVENTS];
        int nevents;
        int i;

        // 根据 polling 状态计算超时
        if (poll_params.poll_handler) {
            // 正在 polling 内存状态
            delay = poll_params.polling_interval_ms;
            nevents = epoll_wait(epollfd, events, maxevents, delay);
        } else if (kill_timeout_ms && is_waiting_for_kill()) {
            // 等待进程死亡通知
            delay = kill_timeout_ms;
            nevents = epoll_wait(epollfd, events, maxevents, delay);
        } else {
            // 正常等待事件,无超时
            nevents = epoll_wait(epollfd, events, maxevents, -1);
        }

        if (nevents == -1) {
            if (errno == EINTR) continue;
            ALOGE("epoll_wait failed (errno=%d)", errno);
            continue;
        }

        // 第一轮:处理连接断开事件 (EPOLLHUP)
        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;
                ctrl_data_close(handler_info->data);  // 关闭数据连接
            }
        }

        // 第二轮:处理其他事件
        for (i = 0, evt = &events[0]; i < nevents; ++i, evt++) {
            if (evt->events & EPOLLHUP) continue;  // 已在第一轮处理
            if (evt->data.ptr) {
                handler_info = (struct event_handler_info*)evt->data.ptr;
                call_handler(handler_info, &poll_params, evt->events);
            }
        }
    }
}

3. Socket 通信流程

3.1 连接建立流程

┌─────────────────────────────────────────────────────────────┐
│                  Framework (ProcessList.init)               │
│           创建 LmkdConnection 对象                            │
└─────────────────────────────────────────────────────────────┘
                           │
                           │ sLmkdConnection.connect()
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                  LmkdConnection.connect()                   │
│         LmkdConnection.java:122                             │
├─────────────────────────────────────────────────────────────┤
│  1. openSocket() - 创建 LocalSocket                          │
│     socket = new LocalSocket(SOCKET_SEQPACKET)              │
│     socket.connect(new LocalSocketAddress("lmkd", RESERVED))│
│                                                             │
│  2. 获取 I/O streams                                         │
│     ostream = socket.getOutputStream()                      │
│     istream = socket.getInputStream()                       │
│                                                             │
│  3. 执行 onConnect 回调                                      │
│     mListener.onConnect(ostream)                            │
│     → onLmkdConnect() 发送初始化命令                          │
│                                                             │
│  4. 注册 FD 监听                                             │
│     mMsgQueue.addOnFileDescriptorEventListener()            │
└─────────────────────────────────────────────────────────────┘
                           │
                           │ accept() → epoll IN event
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                  ctrl_connect_handler()                     │
│         lmkd.cpp:1599                                       │
├─────────────────────────────────────────────────────────────┤
│  1. 查找空闲数据连接槽位                                        │
│     free_dscock_idx = get_free_dsock()                       │
│                                                              │
│  2. accept 新连接                                             │
│     data_sock[idx].sock = accept(ctrl_sock.sock, NULL, NULL) │
│                                                              │
│  3. 注册数据 socket 到 epoll                                   │
│     epoll_ctl(EPOLL_CTL_ADD, data_sock[idx].sock, &epev)     │
│     handler = ctrl_data_handler                              │
│                                                              │
│  ALOGI("lmkd data connection established")                   │
└─────────────────────────────────────────────────────────────┘

3.2 LmkdConnection.openSocket() 实现

文件路径: frameworks/base/services/core/java/com/android/server/am/LmkdConnection.java:249

private LocalSocket openSocket() {
    final LocalSocket socket;

    try {
        // 创建 SEQPACKET 类型 socket
        socket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
        // 连接到 lmkd socket (abstract namespace)
        socket.connect(
            new LocalSocketAddress("lmkd",
                    LocalSocketAddress.Namespace.RESERVED));
    } catch (IOException ex) {
        Slog.e(TAG, "Connection failed: " + ex.toString());
        return null;
    }
    return socket;
}

关键点:

  • SOCKET_SEQPACKET: 与 init.rc 中定义的类型一致
  • Namespace.RESERVED: 对应 /dev/socket/ 目录下的 abstract socket
  • Socket 名称 "lmkd" 由 init 进程创建

3.3 数据发送流程 (setOomAdj)

┌─────────────────────────────────────────────────────────────┐
│                  OomAdjuster.applyOomAdjLSP()               │
│              计算 adj 后调用 setOomAdj                        │
└─────────────────────────────────────────────────────────────┘
                           │
                           │ ProcessList.setOomAdj(pid, uid, amt)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                  ProcessList.setOomAdj()                    │
│         ProcessList.java:1491                               │
├─────────────────────────────────────────────────────────────┤
│  ByteBuffer buf = ByteBuffer.allocate(4 * 4);               │
│  buf.putInt(LMK_PROCPRIO);  // 命令码 = 1                    │
│  buf.putInt(pid);           // 进程 ID                       │
│  buf.putInt(uid);           // 用户 ID                      │
│  buf.putInt(amt);           // oom_adj 值 (-1000 ~ 1000)    │
│                                                             │
│  writeLmkd(buf, null);      // 发送到 lmkd                   │
└─────────────────────────────────────────────────────────────┘
                           │
                           │ LmkdConnection.write(buf)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                  LmkdConnection.write()                     │
│         LmkdConnection.java:264                             │
├─────────────────────────────────────────────────────────────┤
│  mLmkdOutputStream.write(buf.array(), 0, buf.position())    │
└─────────────────────────────────────────────────────────────┘
                           │
                           │ socket send (SEQPACKET)
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                  ctrl_data_handler()                        │
│         lmkd.cpp:1583                                       │
├─────────────────────────────────────────────────────────────┤
│  EPOLLIN 事件触发                                            │
│  → ctrl_command_handler(data)                               │
└─────────────────────────────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                  ctrl_command_handler()                     │
│         lmkd.cpp:1479                                       │
├─────────────────────────────────────────────────────────────┤
│  1. ctrl_data_read() - 读取数据包                             │
│     len = ctrl_data_read(dsock_idx, packet, size, &cred)     │
│                                                              │
│  2. 解析命令                                                  │
│     cmd = lmkd_pack_get_cmd(packet)  // LMK_PROCPRIO         │
│     nargs = len / sizeof(int) - 1                            │
│                                                              │
│  3. 根据命令类型处理                                            │
│     switch(cmd) {                                            │
│         case LMK_PROCPRIO:                                   │
│             cmd_procprio(packet, nargs, &cred);              │
│             break;                                           │
│         ...                                                  │
│     }                                                        │
└─────────────────────────────────────────────────────────────┘

3.4 cmd_procprio() - 进程注册处理

文件路径: system/memory/lmkd/lmkd.cpp:1134

static void cmd_procprio(LMKD_CTRL_PACKET packet, int field_count, struct ucred *cred) {
    struct proc *procp;
    struct lmk_procprio params;

    // 1. 解析数据包
    lmkd_pack_get_procprio(packet, field_count, &params);
    // params.pid = packet[1]
    // params.uid = packet[2]
    // params.oomadj = packet[3]
    // params.ptype = packet[4] (APP 或 SERVICE)

    // 2. 验证 oomadj 值范围
    if (params.oomadj < OOM_SCORE_ADJ_MIN ||  // -1000
        params.oomadj > OOM_SCORE_ADJ_MAX) {  // 1000
        ALOGE("Invalid PROCPRIO oomadj argument %d", params.oomadj);
        return;
    }

    // 3. 验证是线程组 leader
    if (read_proc_status(params.pid, buf, sizeof(buf))) {
        if (parse_status_tag(buf, PROC_STATUS_TGID_FIELD, &tgid) && tgid != params.pid) {
            ALOGE("Attempt to register a task that is not a thread group leader");
            return;
        }
    }

    // 4. ★★★ 写入内核 oom_score_adj 文件 ★★★
    snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
    snprintf(val, sizeof(val), "%d", params.oomadj);
    if (!writefilestring(path, val, false)) {
        ALOGW("Failed to open %s; process %d might have been killed", path, params.pid);
        return;
    }

    // 5. 用户态模式:管理进程信息
    if (!use_inkernel_interface) {
        // 设置 memory cgroup soft limit
        if (params.ptype == PROC_TYPE_APP && per_app_memcg) {
            // 根据 oomadj 计算 soft_limit_mult
            // 写入 memory.soft_limit_in_bytes
        }

        // 注册到进程哈希表
        procp = pid_lookup(params.pid);
        if (!procp) {
            // 创建新的 proc 结构
            procp = static_cast<struct proc*>(calloc(1, sizeof(struct proc)));
            procp->pid = params.pid;
            procp->uid = params.uid;
            // ...
            pid_insert(procp);  // 插入哈希表
        }
        // 更新优先级
        procp->oomadj = params.oomadj;
        // 插入优先级排序链表
        proc_insert(procp);
    }
}

4. LMKD 命令协议

4.1 命令码定义

文件路径: system/memory/lmkd/include/lmkd.h:29

enum lmk_cmd {
    LMK_TARGET = 0,         /* 设置 minfree/adj 配置 */
    LMK_PROCPRIO,           /* 注册进程,设置 oom_adj (1) */
    LMK_PROCREMOVE,         /* 移除进程注册 (2) */
    LMK_PROCPURGE,          /* 清除所有注册 (3) */
    LMK_GETKILLCNT,         /* 获取杀死计数 (4) */
    LMK_SUBSCRIBE,          /* 订阅异步事件 (5) */
    LMK_PROCKILL,           /* 进程被杀死通知 (6) - unsolicited */
    LMK_UPDATE_PROPS,       /* 更新属性配置 (7) */
    LMK_STAT_KILL_OCCURRED, /* 杀死事件统计通知 (8) */
    LMK_STAT_STATE_CHANGED, /* 状态变化通知 (9) */
};

4.2 数据包格式

LMK_PROCPRIO (设置进程优先级)
┌──────────┬──────────┬──────────┬──────────┬──────────┐
│  命令码   │   PID    │   UID    │  oomadj  │  ptype   │
│  (int)   │  (int)   │  (int)   │  (int)   │  (int)   │
│    1     │  pid     │   uid    │  adj值   │  APP/SVC │
└──────────┴──────────┴──────────┴──────────┴──────────┘
   4 bytes   4 bytes   4 bytes   4 bytes   4 bytes

Framework 发送代码 (ProcessList.java:1491):

public static void setOomAdj(int pid, int uid, int amt) {
    ByteBuffer buf = ByteBuffer.allocate(4 * 4);
    buf.putInt(LMK_PROCPRIO);  // 1
    buf.putInt(pid);
    buf.putInt(uid);
    buf.putInt(amt);
    writeLmkd(buf, null);
}

Native 端解析 (lmkd.h:115):

static inline void lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet,
                                          struct lmk_procprio* params) {
    params->pid = (pid_t)ntohl(packet[1]);
    params->uid = (uid_t)ntohl(packet[2]);
    params->oomadj = ntohl(packet[3]);
    params->ptype = (enum proc_type)ntohl(packet[4]);
}
LMK_TARGET (设置 minfree 配置)
┌──────────┬──────────┬──────────┬──────────┬─────┬──────────┬──────────┐
│  命令码   │ minfree1 │  adj1    │ minfree2 │ adj2│   ...    │  adjN    │
│    0     │  pages   │  adj值   │  pages    │adj值│          │          │
└──────────┴──────────┴──────────┴──────────┴─────┴──────────┴──────────┘

最多 6 组 (minfree, adj) 对

Framework 发送代码 (ProcessList.java:1545):

public boolean onLmkdConnect(OutputStream ostream) {
    // ...
    // Reset oom_adj levels
    buf = ByteBuffer.allocate(4 * (2 * mOomAdj.length + 1));
    buf.putInt(LMK_TARGET);
    for (int i = 0; i < mOomAdj.length; i++) {
        buf.putInt((mOomMinFree[i] * 1024)/PAGE_SIZE);  // minfree (pages)
        buf.putInt(mOomAdj[i]);                         // adj
    }
    ostream.write(buf.array(), 0, buf.position());
}
LMK_PROCREMOVE (移除进程)
┌──────────┬──────────┐
│  命令码   │   PID    │
│    2     │  pid     │
└──────────┴──────────┘

Framework 发送代码 (ProcessList.java:1516):

public static final void remove(int pid) {
    ByteBuffer buf = ByteBuffer.allocate(4 * 2);
    buf.putInt(LMK_PROCREMOVE);
    buf.putInt(pid);
    writeLmkd(buf, null);
}
LMK_SUBSCRIBE (订阅事件)
┌──────────┬──────────┐
│  命令码   │ 事件类型  │
│    5     │ evt_type │
└──────────┴──────────┘

事件类型:

  • LMK_ASYNC_EVENT_KILL (0) - 进程被杀死事件
  • LMK_ASYNC_EVENT_STAT (1) - 统计事件

5. Framework 侧 LmkdConnection 实现

5.1 类结构

文件路径: frameworks/base/services/core/java/com/android/server/am/LmkdConnection.java

public class LmkdConnection {
    // Socket 和 I/O 流
    private LocalSocket mLmkdSocket = null;
    private OutputStream mLmkdOutputStream = null;
    private InputStream mLmkdInputStream = null;

    // 输入数据缓冲区
    private final ByteBuffer mInputBuf = ByteBuffer.allocate(LMKD_REPLY_MAX_SIZE);

    // 回调监听器
    interface LmkdConnectionListener {
        boolean onConnect(OutputStream ostream);   // 连接建立回调
        void onDisconnect();                       // 连接断开回调
        boolean isReplyExpected(...);              // 响应匹配检查
        boolean handleUnsolicitedMessage(...);     // 处理异步消息
    }

    private final LmkdConnectionListener mListener;
}

5.2 连接管理流程

文件路径: ProcessList.java:864

void init(ActivityManagerService service, ...) {
    // ...
    if (sKillHandler == null) {
        sKillThread = new ServiceThread(TAG + ":kill", THREAD_PRIORITY_BACKGROUND, true);
        sKillThread.start();
        sKillHandler = new KillHandler(sKillThread.getLooper());

        // 创建 LmkdConnection
        sLmkdConnection = new LmkdConnection(sKillThread.getLooper().getQueue(),
            new LmkdConnection.LmkdConnectionListener() {
                @Override
                public boolean onConnect(OutputStream ostream) {
                    Slog.i(TAG, "Connection with lmkd established");
                    return onLmkdConnect(ostream);  // 发送初始化命令
                }

                @Override
                public void onDisconnect() {
                    Slog.w(TAG, "Lost connection to lmkd");
                    // 重连机制:延迟后重试
                    sKillHandler.sendMessageDelayed(
                        sKillHandler.obtainMessage(KillHandler.LMKD_RECONNECT_MSG),
                        LMKD_RECONNECT_DELAY_MS);
                }

                @Override
                public boolean handleUnsolicitedMessage(DataInputStream inputData, int receivedLen) {
                    // 处理 LMK_PROCKILL 等异步通知
                    switch (inputData.readInt()) {
                        case LMK_PROCKILL:
                            int pid = inputData.readInt();
                            int uid = inputData.readInt();
                            mAppExitInfoTracker.scheduleNoteLmkdProcKilled(pid, uid);
                            return true;
                        case LMK_KILL_OCCURRED:
                            LmkdStatsReporter.logKillOccurred(inputData, ...);
                            return true;
                        // ...
                    }
                    return false;
                }
            }
        );
    }
}

5.3 onLmkdConnect() 初始化命令

文件路径: ProcessList.java:1545

public boolean onLmkdConnect(OutputStream ostream) {
    try {
        // 1. 清除所有已注册进程
        ByteBuffer buf = ByteBuffer.allocate(4);
        buf.putInt(LMK_PROCPURGE);
        ostream.write(buf.array(), 0, buf.position());

        // 2. 重新设置 minfree/adj 配置
        if (mOomLevelsSet) {
            buf = ByteBuffer.allocate(4 * (2 * mOomAdj.length + 1));
            buf.putInt(LMK_TARGET);
            for (int i = 0; i < mOomAdj.length; i++) {
                buf.putInt((mOomMinFree[i] * 1024)/PAGE_SIZE);
                buf.putInt(mOomAdj[i]);
            }
            ostream.write(buf.array(), 0, buf.position());
        }

        // 3. 订阅进程杀死事件
        buf = ByteBuffer.allocate(4 * 2);
        buf.putInt(LMK_SUBSCRIBE);
        buf.putInt(LMK_ASYNC_EVENT_KILL);
        ostream.write(buf.array(), 0, buf.position());

        // 4. 订阅统计事件
        buf = ByteBuffer.allocate(4 * 2);
        buf.putInt(LMK_SUBSCRIBE);
        buf.putInt(LMK_ASYNC_EVENT_STAT);
        ostream.write(buf.array(), 0, buf.position());

    } catch (IOException ex) {
        return false;
    }
    return true;
}

5.4 writeLmkd() 发送函数

文件路径: ProcessList.java:1578

private static boolean writeLmkd(ByteBuffer buf, ByteBuffer repl) {
    if (!sLmkdConnection.isConnected()) {
        // 连接断开,触发重连
        sKillHandler.sendMessage(
            sKillHandler.obtainMessage(KillHandler.LMKD_RECONNECT_MSG));
        // 等待连接,最多 3 次 (约 3 秒)
        for (int retry = 0; retry < 3; retry++) {
            if (sLmkdConnection.waitForConnection(LMKD_RECONNECT_DELAY_MS)) {
                break;
            }
        }
        if (!sLmkdConnection.isConnected()) {
            return false;
        }
    }

    // 发送数据
    if (repl != null) {
        // 需要响应的请求
        return sLmkdConnection.exchange(buf, repl);
    } else {
        // 无需响应的请求
        return sLmkdConnection.write(buf);
    }
}

6. Native 侧 liblmkd_utils

6.1 工具函数

文件路径: system/memory/lmkd/liblmkd_utils.cpp

// 连接到 lmkd socket
int lmkd_connect() {
    return socket_local_client("lmkd",
                               ANDROID_SOCKET_NAMESPACE_RESERVED,
                               SOCK_SEQPACKET | SOCK_CLOEXEC);
}

// 注册进程
int lmkd_register_proc(int sock, struct lmk_procprio *params) {
    LMKD_CTRL_PACKET packet;
    size_t size;

    size = lmkd_pack_set_procprio(packet, params);
    ret = TEMP_FAILURE_RETRY(write(sock, packet, size));

    return (ret < 0) ? -1 : 0;
}

// 移除进程注册
int lmkd_unregister_proc(int sock, struct lmk_procremove *params) {
    LMKD_CTRL_PACKET packet;
    size_t size;

    size = lmkd_pack_set_procremove(packet, params);
    ret = TEMP_FAILURE_RETRY(write(sock, packet, size));

    return (ret < 0) ? -1 : 0;
}

6.2 init 进程中的服务注册

文件路径: system/core/init/lmkd_service.cpp

static int lmkd_socket = -1;

static LmkdRegistrationResult RegisterProcess(uid_t uid, pid_t pid, int oom_score_adjust) {
    // 连接 lmkd
    if (lmkd_socket < 0) {
        lmkd_socket = lmkd_connect();
        if (lmkd_socket < 0) {
            return LMKD_CONN_FAILED;
        }
    }

    // 注册服务进程
    struct lmk_procprio params;
    params.pid = pid;
    params.uid = uid;
    params.oomadj = oom_score_adjust;
    params.ptype = PROC_TYPE_SERVICE;  // 服务类型

    if (lmkd_register_proc(lmkd_socket, &params) != 0) {
        close(lmkd_socket);
        lmkd_socket = -1;
        return LMKD_REG_FAILED;
    }

    return LMKD_REG_SUCCESS;
}

// init 进程调用此函数注册服务
void LmkdRegister(const std::string& name, uid_t uid, pid_t pid, int oom_score_adjust) {
    LmkdRegistrationResult result;
    result = RegisterProcess(uid, pid, oom_score_adjust);
    // ...
}

7. 进程杀死流程

7.1 PSI 内存压力监控

文件路径: lmkd.cpp PSI 监控器

// PSI 阈值配置
static struct psi_threshold psi_thresholds[VMPRESS_LEVEL_COUNT] = {
    { PSI_SOME, 70 },    // 70ms partial stall - LOW pressure
    { PSI_SOME, 100 },   // 100ms partial stall - MEDIUM pressure
    { PSI_FULL, 70 },    // 70ms complete stall - CRITICAL pressure
};

// PSI 事件触发时查找并杀死进程
static void mp_event_handler(int data, uint32_t events, struct polling_params *poll_params) {
    // 1. 评估内存压力等级
    // 2. 根据压力等级选择合适的 adj 阈值
    // 3. 从进程链表中查找符合条件的进程
    // 4. 调用 kill_one_process() 杀死进程
}

7.2 进程选择策略

// 从最低优先级开始查找
struct proc *procp;
for (int i = OOM_SCORE_ADJ_MAX; i >= target_oomadj; i--) {
    procp = procadjslot_list[i].next;
    while (procp != &procadjslot_list[i]) {
        // 检查进程是否可杀死
        if (procp->oomadj >= target_oomadj && procp->pid > 0) {
            // 执行杀死
            kill_one_process(procp);
            return;
        }
        procp = procp->next;
    }
}

7.3 进程杀死执行

static void kill_one_process(struct proc *procp) {
    int pid = procp->pid;
    int pidfd = procp->pidfd;

    // 发送 SIGKILL
    if (pidfd >= 0) {
        // 使用 pidfd 发送信号 (更可靠)
        syscall(__NR_pidfd_send_signal, pidfd, SIGKILL, NULL, 0);
    } else {
        // 传统方式
        kill(pid, SIGKILL);
    }

    // 记录杀死信息
    last_kill_pid_or_fd = pidfd >= 0 ? pidfd : pid;
    clock_gettime(CLOCK_MONOTONIC_COARSE, &last_kill_tm);

    // 通知订阅者 (LMK_PROCKILL)
    notify_kill(pid, procp->uid);
}

8. 关键代码路径汇总

8.1 LMKD Native 侧

文件路径关键内容
主程序system/memory/lmkd/lmkd.cppmain(), init(), mainloop(), cmd_* 处理
头文件system/memory/lmkd/include/lmkd.h命令码定义, 数据包格式
Init配置system/memory/lmkd/lmkd.rc服务启动配置, socket 创建
工具库system/memory/lmkd/liblmkd_utils.cpplmkd_connect(), lmkd_register_proc()
Init服务system/core/init/lmkd_service.cpp服务进程注册
Reapersystem/memory/lmkd/reaper.cpp进程杀死线程池

8.2 Framework 侧

文件路径关键内容
ProcessListframeworks/base/services/.../am/ProcessList.javasetOomAdj(), writeLmkd(), onLmkdConnect()
LmkdConnectionframeworks/base/services/.../am/LmkdConnection.javaSocket 连接管理, 数据收发
OomAdjusterframeworks/base/services/.../am/OomAdjuster.javaadj 计算, applyOomAdjLSP()

8.3 关键函数行号

函数文件行号
main()lmkd.cpp4234
init()lmkd.cpp3882
mainloop()lmkd.cpp4043
ctrl_connect_handler()lmkd.cpp1599
ctrl_command_handler()lmkd.cpp1479
cmd_procprio()lmkd.cpp1134
android_get_control_socket()lmkd.cpp3909
LmkdConnection.connect()LmkdConnection.java122
openSocket()LmkdConnection.java249
setOomAdj()ProcessList.java1491
writeLmkd()ProcessList.java1578
onLmkdConnect()ProcessList.java1545

9. 完整通信流程图

┌──────────────────────────────────────────────────────────────────────────────┐
│                           系统启动阶段                                         │
├──────────────────────────────────────────────────────────────────────────────┤
│  init 进程                                                                    │
│    │                                                                         │
│    ├─ 解析 lmkd.rc                                                            │
│    │    └─ 创建 socket: "/dev/socket/lmkkd" (SOCK_SEQPACKET)                 │
│    │                                                                         │
│    ├─ 启动 lmkd 服务                                                          │
│    │    └─ execve("/system/bin/lmkkd")                                       │
│    │                                                                         │
│    └─ 注册 init 服务进程                                                       │
│        └─ LmkdRegister() → lmkd_socket → LMK_PROCPRIO                        │
└──────────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────────┐
│                           LMKD 初始化阶段                                      │
├──────────────────────────────────────────────────────────────────────────────┤
│  lmkd main()                                                                 │
│    │                                                                         │
│    ├─ update_props() - 读取配置属性                                            │
│    │                                                                         │
│    ├─ init()                                                                 │
│    │    ├─ epoll_create()                                                    │
│    │    ├─ android_get_control_socket("lmkd") ← 获取 init 创建的 socket       │
│    │    ├─ listen(socket, MAX_DATA_CONN)                                     │
│    │    ├─ epoll_ctl(EPOLL_CTL_ADD, socket, ctrl_connect_handler)            │
│    │    └─ init_monitors() - 初始化 PSI 监控                                   │
│    │                                                                         │
│    └─ mainloop()                                                             │
│        └─ epoll_wait() 等待事件                                               │
└──────────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────────┐
│                           Framework 连接阶段                                   │
├──────────────────────────────────────────────────────────────────────────────┤
│  ActivityManagerService.init()                                               │
│    │                                                                         │
│    ├─ ProcessList.init()                                                     │
│    │    └─ 创建 LmkdConnection                                                │
│    │                                                                         │
│    ├─ LmkdConnection.connect()                                                │
│    │    ├─ openSocket()                                                       │
│    │    │    └─ new LocalSocket(SOCKET_SEQPACKET)                            │
│    │    │    └─ connect(new LocalSocketAddress("lmkd", RESERVED))             │
│    │    │                                                                     │
│    │    ├─ 获取 I/O streams                                                    │
│    │    │                                                                     │
│    │    ├─ onLmkdConnect(ostream)                                             │
│    │    │    ├─ LMK_PROCPURGE                                                 │
│    │    │    ├─ LMK_TARGET (minfree/adj 配置)                                  │
│    │    │    ├─ LMK_SUBSCRIBE (KILL)                                          │
│    │    │    └─ LMK_SUBSCRIBE (STAT)                                          │
│    │    │                                                                     │
│    │    └─ 注册 FD 监听事件                                                    │
│    │                                                                         │
│    └─ lmkd 收到连接                                                            │
│        ├─ epoll_wait() 返回 EPOLLIN                                           │
│        ├─ ctrl_connect_handler()                                              │
│        │    └─ accept(socket) → 新 data socket                               │
│        │    └─ epoll_ctl(EPOLL_CTL_ADD, data_sock, ctrl_data_handler)        │
│        └─ ALOGI("lmkd data connection established")                          │
└──────────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────────┐
│                           运行时 adj 更新                                      │
├──────────────────────────────────────────────────────────────────────────────┤
│  OomAdjuster.computeOomAdjLSP() → applyOomAdjLSP()                           │
│    │                                                                         │
│    ├─ ProcessList.setOomAdj(pid, uid, amt)                                   │
│    │    └─ ByteBuffer: [LMK_PROCPRIO, pid, uid, adj]                         │
│    │    └─ writeLmkd(buf, null)                                              │
│    │                                                                         │
│    ├─ LmkdConnection.write()                                                 │
│    │    └─ mLmkdOutputStream.write(buf.array())                              │
│    │                                                                         │
│    └─ lmkd 收到命令                                                           │
│        ├─ epoll_wait() 返回 EPOLLIN                                           │
│        ├─ ctrl_data_handler(data_sock_idx)                                   │
│        ├─ ctrl_command_handler()                                             │
│        │    ├─ ctrl_data_read() → packet                                     │
│        │    ├─ lmkd_pack_get_cmd() → LMK_PROCPRIO                            │
│        │    └─ cmd_procprio()                                                │
│        │        ├─ lmkd_pack_get_procprio() → 解析参数                        │
│        │        ├─ writefilestring("/proc/pid/oom_score_adj", adj)           │
│        │        ├─ pid_insert() → 注册到哈希表                                 │
│        │        └─ proc_insert() → 插入优先级链表                              │
│        └─ 返回                                                               │
└──────────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────────┐
│                           内存压力 → 进程杀死                                   │
├──────────────────────────────────────────────────────────────────────────────┤
│  PSI 监控器                                                                   │
│    │                                                                         │
│    ├─ PSI 事件触发 (内存压力超过阈值)                                            │
│    │                                                                         │
│    ├─ mp_event_handler()                                                     │
│    │    ├─ 读取内存状态                                                        │
│    │    ├─ 计算需要释放的内存量                                                 │
│    │    ├─ 确定目标 adj 阈值                                                   │
│    │    └─ 从进程链表查找符合条件的进程                                          │
│    │                                                                         │
│    ├─ kill_one_process()                                                     │
│    │    ├─ pidfd_send_signal(pidfd, SIGKILL) 或 kill(pid, SIGKILL)           │
│    │    └─ notify_kill(pid, uid) → 发送 LMK_PROCKILL 通知                     │
│    │                                                                         │
│    └─ Framework 收到通知                                                      │
│        ├─ fileDescriptorEventHandler()                                       │
│        ├─ processIncomingData()                                              │
│        ├─ handleUnsolicitedMessage()                                         │
│        │    └─ LMK_PROCKILL → scheduleNoteLmkdProcKilled()                   │
│        └─ 记录进程退出信息                                                      │
└──────────────────────────────────────────────────────────────────────────────┘

参考文献

  1. LMKD 源码

    • system/memory/lmkd/lmkd.cpp - 主程序
    • system/memory/lmkd/include/lmkd.h - 协议定义
    • system/memory/lmkd/liblmkd_utils.cpp - 工具库
    • system/memory/lmkd/lmkd.rc - Init 配置
  2. Framework 源码

    • frameworks/base/services/core/java/com/android/server/am/ProcessList.java
    • frameworks/base/services/core/java/com/android/server/am/LmkdConnection.java
    • frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
  3. Init 服务注册

    • system/core/init/lmkd_service.cpp
  4. Android 官方文档

    • PSI (Pressure Stall Information) 监控
    • Low Memory Killer 设计文档

文档创建日期: 2026/04/28