The log information printed in Rust println!()
can be displayed in Xcode, but not in Android Studio. So Android can use android_logger to achieve log output. However, it is not enough to debug by printing logs only in development, we also need debug mode. So with the content of this article.
LLDB
(Low Level Debugger) is a new generation of lightweight high-performance debugger, and is the default debugger Xcode
in and in. Android Studio
Compared with Android development students, iOS students are more familiar with it. Rust provides an LLDB-based debugging toolchain, so we can use it to debug Rust programs.
Preparation
First of all, it is recommended that you read Rust library cross-compilation and use in Android and iOS to learn how to integrate Rust programs into Android or iOS. The examples in this article also use the demo of this article.
Whether it is Android or iOS, our content in this article uses CodeLLDB
plug-ins for debugging, so you must have VS Code and this plug-in installed.
Android
Concrete operation
Note that in the Android project, we need to configure the debug so file to not be compressed and optimized , and pay attention to the so file generated by debug.
android {
...
packagingOptions{
doNotStrip "**/libxxx.so"
}
}
1.push lldb-server to the phone
adb push lldb-server /data/local/tmp/
If your device has debugged JNI code before, then this file will exist /data/local/tmp/
in the directory, you can ignore this step. Similarly, if you don't have this file, you can create a new Native C++ project and adjust it.
Or go to ndk to find lldb-server
the file:
find . -name lldb-server
For example, my mobile phone is 64-bit, so choose aarch64
the next one. Then push lldb-server
to the phone.
2. Start the App and get the pid
# 启动App
adb shell am start -a android.intent.action.MAIN -n <package-name>/.<activity-name>
# 获取pid
adb shell pidof <package-name>
3. Start lldb-server
adb shell /data/local/tmp/lldb-server p --server --listen "*:9876"
4. Rust project debug configuration
launch.json
The configuration is as follows, the function is to attach to the target process.
{
"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
Fill in as obtained in the previous steps.target/aarch64-linux-android/debug/librust_demo.so
For the debug binary location, keep the same file as in the Android project.
Other parts can not be modified. Then you can interrupt the debug point to debug when you run Debug.
question
The above is actually only suitable for rooted devices, otherwise attach xxx
it will prompt no permission when executing. So at first I used the emulator, and then got root permission to debug.
Later, I saw the Android basic development practice: how to analyze the gdb debugging part of Native Crash, and found a solution.
When we use Android Studio's lldb debugger for native debugging, we have the following output:
As can be seen from the above, Android Studio uses cat output
lldb-server
and run-as to execute cat with the permission of the application to receive, and thenlldb-server
writes to the private data directory of the app, and thenchmod 700
increases the executable permission. Then use the same method tostart_lldb_server.sh
send a shell script to the app data directory. Finally, run the script with app permissions to start lldb.
In fact, think about this question carefully, why as can be debugged without root, but we can't. So it is to copy the homework of 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'"
# 启动lldb-server
adb shell run-as <package-name> ./lldb/bin/lldb-server p --server --listen "*:9876"
If it starts, Operation not permitted
an error is reported. You can use unix-abstract
the method, start_lldb_server.sh
which is implemented in this method.
adb shell run-as <package-name> ./lldb/bin/lldb-server p --server --listen unix-abstract:///<package-name>/debug.sock
The corresponding launch.json
in platform connect connect://localhost:9876
is replaced with
platform connect unix-abstract-connect:///<package-name>/debug.sock
.
Of course, <package-name>/debug.sock
you can define the name however you want, here is just a suggested format to avoid conflicts.
optimization
In the fourth step, we need to manually replace the pid every time, which is quite troublesome. We can optimize this and get the pid dynamically.
Create tasks.json
a file with the following content:
{
"version": "2.0.0",
"tasks": [
{
"label": "get pid",
"type": "shell",
"command": "adb shell pidof <package-name> | tr -d '\n' > ${workspaceRoot}/pid.txt"
}
]
}
The function is to get the pid, and then write it into the pid.txt file.
launch.json
Modify as follows:
{
"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"
}
}
]
}
At runtime, read pid.txt
the file content as the pid.
- Note that the usage here
extension.commandvariable.file.content
requires vs code to installCommand Variable
the plug-in. - The problem with this method is that the pid in the file will be read first, and it will be
get pid
executed earlier. So you need to run it a second time to get the correct pid. But since the pid will not change as long as the app is not killed, it is not a big problem.
Although Android can debug Rust code through the above method, after all, it does not have the convenience of direct support from as. For now, talk is better than nothing.
iOS
iOS as a whole is much simpler and more convenient than Android. First, you need to use the debug static library package (command) just like Android cargo lipo
. Then in Frameworks,Libraries,and Embedded Content
and Library Search Paths
configure libxxx.a
.
I use the emulator, so I choose x86_64-apple-ios
the folder here.
launch.json
The configuration is as follows:
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "attach",
"name": "iOS",
"program": "RustDemo",
},
]
}
Here it is connected according to the App name, RustDemo
which is the name of this demo.
Start the App, and then debug just fine.
Isn't it very simple.