1 前言

在软件开发的过程中,我们不仅需要实现业务功能,还常常需要深入底层进行问题定位。

在常规的 UNIX-like 系统上,常用的问题定位手段有这几类:

  1. 进程跟踪。业界有很多知名的用于进程跟踪的开源工具,它们实现的功能各不相同,但归根结底都是跟踪某个进程的运行过程,大多都是依赖操作系统提供的 ptrace syscall 去实现这个能力。典型的工具有 gdb、lldb、strace、ltrace 等。
  2. 系统日志。每个操作系统都有日志机制。比如 Linux 上面会有各种各样的日志,包括 systemd 服务日志、内核日志等。
  3. proc 文件系统。通过读 proc 文件系统,我们可以观测到进程运行过程中的各种状态。
  4. 内核打点。ftrace 和 eBPF 都是常用的内核打点机制,这需要操作系统内核支持。

受限于当前鸿蒙 PC 的安全管控措施,上述大多数手段在鸿蒙 PC 上并不可用,本文档仅整理出当前可用的部分。

2 进程跟踪

2.1 lldb

在当前 6.1 版本的 HarmonyOS 系统中,自签名二进制无法拥有 ptrace 权限,因此我们自己编译的 lldb 是无法正常工作的,必须要使用 ohos-sdk 里面提供的 lldb,并且版本要足够新。

为什么需要新版本:OpenHarmony 社区在最新版本的 ohos-sdk 中对 lldb 做了证书签名(而非自签名),证书签名可以让二进制拥有更多高级权限,ptrace 就包括在内。

我们可以去 OpenHarmony 的日构建流水线下载最新的 ohos-sdk-full_ohos 制品

curl -fL -o ohos-sdk-full_ohos.tar.gz https://cidownload.openharmony.cn/version/Daily_Version/ohos-sdk-full_ohos/20260728_020506/version-Daily_Version-ohos-sdk-full_ohos-20260728_020506-ohos-sdk-full_ohos.tar.gz
tar -zxf ohos-sdk-full_ohos.tar.gz -C ~/
rm ~/daily_build.log ~/manifest_tag.xml
cd ~/ohos-sdk/ohos
unzip -uq native-*.zip
unzip -uq toolchains-*.zip
cd -
export PATH=~/ohos-sdk/ohos/native/llvm/bin:~/ohos-sdk/ohos/toolchains/lib:$PATH

现在你可以在 ohos-sdk 中找到 lldb 程序,路径是 ~/ohos-sdk/ohos/native/llvm/bin/lldb。这个 lldb 在鸿蒙 PC 上可正常工作。

附赠一个技巧:如何检查你下载的 lldb 文件是否具有调试权限。

方法非常简单,使用 binary-sign-tool 查看签名信息即可(该工具来自 ohos-sdk)

binary-sign-tool display-sign -inFile ~/ohos-sdk/ohos/native/llvm/bin/lldb

如果你的 lldb 是具有调试权限的版本,你将会得到这样的信息

07-29 10:37:12.321 INFO  - +++++++++++++++++++++++++++++++++permission+++++++++++++++++++++++++++++++++++++
{
        "requestPermissions":   [{
                        "name": "ohos.permission.kernel.ALLOW_DEBUG"
                }, {
                        "name": "ohos.permission.kernel.DEBUGGER"
                }, {
                        "name": "ohos.permission.READ_WRITE_USB_FILE"
                }],
        "version":      1
}
07-29 10:37:12.333 INFO  - +++++++++++++++++++++++++++++++++certificate #0+++++++++++++++++++++++++++++++++++++
        Version: 3 (0x2)
        Serial Number:
            09:fc:0d:1c:17:b5:b3:b1:19:91:67:ec:90:16
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: C=CN,O=Huawei,OU=Huawei CBG,CN=Huawei CBG Developer Relations CA G2
        Validity
            Not Before: Nov 24 06:53:47 2025 GMT
            Not After : Nov 24 06:53:47 2028 GMT
        Subject: C=CN,O=\U5F00\U653E\U539F\U5B50\U5F00\U6E90\U57FA\U91D1\U4F1A,OU=1826159925408081473,CN=\U5F00\U653E\U539F\U5B50\U5F00\U6E90\U57FA\U91D1\U4F1A(1826159925408081473)\,DevID

查询结果显示这个文件拥有 ohos.permission.kernel.ALLOW_DEBUG 和 ohos.permission.kernel.DEBUGGER 权限,并且下方展示了证书链。证书链里面显示颁发者是华为(可能是应用市场或者开发者中心之类的网站颁发的),证书的所属主体属于开放原子基金会。那一串 Unicode 转义序列解码出来是“开放原子基金会”几个字。

2.2 QEMU

在当前 6.1 版本的 HarmonyOS 系统中,自签名二进制无法拥有 ptrace 权限,我们自己编译的 strace 是无法正常工作的。

好在 QEMU 也提供了与 strace 类似的功能。并且这个功能是在纯用户态实现的,不需要内核 ptrace 权限。因此我们可以用 QEMU 来作为 strace 的替代品。

通过 Harmonybrew 安装这个软件包:

brew install qemu

尝试用它来作为 ELF 解释器,用来执行一个程序:

# 解释 ELF 文件的时候需要输入文件路径
# 执行过程中加上 -strace 参数,输出系统调用日志
qemu-aarch64 -strace /bin/ls

你将会得到这样的日志输出,格式与 strace 工具一模一样

38114 set_tid_address(0x7e1fa611e8) = 38114
38114 mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x0000007e1efa7000
38114 madvise(0x0000007e1efa7000,4096,MADV_DONTNEED) = 0
38114 munmap(0x0000007e1efa7000,4096) = 0
38114 mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x0000007e1efa7000
38114 prctl(1398164801,0,541685608448,4096,541694890400,541694890400) = -1 errno=22 (Invalid argument)
38114 madvise(0x0000007e1efa7000,4096,MADV_FREE) = 0
38114 munmap(0x0000007e1efa7000,4096) = 0
...

最后需要澄清一个常见误区:使用了 QEMU,并不等于运行在虚拟机中。

这里使用的只是 QEMU 用户态解释器,并没有虚拟出完整的硬件设备和操作系统。程序发起的 syscall 最终仍会下发给鸿蒙内核,因此不会改变程序原有的运行逻辑。由于这些 syscall 在下发内核前会先由 QEMU 进行拦截与转发,我们得以轻松捕捉并观测它们。

3 系统日志

对底层开发而言,定位问题最有价值的日志就是内核日志了。要查看内核日志,大家可能会首先想到 dmesg 命令和 /dev/kmsg 文件。

在鸿蒙 PC 上,dmesg 命令和 /dev/kmsg 文件都是存在的,但它们并不向用户开放,因此我们无法通过这两个途径查看内核日志。

要查看内核日志,唯一的途径就是 HiLog。HiLog 日志系统除了会收集应用日志外,还会收集内核日志,并且这部分日志是向用户开放的。

只需要在 HiShell 中执行这句命令,就能看到有内核日志源源不断打出

hilog -t kmsg

一般情况下,使用自己的进程名字作为过滤关键字,就能知道你的程序被什么安全模块拦截了

hilog -t kmsg | grep my_program

你也可以使用安全模块的名字来作为过滤关键字,例如 avc、xpm、hmsecpt 都是引发拦截的常见模块

hilog -t kmsg | grep -E "avc|xpm|hmsecpt"

关于这几个日志的作用,这里提供一些个人经验总结(由于缺乏官方资料,暂无权威信息)

  • avc: 程序被 selinux 拦截,会产生这方面的日志
  • xpm: 程序因代码签名无效而验签不通过,会产生这方面的日志
  • hmsecpt:程序被 seccomp 拦截,会产生这方面的日志

4 proc 文件系统

proc 文件系统涉及范围太广,这里不展开介绍,只说一个大致结论:在鸿蒙 PC 上,/proc 下的部分路径是向用户开放的,尤其是 /proc/self 下面的节点几乎是完全开放的。用户需要使用哪个路径,可以自行尝试访问。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐