
背景介绍
下面介绍一种Android系统调试方法,借助Linux proc虚拟文件系统将Android用户态的调试数据放到内核态进行显示,用于logcat不可用情况下调试Android系统。
主要是介绍Linux Kernel中如何实现这样一个/proc/debugprof节点供用户态访问。
环境描述:
- ARM CotexA 64bit
- Android15 Linux 6.6
具体实现
Android15 Linux Kernel(非GKI)Driver中实现一个proc节点,包括三个内容:
- debugprof模块驱动源码
- debugprof模块构建脚本
- debugprof模块设备树配置
debugprof目录结构大概是这个样子:
bash
drivers/Xxx/Xxx_debug/
├── debugprof.c
├── Kconfig
└── Makefile
Linux Kernel实现debugprof
debugprof模块实现源码
cpp
//drivers/xx/debugprof.c
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2026 Xxx Inc.
*/
#include <linux/proc_fs.h>
#include <linux/sched/clock.h>
#include <linux/seq_file.h>
#include <linux/kallsyms.h>
#include <linux/utsname.h>
#include <asm/uaccess.h>
#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/tracepoint.h>
#include <trace/events/initcall.h>
#include <linux/delay.h>
#include <linux/soc/xx/boot_param.h>
#include <linux/console.h>
#define SEQ_printf(m, x...) \
do { \
if (m) \
seq_printf(m, x); \
else \
printk(x); \
} while (0)
//注意:这个是debugprof数据缓存大小,不能分配太大
#define DEBUG_BUF_SIZE (512)
typedef struct dg_debugprof {
int data_size;
char debug_buf[DEBUG_BUF_SIZE]; //用于存用户态传过来的数据
} dg_debugprof;
dg_debugprof dg_debug_stat;
static int dg_debugprof_show(struct seq_file *m, void *v)
{
SEQ_printf(m, "----------------------------------------\n");
SEQ_printf(m, "debug : %s\n", dg_debug_stat.debug_buf);
SEQ_printf(m, "----------------------------------------\n");
return 0;
}
static int dg_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, dg_debugprof_show, inode->i_private);
}
static ssize_t dg_debug_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *data)
{
char buf[DEBUG_BUF_SIZE];
size_t copy_size = cnt;
if (cnt >= sizeof(buf))
copy_size = DEBUG_BUF_SIZE - 1;
if (copy_from_user(&buf, ubuf, copy_size))
return -EFAULT;
buf[copy_size] = 0;
strcpy((char *)&dg_debug_stat.debug_buf, buf);
return cnt;
}
static const struct proc_ops dg_debug_fops = {
.proc_open = dg_debug_open,
.proc_write = dg_debug_write, //重点实现这个接口,Android程序走这个接口将数据传过来
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int debugprof_probe(struct platform_device *pdev)
{
struct proc_dir_entry *pe;
//创建proc debugprof节点,dg_debug_fops是接口函数
pe = proc_create("debugprof", 0664, NULL, &dg_debug_fops);
if (!pe) {
pr_err("debugprof_probe fail.");
return -ENOMEM;
}
pr_info("debugprof_probe success.");
return 0;
}
static int debugprof_remove(struct platform_device *pdev)
{
return 0;
}
static const struct dev_pm_ops debugprof_pm_ops = {
};
static const struct of_device_id debugprof_match[] = {
{.compatible = "Xxx,debugprof",},
{},
};
static struct platform_driver debugprof_drv = {
.driver = {
.owner = THIS_MODULE,
.name = "debugprof",
.of_match_table = debugprof_match,
.pm = &debugprof_pm_ops,
},
.probe = debugprof_probe,
.remove = debugprof_remove,
};
static int __init debugprof_init(void)
{
return platform_driver_register(&debugprof_drv);
}
static void __exit debugprof_exit(void)
{
platform_driver_unregister(&debugprof_drv);
}
core_initcall(debugprof_init);
module_exit(debugprof_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Xxx Boot Chart driver");
MODULE_AUTHOR("yuxi@Xxx.com");
debugprof模块构建
cpp
//drivers/Xxx/Kconfig
source "drivers/Xxx/Xxx_debug/Kconfig"
//drivers/Xxx/Xxx_debug/Kconfig
config Xxx_DEBUGPROF
tristate "Xxx debug info"
default n
help
This option help you to debug
//arch/arm64/configs/Xxx.fragment
CONFIG_Xxx_DEBUGPROF=y
bash
//drviers/Xxx/Makefile
obj-y += Xxx_debug/
debugprof模块dts
cpp
//arch/arm64/boot/dts/Xxx/Xxx_platform.dts
{
...
debugprof: debugprof {
compatible = "Xxx,debugprof";
status = "okay";
};
...
}
Android15中访问/proc/debugprof
cpp
//frameworks/base/tools/aapt2/cmd/Link_test.cpp
TEST_F(LinkTest, NoCompressAssets) {
...
if (auto result =
WriteFile("/proc/debugprof", "^-^##;/odm/etc/init;/product/etc/init");
!result.ok()) {
//write fail
}
}
实现效果
