我需要访问 Android 内核模块中的一些 proc 文件。基本上我需要 cat 命令中显示的信息,例如cat /proc/uptime
. 但是我需要以编程方式进行。
我尝试使用proc_fs
函数,但对我来说有点模糊,通常示例是创建一个 proc 文件然后读取它,就是这样。我需要实际使用 proc 文件中的数据。
我也很好fopen
,但它似乎不适用于模块。
我怎样才能做到这一点?我真的是这方面的新手。我正在研究金鱼 Android 内核。
谢谢。
我需要访问 Android 内核模块中的一些 proc 文件。基本上我需要 cat 命令中显示的信息,例如cat /proc/uptime
. 但是我需要以编程方式进行。
我尝试使用proc_fs
函数,但对我来说有点模糊,通常示例是创建一个 proc 文件然后读取它,就是这样。我需要实际使用 proc 文件中的数据。
我也很好fopen
,但它似乎不适用于模块。
我怎样才能做到这一点?我真的是这方面的新手。我正在研究金鱼 Android 内核。
谢谢。
Procfs 是一个内存文件系统。它是用户空间获取信息并将(配置)信息放入内核数据结构的接口。换句话说,procfs 使用户空间能够交互并查看内核数据结构,就像它们在运行时存在的方式一样。
因此,/proc 中的任何文件都不意味着从内核或内核模块中读取。为什么要这样做?在像 Linux 这样的单片内核中,您可以直接通过另一个子系统或通过预定义函数访问内核中一个子系统的数据结构。
以下函数调用可能会有所帮助:
struct timespec uptime;
do_posix_clock_monotonic_gettime(&uptime);
您可以参考下面链接中的 /proc/uptime 实现,它本质上是一个seq_file
.
我正在回答最初的问题,内核模块如何访问procfs
.
我发现以下是一个有用的参考: https ://elixir.bootlin.com/linux/latest/source/fs/proc/proc_sysctl.c#L1790
我认为它是sysctl
从内核命令行设置值。顺序似乎如下:
A. 挂载procfs
文件系统
proc_fs_type = get_fs_type("proc");
*proc_mnt = kern_mount(proc_fs_type);
B. 在相对于 procfs 根目录的路径打开文件
file = file_open_root((*proc_mnt)->mnt_root, *proc_mnt, path, O_WRONLY, 0);
C. 读/写文件
int kernel_read_file(struct file *file, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id)
wret = kernel_write(file, val, len, &pos);
D. 关闭文件
err = filp_close(file, NULL);
D. 清理文件系统挂载
kern_unmount(proc_mnt);
put_filesystem(proc_fs_type);
是的,procfs
主要为用户空间提供对内核级数据的读/写访问。由于内核模块在内核中运行,如果存在允许模块访问此类数据的更直接的 API 调用序列,则首选使用此类 API,因为它可能更清洁、更少代码和更高效。
但是,动态加载的内核模块不能(干净)直接访问内核中的所有符号(或数据结构)。
内核模块只能访问以下函数和变量
完全定义在可以包含在内核模块源代码中的头文件中
或通过以下宏之一显式暴露给内核模块/include/asm-generic/export.h
:
EXPORT_SYMBOL
EXPORT_SYMBOL_GPL
EXPORT_DATA_SYMBOL
EXPORT_DATA_SYMBOL_GPL
内核模块需要访问未通过此类EXPORTED
API 公开但可通过文件procfs
或任何其他特殊文件系统中的文件访问的数据的情况似乎是从内核模块访问此类文件的合法情况。
作为一般设计原则,我的理解是,内核旨在实现机制而不强制执行特定策略。任何以强制用户空间可以访问数据但内核模块不能访问的策略的方式实现的功能都是设计不佳的。
内核模块代码按照设计运行在与内核其余部分相同的特权级别。没有万无一失的方法可以拒绝内核模块访问内核的任何其他部分可以访问的任何数据。任何此类尝试都可以通过漂亮丑陋的黑客来规避。
举个极端的例子,在 x86 机器上,内核模块可以使用内联汇编来直接访问控制寄存器、遍历页表,并使用它想要的任何内存区域。中断和异常处理程序也是如此。
我用 top 来完成这个,因为它实际上给出了 CPU %。我使用的代码如下
Process process = Runtime.getRuntime().exec("top -n 1");
//Get the output of top so that it can be read
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
//Read every line of the output of top that contains data
while (((line = bufferedReader.readLine()) != null)) {
//Break the line into parts. Any number of spaces greater than 0 defines a new element
numbersC = line.split("[ ]+");
if (i > 6) {
//Some lines start with a space, so their indices are different than others
if (numbersC[0].equals("")){
//If name contains the string com.android, then it is a process that we want to take values for
if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android".toLowerCase())){
//Add the name of the process to the Name arraylist, excluding the com.android. part
Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
//Add the CPU value of the process to the CPU arraylist, without the % at the end
CPU.add(Long.parseLong(numbersC[3].replace("%", "")));
}
}
else {
//This is basically the same as above, except with different index values, as there is no leading space in the numbers array
if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android.".toLowerCase())){
Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
CPU.add(Long.parseLong(numbersC[2].replace("%", "")));
}
}
}
i++;
}