打印调试技术 printk klogd dmesg

Linux printk详解
4.2.1. printk

#include
printk(KERN_CRIT"error %s,%i",__FILE__,__LINE__);
注:
1). printk函数中能够指定优先级,假如printk没有指定优先级,采用默认优先级,DEFAULT_MESSAGE_LEVEL,其值在kernel/printk.c.
    头文档linux/printk.h中宏定义了8个级别,0-8从高到低分别是:
    KERN_EMERG, KERNEL_ALERT, KERN_CRIT, KERN_ERR, KERN_WARNING, KERN_NOTICE, KERN_INFO, KERN_DEBUG
2). 当printk指定的优先级小于指定的控制台优先级console_loglevel时,调试消息就显示在控制台虚拟终端。
   缺省的console_loglevel值是DEFAULT_CONSOLE_LOGLEVEL。
   .也能够使用系统调用sys_syslog或klogd -c来修改console_loglevel值。
   .在新版本中,也能够直接通过文档/proc/sys/kernel/printk修改,这个文档包含4个整数值,前两个表示系统当前的优先级和缺省优先级。
    能够直接echo 8 > /proc/sys/kernel/printk
   .也能够指定显示在其他控制台,通过调用ioctl(TIOCLINUX)或shell命令setconsole来配置。
   .假如运行了klogd和syslogd,则printk打印到var/log/messages。
. 用打印调试

最常用的调试技术是监视, 在应用程序编程当中是通过在合适的地方调用 printf 来实现. 在你调试内核代码时, 你可以通过 printk 来达到这个目的.

一个不同是 printk 允许你根据消息的严重程度对其分类, 通过附加不同的记录级别或者优先级在消息上. 你常常用一个宏定义来指示记录级别. 例如, KERN_INFO, 我们之前曾在一些打印语句的前面看到过, 是消息记录级别的一种可能值. 记录宏定义扩展成一个字串, 在编译时与消息文本连接在一起; 这就是为什么下面的在优先级和格式串之间没有逗号的原因. 这里有 2 个 printk 命令的例子, 一个调试消息, 一个紧急消息:

printk(KERN_DEBUG "Here I am: %s:%i/n", __FILE__, __LINE__);
printk(KERN_CRIT "I'm trashed; giving up on %p/n", ptr);

有 8 种可能的记录字串, 在头文件 <linux/kernel.h> 里定义; 我们按照严重性递减的顺序列出它们:

KERN_EMERG

用于紧急消息, 常常是那些崩溃前的消息.

KERN_ALERT

需要立刻动作的情形.

KERN_CRIT

严重情况, 常常与严重的硬件或者软件失效有关.

KERN_ERR

用来报告错误情况; 设备驱动常常使用 KERN_ERR 来报告硬件故障.

KERN_WARNING

有问题的情况的警告, 这些情况自己不会引起系统的严重问题.

KERN_NOTICE

正常情况, 但是仍然值得注意. 在这个级别一些安全相关的情况会报告.

KERN_INFO

信息型消息. 在这个级别, 很多驱动在启动时打印它们发现的硬件的信息.

KERN_DEBUG

用作调试消息.

每个字串( 在宏定义扩展里 )代表一个在角括号中的整数. 整数的范围从 0 到 7, 越小的数表示越大的优先级.

一条没有指定优先级的 printk 语句缺省是 DEFAULT_MESSAGE_LOGLEVEL, 在 kernel/printk.c 里指定作为一个整数. 在 2.6.10 内核中, DEFAULT_MESSAGE_LOGLEVEL 是 KERN_WARNING, 但是在过去已知是改变的.

基于记录级别, 内核可能打印消息到当前控制台, 可能是一个文本模式终端, 串口, 或者是一台并口打印机. 如果优先级小于整型值 console_loglevel, 消息被递交给控制台, 一次一行( 除非提供一个新行结尾, 否则什么都不发送 ). 如果 klogd 和 syslogd 都在系统中运行, 内核消息被追加到 /var/log/messages (或者另外根据你的 syslogd 配置处理), 独立于 console_loglevel. 如果 klogd 没有运行, 你只有读 /proc/kmsg ( 用 dmsg 命令最易做到 )将消息取到用户空间. 当使用 klogd 时, 你应当记住, 它不会保存连续的同样的行; 它只保留第一个这样的行, 随后是, 它收到的重复行数.

变量 console_loglevel 初始化成 DEFAULT_CONSOLE_LOGLEVEL, 并且可通过 sys_syslog 系统调用修改. 一种修改它的方法是在调用 klogd 时指定 -c 开关, 在 klogd 的 manpage 里有指定. 注意要改变当前值, 你必须先杀掉 klogd, 接着使用 -c 选项重启它. 另外, 你可写一个程序来改变控制台记录级别. 你会发现这样一个程序的版本在由 O' Reilly 提供的 FTP 站点上的 miscprogs/setlevel.c. 新的级别指定未一个整数, 在 1 和 8 之前, 包含 1 和 8. 如果它设为 1, 只有 0 级消息( KERN_EMERG )到达控制台; 如果它设为 8, 所有消息, 包括调试消息, 都显示.

也可以通过文本文件 /proc/sys/kernel/printk 读写控制台记录级别. 这个文件有 4 个整型值: 当前记录级别, 适用没有明确记录级别的消息的缺省级别, 允许的最小记录级别, 以及启动时缺省记录级别. 写一个单个值到这个文件就改变当前记录级别成这个值; 因此, 例如, 你可以使所有内核消息出现在控制台, 通过简单地输入:

 # echo 8 > /proc/sys/kernel/printk 

现在应当清楚了为什么 hello.c 例子使用 KERN_ALERT 标志; 它们是要确保消息会出现在控制台上.

4.2.2. 重定向控制台消息

Linux 在控制台记录策略上允许一些灵活性, 它允许你发送消息到一个指定的虚拟控制台(如果你的控制台使用的是文本屏幕). 缺省地, 这个"控制台"是当前虚拟终端. 为了选择一个不同地虚拟终端来接收消息, 你可对任何控制台设备调用 ioctl(TIOCLINUX). 下面的程序, setconsole, 可以用来选择哪个控制台接收内核消息; 它必须由超级用户运行, 可以从 misc-progs 目录得到.

下面是全部程序. 应当使用一个参数来指定用以接收消息的控制台的编号.

int main(int argc, char **argv)
{
    char bytes[2] = {11,0}; /* 11 is the TIOCLINUX cmd number */
    if (argc==2) bytes[1] = atoi(argv[1]); /* the chosen console */
    else {

        fprintf(stderr, "%s: need a single arg/n",argv[0]); exit(1); } if (ioctl(STDIN_FILENO, TIOCLINUX, bytes)<0) { /* use stdin */
        fprintf(stderr,"%s: ioctl(stdin, TIOCLINUX): %s/n",
                argv[0], strerror(errno));
        exit(1);
    }
    exit(0);
}

setconsole 使用特殊的 ioctl 命令 TIOCLINUX, 来实现特定于 linux 的功能. 为使用 TIOCLINUX, 你传递它一个指向字节数组的指针作为参数. 数组的第一个字节是一个数, 指定需要的子命令, 下面的字节是特对于子命令的. 在 setconsole 里, 使用子命令 11, 下一个字节(存于 bytes[1])指定虚拟控制台. TIOCLINUX 的完整描述在内核源码的 drivers/char/tty_io.c 里.

4.2.3. 消息是如何记录的

printk 函数将消息写入一个 __LOG_BUF_LEN 字节长的环形缓存, 长度值从 4 KB 到 1 MB, 由配置内核时选择. 这个函数接着唤醒任何在等待消息的进程, 就是说, 任何在系统调用中睡眠或者在读取 /proc/kmsg 的进程. 这 2 个日志引擎的接口几乎是等同的, 但是注意, 从 /proc/kmsg 中读取是从日志缓存中消费数据, 然而 syslog 系统调用能够选择地在返回日志数据地同时保留它给其他进程. 通常, 读取 /proc 文件容易些并且是 klogd 的缺省做法. dmesg 命令可用来查看缓存的内容, 不会冲掉它; 实际上, 这个命令将缓存区的整个内容返回给 stdout, 不管它是否已经被读过.

在停止 klogd 后, 如果你偶尔手工读取内核消息, 你会发现 /proc 看起来象一个 FIFO, 读者阻塞在里面, 等待更多数据. 显然, 你无法以这种方式读消息, 如果 klogd 或者其他进程已经在读同样的数据, 因为你要竞争它.

如果环形缓存填满, printk 绕回并在缓存的开头增加新数据, 覆盖掉最老的数据. 因此, 这个记录过程会丢失最老的数据. 这个问题相比于使用这样一个环形缓存的优点是可以忽略的. 例如, 环形缓存允许系统即便没有一个日志进程也可运行, 在没有人读它的时候可以通过覆盖旧数据浪费最少的内存. Linux 对于消息的解决方法的另一个特性是, printk 可以从任何地方调用, 甚至从一个中断处理里面, 没有限制能打印多少数据. 唯一的缺点是可能丢失一些数据.

如果 klogd 进程在运行, 它获取内核消息并分发给 syslogd, syslogd 接着检查 /etc/syslog.conf 来找出如何处理它们. syslogd 根据一个设施和一个优先级来区分消息; 这个设施和优先级的允许值在 <sys/syslog.h> 中定义. 内核消息由 LOG_KERN 设施来记录, 在一个对应于 printk 使用的优先级上(例如, LOG_ERR 用于 KERN_ERR 消息). 如果 klogd 没有运行, 数据保留在环形缓存中直到有人读它或者缓存被覆盖.

如果你要避免你的系统被来自你的驱动的监视消息击垮, 你或者给 klogd 指定一个 -f (文件) 选项来指示它保存消息到一个特定的文件, 或者定制 /etc/syslog.conf 来适应你的要求. 但是另外一种可能性是采用粗暴的方式: 杀掉 klogd 和详细地打印消息在一个没有用到的虚拟终端上,[13] 或者从一个没有用到的 xterm 上发出命令 cat /proc/kmsg.

4.2.4. 打开和关闭消息

在驱动开发的早期, printk 非常有助于调试和测试新代码. 当你正式发行驱动时, 换句话说, 你应当去掉, 或者至少关闭, 这些打印语句. 不幸的是, 你很可能会发现, 就在你认为你不再需要这些消息并去掉它们时, 你要在驱动中实现一个新特性(或者有人发现了一个 bug), 你想要至少再打开一个消息. 有几个方法来解决这 2 个问题, 全局性地打开或关闭你地调试消息和打开或关闭单个消息.

这里我们展示一种编码 printk 调用的方法, 你可以单独或全局地打开或关闭它们; 这个技术依靠定义一个宏, 在你想使用它时就转变成一个 printk (或者 printf)调用.

  • 每个 printk 语句可以打开或关闭, 通过去除或添加单个字符到宏定义的名子.

  • 所有消息可以马上关闭, 通过在编译前改变 CFLAGS 变量的值.

  • 同一个 print 语句可以在内核代码和用户级代码中使用, 因此对于格外的消息, 驱动和测试程序能以同样的方式被管理.

下面的代码片断实现了这些特性, 直接来自头文件 scull.h:

#undef PDEBUG /* undef it, just in case */
#ifdef SCULL_DEBUG
# ifdef __KERNEL__

/* This one if debugging is on, and kernel space */
# define PDEBUG(fmt, args...) printk( KERN_DEBUG "scull: " fmt, ## args)
# else

/* This one for user space */
# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
# endif
#else
# define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif

#undef PDEBUGG #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */

符号 PDEBUG 定义和去定义, 取决于 SCULL_DEBUG 是否定义, 和以何种方式显示消息适合代码运行的环境: 当它在内核中就使用内核调用 printk, 在用户空间运行就使用 libc 调用 fprintf 到标准错误输出. PDEBUGG 符号, 换句话说, 什么不作; 他可用来轻易地"注释" print 语句, 而不用完全去掉它们.

为进一步简化过程, 添加下面的行到你的 makfile 里:

# Comment/uncomment the following line to disable/enable debugging
DEBUG = y

# Add your debugging flag (or not) to CFLAGS
ifeq ($(DEBUG),y)
 DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
else
 DEBFLAGS = -O2
endif

CFLAGS += $(DEBFLAGS) 

本节中出现的宏定义依赖 gcc 对 ANSI C 预处理器的扩展, 支持带可变个数参数的宏定义. 这个 gcc 依赖不应该是个问题, 因为无论如何内核固有的非常依赖于 gcc 特性. 另外, makefile 依赖 GNU 版本的 make; 再一次, 内核也依赖 GNU make, 所以这个依赖不是问题.

如果你熟悉 C 预处理器, 你可以扩展给定的定义来实现一个"调试级别"的概念, 定义不同的级别, 安排一个整数(或者位掩码)值给每个级别, 以便决定它应当多么详细.

但是每个驱动有它自己的特性和监视需求. 好的编程技巧是在灵活性和效率之间选择最好的平衡, 我们无法告诉你什么是最好的. 记住, 预处理器条件(连同代码中的常数表达式)在编译时执行, 因此你必须重新编译来打开或改变消息. 一个可能的选择是使用 C 条件句, 它在运行时执行, 因而, 能允许你在出现执行时打开或改变消息机制. 这是一个好的特性, 但是它在每次代码执行时需要额外的处理, 这样即便消息给关闭了也会影响效率. 有时这个效率损失无法接受.

本节出现的宏定义已经证明在多种情况下是有用的, 唯一的缺点是要求在任何对它的消息改变后重新编译.

4.2.5. 速率限制

如果你不小心, 你会发现自己用 printk 产生了上千条消息, 压倒了控制台并且, 可能地, 使系统日志文件溢出. 当使用一个慢速控制台设备(例如, 一个串口), 过量的消息速率也能拖慢系统或者只是使它不反应了. 非常难于着手于系统出错的地方, 当控制台不停地输出数据. 因此, 你应当非常注意你打印什么, 特别在驱动的产品版本以及特别在初始化完成后. 通常, 产品代码在正常操作时不应当打印任何东西; 打印的输出应当是指示需要注意的异常情况.

另一方面, 你可能想发出一个日志消息, 如果你驱动的设备停止工作. 但是你应当小心不要做过了头. 一个面对失败永远继续的傻瓜进程能产生每秒上千次的尝试; 如果你的驱动每次都打印"my device is broken", 它可能产生大量的输出, 如果控制台设备慢就有可能霸占 CPU -- 没有中断用来驱动控制台, 就算是一个串口或者一个行打印机.

在很多情况下, 最好的做法是设置一个标志说, "我已经抱怨过这个了", 并不打印任何后来的消息只要这个标志设置着. 然而, 有几个理由偶尔发出一个"设备还是坏的"的提示. 内核已经提供了一个函数帮助这个情况:

int printk_ratelimit(void); 

这个函数应当在你认为打印一个可能会常常重复的消息之前调用. 如果这个函数返回非零值, 继续打印你的消息, 否则跳过它. 这样, 典型的调用如这样:

if (printk_ratelimit())
    printk(KERN_NOTICE "The printer is still on fire/n");

printk_ratelimit 通过跟踪多少消息发向控制台而工作. 当输出级别超过一个限度, printk_ratelimit 开始返回 0 并使消息被扔掉.

printk_ratelimit 的行为可以通过修改 /proc/sys/kern/printk_ratelimit( 在重新使能消息前等待的秒数 ) 和 /proc/sys/kernel/printk_ratelimit_burst(限速前可接收的消息数)来定制.

4.2.6. 打印设备编号

偶尔地, 当从一个驱动打印消息, 你会想打印与感兴趣的硬件相关联的设备号. 打印主次编号不是特别难, 但是, 为一致性考虑, 内核提供了一些实用的宏定义( 在 <linux/kdev_t.h> 中定义)用于这个目的:

int print_dev_t(char *buffer, dev_t dev); 
char *format_dev_t(char *buffer, dev_t dev);

两个宏定义都将设备号编码进给定的缓冲区; 唯一的区别是 print_dev_t 返回打印的字符数, 而 format_dev_t 返回缓存区; 因此, 它可以直接用作 printk 调用的参数, 但是必须记住 printk 只有提供一个结尾的新行才会刷行. 缓冲区应当足够大以存放一个设备号; 如果 64 位编号在以后的内核发行中明显可能, 这个缓冲区应当可能至少是 20 字节长.

 

总结:

(1)所有系统信息是输出到ring buffer中去的.dmesg所显示的内容也是从ring buffer中读取的.

(2)linux系统中/etc/init.d/sysklogd会启动2个守护进程:klogd&&syslogd

(3)klogd是负责读取内核信息的,有2种方式:

syslog()系统调用(这个函数用法比较全,大家去man一下看看)

直接的对/proc/kmsg进行读取(再这提一下,/proc/kmsg是专门输出内核信息的地方)

(4)klogd的输出结果会传送给syslogd进行处理,syslogd会根据/etc/syslog.conf的配置把log

信息输出到/var/log/下的不同文件中。

<think>我们正在讨论的是在Android 7.1的vendor模块中使用printk打印日志。printkLinux内核的日志函数,因此它通常在内核空间使用。而vendor模块可能既包含内核空间代码(如驱动)也包含用户空间代码(如HAL层)。因此,需要明确是在哪个空间使用printk。 根据问题描述,用户提到“vendor部分”,并且引用[3]中提到了内核驱动(dhd_bus)中的打印,使用的是DHD_ERROR(可能是通过printk实现)。因此,我们假设用户是在vendor下的内核模块(比如驱动)中使用printk。 ### 步骤 1. **确认代码位置**:vendor模块中的内核代码(通常是驱动程序)可以使用printk。在用户空间(如HAL)中不能直接使用printk,因为printk是内核函数。用户空间的HAL代码应该使用syslog或者通过liblog库(即使用ALOG*或SLOG*宏)进行日志打印。 2. **在内核代码中使用printk**: - 在驱动代码中直接使用printk函数,例如: ```c printk(KERN_INFO "This is a log message from vendor module.\n"); ``` 其中,日志级别包括:KERN_EMERG, KERN_ALERT, KERN_CRIT, KERN_ERR, KERN_WARNING, KERN_NOTICE, KERN_INFO, KERN_DEBUG。 3. **控制printk输出**: - 通过修改内核打印等级来控制输出。printk输出的日志会到内核环形缓冲区,然后由用户空间的logd或者klogd等进程收集。在Android中,通常通过`dmesg`命令查看。 - 可以通过以下方式调整内核打印等级: ```bash # 查看当前控制台日志级别 cat /proc/sys/kernel/printk # 输出四个数字,例如:7 4 1 7 # 第一个数字(控制台日志级别)为7,表示比7小的级别的信息都会输出到控制台 # 第二个数字(默认消息日志级别)为4,表示没有指定级别的消息默认级别为4(KERN_WARNING) # 第三个数字(最低控制台日志级别)为1 # 第四个数字(默认控制台日志级别)为7 # 临时修改控制台日志级别(例如,设置为8,即所有级别的消息都输出) echo 8 > /proc/sys/kernel/printk ``` 或者通过修改内核参数: ```bash # 在启动参数中设置 # 在kernel command line中添加:loglevel=8 ``` 4. **在Android中查看printk日志**: - 使用adb命令: ```bash adb shell dmesg ``` - 或者实时查看: ```bash adb shell cat /proc/kmsg ``` 注意:/proc/kmsg只能被一个进程读取,所以如果有其他进程(如logd)正在读取,则可能无法获取全部信息。 5. **在用户空间(HAL)中打印日志**: 如果用户实际上是在vendor下的用户空间代码(如HAL)中需要打印日志,则不应该使用printk,而应该使用syslog或者Android的日志库。在HAL中,通常使用`liblog`库,例如: ```c #include <log/log.h> ALOGD("This is a debug log in HAL"); ``` 然后通过logcat查看: ```bash adb logcat -s your_tag ``` ### 注意事项 - **内核模块编译**:确保在编译内核模块时,包含必要的头文件(如`linux/printk.h`),并且模块已经正确加载(使用`insmod`或`modprobe`)。 - **权限问题**:在Android中,访问`/proc/kmsg`需要root权限。 - **日志丢失**:内核环形缓冲区大小有限,可能会被新的日志覆盖。 ### 示例代码(内核模块) 假设我们有一个vendor内核模块,需要添加printk日志: ```c #include <linux/init.h> #include <linux/module.h> #include <linux/printk.h> static int __init my_module_init(void) { printk(KERN_INFO "My vendor module loaded\n"); return 0; } static void __exit my_module_exit(void) { printk(KERN_INFO "My vendor module unloaded\n"); } module_init(my_module_init); module_exit(my_module_exit); ``` ### 验证 加载模块后,通过`dmesg`查看日志: ```bash adb shell dmesg | grep "My vendor module" ``` ### 相关问题 1. 如何在Android HAL层打印日志? 2. 如何调整内核日志缓冲区大小? 3. 如何将内核日志重定向到logcat? 4. 在Android中如何查看内核模块的加载状态? 5. 如何在内核模块中打印堆栈信息? 注意:如果用户的问题实际上是在用户空间(如HAL)中打印日志,那么请使用ALOG*宏,而不是printk。根据引用[3]中的代码,他们使用的是DHD_ERROR,这可能是基于printk的封装,因为那是在内核驱动中。 因此,我们根据上下文推断用户可能是在vendor的内核模块中使用printk。如果用户指的是用户空间,请参考上述HAL的日志方法。</think>### 🔧 Android 7.1 vendor 模块中使用 printk 打印日志的实现方法 printkLinux 内核的日志系统,在 Android 的 vendor 模块中(特别是内核驱动层)可通过以下方式使用: #### 1️⃣ **在内核驱动代码中直接使用 printk** 在 vendor 内核模块代码中直接调用 printk 函数: ```c #include <linux/kernel.h> // 必需头文件 void your_vendor_function() { // 基本打印(使用默认日志级别) printk("Vendor module: Initialization started\n"); // 带日志级别的打印(推荐) printk(KERN_INFO "Vendor: Chip detected: 0x%x\n", chip_id); printk(KERN_ERR "Vendor: Critical error in %s!\n", __func__); } ``` #### 2️⃣ **日志级别控制** printk 支持不同日志级别: ```c printk(KERN_EMERG "Emergency message\n"); // 最高级别 printk(KERN_ALERT "Alert message\n"); printk(KERN_CRIT "Critical error\n"); printk(KERN_ERR "Error condition\n"); // 常用错误级别 printk(KERN_WARNING "Warning message\n"); printk(KERN_NOTICE "Normal notice\n"); printk(KERN_INFO "Information message\n"); // 常用信息级别 printk(KERN_DEBUG "Debug message\n"); // 调试专用 ``` #### 3️⃣ **内核日志级别配置** 在设备上修改内核日志级别(需 root 权限): ```bash # 查看当前日志级别 adb shell cat /proc/sys/kernel/printk # 输出示例:7 4 1 7 (分别表示:当前控制台级别、默认消息级别、最低允许级别、默认控制台级别) # 临时设置调试级别(允许DEBUG以上所有日志) adb shell su root echo "8 4 1 7" > /proc/sys/kernel/printk # 永久设置(需修改内核启动参数) # 在kernel command line中添加:loglevel=8 ``` #### 4️⃣ **查看 printk 日志** 使用以下命令查看内核日志: ```bash # 查看完整内核日志 adb shell dmesg # 实时监控内核日志 adb shell cat /proc/kmsg # 过滤特定模块日志 adb shell dmesg | grep -i "your_log_tag" ``` #### 5️⃣ **在 HAL 层使用替代方案** 若在用户空间的 vendor HAL 层,应使用 Android 专用日志接口: ```c #include <log/log.h> void hal_function() { ALOGD("HAL debug: %s", debug_info); // DEBUG 级别 ALOGI("HAL info: Device initialized"); // INFO 级别 ALOGE("HAL error: Code %d", err_code); // ERROR 级别 } ``` #### ⚙️ 技术原理说明 printk 日志输出流程: ```mermaid graph LR A[vendor模块] -->|printk调用| B[内核环形缓冲区] B --> C[/proc/kmsg] B --> D[dmesg命令] C --> E[logcat] D --> F[开发者] ``` #### ⚠️ 注意事项 1. **权限问题**: - 访问 `/proc/kmsg` 需要 root 权限 - 永久修改日志级别需修改 bootloader 参数 2. **性能影响**: - 高频 printk 调用会导致性能下降 - 生产环境建议使用 `KERN_ERR` 及以上级别 3. **日志丢失风险**: - 内核环形缓冲区默认仅 16KB,重要日志需及时抓取 - 可通过修改 `/proc/sys/kernel/printk_ringbuffer` 调整缓冲区大小 4. **Android 版本差异**: - Android 8.0+ 使用 pKmsg 替代 kmsg - Android 11+ 需 SELinux 权限配置 > 📚 参考示例代码结构见引用[3]中的 `dhdsdio_probe_attach` 函数实现[^3] --- ### ❓ 相关问题 1. 如何在内核驱动中区分 printk 和 ALOG 的使用场景? 2. Android 7.1 的 printk 日志缓冲区大小如何调整? 3. 如何将 vendor 模块的 printk 日志重定向到 logcat? 4. 在内核模块中使用 printk 会有什么安全风险? 5. Android 7.1 的 SELinux 策略如何影响 printk 日志访问?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值