Android内核模块insmod成功但入口函数demo_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_create或device_create调用失败,且你没加错误处理和日志打印,导致init函数提前返回,看起来像是没执行。
如果简化版也没输出,那基本可以确定是编译环境或内核配置的问题,重点检查:
- 临时关闭SELinux:
setenforce 0,有些定制ROM的SELinux会阻止第三方模块执行。
5. 检查模块的实际运行状态
加载模块后,除了lsmod,还可以看/proc/modules里的模块条目,确认状态是Live,没有Unloading或其他异常标记。另外用modinfo demo.ko查看模块信息,检查init:字段是不是demo_init,确保入口函数被正确注册。
6. 设备节点与类的创建问题
如果简化版能正常输出,回到原代码检查设备类和节点的创建逻辑:
- 有没有检查
class_create和device_create的返回值?比如:
很多时候创建失败(比如权限不足、名称冲突)会导致init函数提前返回,却没有日志,看起来像是没执行。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); } - 动态分配主设备号时,有没有用
alloc_chrdev_region?静态指定的主设备号是不是和系统里的其他设备冲突了?
内容的提问来源于stack exchange,提问作者MrJu




