在Rust中通过println!()
打印的日志信息在Xcode中可以显示,但是Android Studio里不显示。所以Android可以使用android_logger实现日志输出。但是开发中仅使用打印日志的方式进行调试还是不够的,我们还需要debug调式。所以有了本篇的内容。
LLDB
(Low Level Debugger)是新一代轻量级高性能调试器, 是Xcode
和Android Studio
中的默认调试器。相较于Android开发同学,iOS同学更熟悉它。Rust提供了基于LLDB的调试工具链,所以我们就可以借此用来调试Rust程序。
准备工作
首先建议你先阅读Rust库交叉编译以及在Android与iOS中使用这篇内容,了解如何将Rust程序集成进Android或iOS。本篇的例子也是使用此篇的demo。
不论是Android还是iOS,我们本篇的内容都使用CodeLLDB
插件进行调试,所以你必须有安装 VS Code和此插件。
Android
具体操作
注意Android项目中我们需要将调试的so文件配置为不压缩优化,同时注意使用debug生成的so文件。
android {
...
packagingOptions{
doNotStrip "**/libxxx.so"
}
}
1.push lldb-server到手机
adb push lldb-server /data/local/tmp/
如果之前你的设备有调式过JNI代码,那么此文件就会存在/data/local/tmp/
目录下,可以忽略这一步。同理,如果你没有这个文件,可以新建一个Native C++项目调式一下。
或者去ndk中寻找lldb-server
文件:
find . -name lldb-server
比如我的手机64位的, 所以选择aarch64
下的。然后pushlldb-server
到手机。
2.启动App,然后获取pid
adb shell am start -a android.intent.action.MAIN -n <package-name>/.<activity-name>
adb shell pidof <package-name>
3.启动lldb-server
adb shell /data/local/tmp/lldb-server p --server --listen "*:9876"
4.rust项目debug配置
launch.json
配置如下,作用是attch到目标进程。
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "attach",
"name": "Android",
"pid": "xxx",
"initCommands": [
"platform select remote-android",
"platform connect connect://localhost:9876",
"file target/aarch64-linux-android/debug/libxxx.so",
]
}
]
}
pid
按照前面步骤获取的填入。target/aarch64-linux-android/debug/librust_demo.so
为调试二进制文件位置,保持与Android项目中的文件一致。
其他部分可以不用修改。然后Debug运行就可以打断点进行调式了。
问题
以上其实只适合root设备,否则执行attach xxx
时会提示无权限。所以一开始我是使用的模拟器,然后获取root权限进行调试的。
后面看到了Android基础开发实践:如何分析Native Crash这篇gdb调试部分,找到了解决思路。
我们用Android Studio的lldb调试器进行native调试时有如下的输出:
从上面可以看出,Android Studio通过cat输出lldb-server
并run-as以应用的权限执行cat进行接收,然后将lldb-server
写入到app的私有数据目录,紧接着chmod 700
增加可执行权限。然后使用同样的方式将一个shell脚本start_lldb_server.sh
发送到app数据目录。最后以app的权限运行脚本启动lldb。
其实这个问题仔细想想,为啥as可以不用root就能调试,我们不行。所以就是抄as的作业:
adb shell "cat /data/local/tmp/lldb-server
| run-as <package-name> sh -c 'cat > /data/data/<package-name>/lldb/bin/lldb-server
&& chmod 700 /data/data/<package-name>/lldb/bin/lldb-server'"
adb shell run-as <package-name> ./lldb/bin/lldb-server p --server --listen "*:9876"
如果启动时,报Operation not permitted
错误。可以使用unix-abstract
方式,start_lldb_server.sh
中就是此种方法实现。
adb shell run-as <package-name> ./lldb/bin/lldb-server p --server --listen unix-abstract:///<package-name>/debug.sock
相应的launch.json
中的platform connect connect://localhost:9876
替换为
platform connect unix-abstract-connect:///<package-name>/debug.sock
。
当然<package-name>/debug.sock
名字随你怎么定义,这里只是给了一个建议格式,避免冲突。
优化
在第四步中,我们需要每次手动替换pid,这还是比较麻烦的。我们可以优化一下这里,动态获取pid。
创建tasks.json
文件,输入以下内容:
{
"version": "2.0.0",
"tasks": [
{
"label": "get pid",
"type": "shell",
"command": "adb shell pidof <package-name> | tr -d '\n' > ${workspaceRoot}/pid.txt"
}
]
}
作用是获取pid,然后写入到pid.txt文件中。
launch.json
修改如下:
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "attach",
"name": "Attach",
"pid": "${input:pid}",
"preLaunchTask": "get pid",
"initCommands": [
"platform select remote-android",
"platform connect connect://localhost:9876",
"file target/aarch64-linux-android/debug/libxxx.so",
]
}
],
"inputs": [
{
"id": "pid",
"type": "command",
"command": "extension.commandvariable.file.content",
"args": {
"fileName": "${workspaceFolder}/pid.txt"
}
}
]
}
运行时,读取pid.txt
文件内容作为pid。
- 注意这里使用
extension.commandvariable.file.content
需要vs code安装Command Variable
插件。 - 目前这种方式的问题是会先读取文件中的pid,早于
get pid
的执行。所以需要运行第二次才可以拿到正确的pid。但由于pid只要app不杀死就不会变动,所以问题不大。
Android虽然可以通过上述方法实现调试Rust代码,但毕竟没有as直接支持来的方便。目前来说,聊胜于无。
iOS
iOS整体比Android简单方便很多,首先和Android一样需要用debug静态库包(cargo lipo
命令)。然后在 Frameworks,Libraries,and Embedded Content
和 Library Search Paths
配置libxxx.a
。
我用的模拟器,所以这里选择x86_64-apple-ios
文件夹下的。
launch.json
配置如下:
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "attach",
"name": "iOS",
"program": "RustDemo",
},
]
}
这里是根据App名称连接的,RustDemo
就是这个的demo的名称。
启动App,然后debug就好了。
是不是非常简单。
参考
- 使用GDB/LLDB调试Android的Rust程序
- Android基础开发实践:如何分析Native Crash
- LLDB调试Android Native程序
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)