2. 模块参数传递

任务目标

为Android内核模块添加可配置参数,支持在加载时通过insmod或modprobe传递参数,并在模块加载/卸载时读取和显示参数值。

核心实现

本案例实现一个最小内核模块,定义三种典型参数类型:int、char*和int数组。模块加载时打印参数值,卸载时打印参数最终值,用于验证参数传递是否生效。

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

/* 模块参数定义 */
static int count = 1;
static char *name = "android_drv";
static int arr[4] = {0, 0, 0, 0};
static int arr_argc = 0;

/* 参数注册:权限0644表示可通过sysfs在运行时查看/修改 */
module_param(count, int, 0644);
MODULE_PARM_DESC(count, "loop count, default 1");

module_param(name, charp, 0644);
MODULE_PARM_DESC(name, "device name, default android_drv");

/* 数组参数:arr_argc自动接收实际传入的元素个数 */
module_param_array(arr, int, &arr_argc, 0644);
MODULE_PARM_DESC(arr, "int array, max 4 elements");

static int __init param_demo_init(void)
{
    int i;

    pr_info("param_demo: module loaded\n");
    pr_info("param_demo: count = %d\n", count);
    pr_info("param_demo: name = %s\n", name);
    pr_info("param_demo: arr_argc = %d\n", arr_argc);
    for (i = 0; i < arr_argc; i++)
        pr_info("param_demo: arr[%d] = %d\n", i, arr[i]);

    return 0;
}

static void __exit param_demo_exit(void)
{
    pr_info("param_demo: module unloaded\n");
    pr_info("param_demo: final count = %d\n", count);
    pr_info("param_demo: final name = %s\n", name);
}

module_init(param_demo_init);
module_exit(param_demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kernel Dev");
MODULE_DESCRIPTION("Module parameter passing demo");

Makefile

obj-m := param_demo.o
KDIR := /path/to/android/kernel/source
all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

编译与加载

  1. 将param_demo.c和Makefile放入同一目录,KDIR指向Android内核源码树(需已编译过并生成modules目标)。
  2. 执行make生成param_demo.ko。
  3. 将param_demo.ko推送到设备:adb push param_demo.ko /data/local/tmp/
  4. 加载模块并传参:
adb shell
su
cd /data/local/tmp
# 方式1:insmod传参
insmod param_demo.ko count=5 name="test_dev" arr=1,2,3,4

# 方式2:modprobe传参(需将ko放入/lib/modules/对应目录并运行depmod)
modprobe param_demo count=3 name="mdev" arr=7,8

验证方法

  1. 加载后执行dmesg | tail -20,应看到打印的count、name、arr_argc及数组各元素值,与传入参数一致。
  2. 执行ls /sys/module/param_demo/parameters/,应看到count、name、arr三个参数节点。
  3. 运行时修改参数:echo 10 > /sys/module/param_demo/parameters/count,然后卸载模块,dmesg中final count应显示为10,证明参数可读写。
  4. 卸载模块:rmmod param_demo,dmesg应显示卸载日志及最终参数值。

预期输出(dmesg片段)

param_demo: module loaded
param_demo: count = 5
param_demo: name = test_dev
param_demo: arr_argc = 4
param_demo: arr[0] = 1
param_demo: arr[1] = 2
param_demo: arr[2] = 3
param_demo: arr[3] = 4

关键说明

  • module_param_array的第三个参数&arr_argc是输出参数,内核自动填充实际传入的元素个数,无需手动赋值。
  • 权限位0644使参数在sysfs中可读可写(root可写),便于运行时调整。
  • 若使用modprobe,需确保param_demo.ko已安装到内核模块目录并执行depmod更新依赖。
  • 数组参数最大长度由数组定义决定(此处为4),超出部分会被内核丢弃并告警。
模块参数传递流程 用户空间 insmod param_demo.ko modprobe param_demo /sys/module/param_demo/ 内核空间 module_param count(int) / name(charp) module_param_array arr(int[4]) + arr_argc 内核参数解析 自动填充变量 module_init → param_demo_init() pr_info 打印 count / name / arr[0..arr_argc-1] module_exit → param_demo_exit() 打印最终参数值