You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android内核模块insmod成功但入口函数demo_init未执行求助

解决Android 3.10.86内核模块insmod成功但init函数未执行的问题

嘿,我碰到过类似的Android内核模块坑,咱们一步步拆解排查:

1. 先确认模块入口宏的正确性

首先检查你的代码里,是不是正确用了module_init(demo_init)?有没有拼写错误(比如把demo_init写成demo_int),或者不小心加了括号写成module_init(demo_init())?后者会在编译时直接执行函数,而非注册为模块入口,这是新手常踩的小坑。

同时别忘了对应写好module_exit(demo_exit),虽然这和init函数不执行直接关联不大,但先把基础配置拉满。

2. 验证编译环境与内核版本的匹配度

Android内核的编译环境和标准Linux差异很大,这是重灾区:

  • 你用的内核头文件是不是当前运行设备的3.10.86内核头文件?如果是用通用Linux头文件编译,大概率会出现加载后不执行init的情况。
  • 检查内核配置:有没有开启CONFIG_MODULES?有些定制Android内核会默认关闭模块支持,或者开启了CONFIG_MODULE_SIG_FORCE(强制模块签名)——如果你的模块没签名,哪怕insmod显示成功,内核也会悄悄拒绝执行init函数。可以用zcat /proc/config.gz | grep CONFIG_MODULE查看相关配置。
  • 编译时加-Wall选项,看看有没有隐性警告(比如函数未声明、类型不匹配),这些问题可能导致init函数被编译器优化掉。如果怀疑优化问题,给demo_init__attribute__((used))属性防止被丢弃:
    static int __init demo_init(void) __attribute__((used));
    

3. 换个方式看内核日志

Android的内核日志不一定只在dmesg里,有时候缓冲区会被覆盖。试试用:

logcat -b kernel

实时查看内核日志,或者直接读取/proc/kmsg(需要root权限),说不定能找到dmesg没抓到的错误信息。

4. 用极简代码排查根源

把你的模块代码简化到最小,只保留init和exit的日志打印:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int __init demo_init(void) {
    printk(KERN_INFO "[DEMO] Hello, World!\n");
    return 0;
}

static void __exit demo_exit(void) {
    printk(KERN_INFO "[DEMO] Goodbye, World!\n");
}

module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL"); // 这个很重要!Android内核可能拒绝加载无GPL许可证的模块
MODULE_DESCRIPTION("Minimal Demo Module");

编译加载这个简化版,如果能看到日志输出,说明你原来的代码里创建设备类/节点的逻辑有错误——比如class_createdevice_create调用失败,且你没加错误处理和日志打印,导致init函数提前返回,看起来像是没执行。

如果简化版也没输出,那基本可以确定是编译环境或内核配置的问题,重点检查:

  • 临时关闭SELinux:setenforce 0,有些定制ROM的SELinux会阻止第三方模块执行。

5. 检查模块的实际运行状态

加载模块后,除了lsmod,还可以看/proc/modules里的模块条目,确认状态是Live,没有Unloading或其他异常标记。另外用modinfo demo.ko查看模块信息,检查init:字段是不是demo_init,确保入口函数被正确注册。

6. 设备节点与类的创建问题

如果简化版能正常输出,回到原代码检查设备类和节点的创建逻辑:

  • 有没有检查class_createdevice_create的返回值?比如:
    demo_class = class_create(THIS_MODULE, "demo_class");
    if (IS_ERR(demo_class)) {
        printk(KERN_ERR "[DEMO] Failed to create class: %ld\n", PTR_ERR(demo_class));
        return PTR_ERR(demo_class);
    }
    
    很多时候创建失败(比如权限不足、名称冲突)会导致init函数提前返回,却没有日志,看起来像是没执行。
  • 动态分配主设备号时,有没有用alloc_chrdev_region?静态指定的主设备号是不是和系统里的其他设备冲突了?

内容的提问来源于stack exchange,提问作者MrJu

火山引擎 最新活动