我正在作为初学者学习android内核。我可以通过 adb 使用dmesg
命令读取从main()
函数内的宏ERROR()
system/core/init/init.c
抛出的消息。我观察到在main()
内部调用函数open_devnull_stdio()
后,dmesg
不再显示ERROR()
抛出的消息。
为了找到原因,我开始挖掘system/core/init/util.c
内部的open_devnull_stdio()
声明,我发现这句话我看不懂
static const char *name = "/dev/__null__"
;
实际上,设备中/dev/
内部没有名为__null__
的文件,但是有一个名为null
的文件,我可以使用adb pull
抓取它,它是一个0字节(空)文件。
那么为什么文件名用双下划线 (__) 括起来呢?
这是 util.c 的链接
在 C 语言中,在开始之前、结束之后或两者之后使用双下划线没有特殊目的。从C的角度来看,文件名只是一个字符串,操作系统可以自由地以它选择的任何方式进行解释。从Linux的角度来看,这同样适用。文件名中的下划线只是字符。它们的处理方式与字母b
和t
没有区别。
如果我猜对了,并且我正在阅读与您相同的文件(链接到您正在阅读的源代码可能是个好主意),那么代码在您提到的代码之后的行上的作用应该很明显。接下来的行是:
if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
fd = open(name, O_RDWR);
unlink(name);
这将创建空设备,然后将其打开并立即再次删除。
我怀疑这样做是为了让程序可以在不访问根文件系统的情况下运行,并且仍然能够打开相当于/dev/null
.
我不知道答案,但我有一个想法:
以下页面显示了使用/dev/__null__
的"strace"输出:
https://gist.github.com/tetsu-koba/1522515
在 Linux 设备文件下有一个 33 位 (?) 数字,用于标识设备。(至少在旧的Linux版本下)您可以在/dev
中删除一些文件,当您知道33位数字时,您可以恢复它甚至在另一个目录中创建它(!)!(因此,您可以删除设备/dev/sda2
并创建设备(而不是文件!/home/myuser/sda2
改为。
上面链接中的跟踪显示以下三行:
mknod("/dev/__null__", S_IFCHR|0600, makedev(1, 3)) = 0
open("/dev/__null__", O_RDWR|O_LARGEFILE) = 3
unlink("/dev/__null__") = 0
这些行将创建设备文件/dev/__null__
(使用 33 位数字标识/dev/null
)。然后它会打开该文件,然后再次删除该文件。
也许这样做是因为该工具应该能够在存在设备文件"/dev/null"的 Linux 安装上运行(在这种情况下,不应覆盖该文件)和在缺少该文件的安装上运行(在这种情况下,必须使用已知的 33 位数字创建替换文件)。
正如其他人指出的那样,这只是告诉它是"空设备",而不是一个名为"null"的常规文件。null
应该像信息接收器一样,而不是像将数据转储到的普通文件。希望这有帮助。