Skip to content

Commit 75271f5

Browse files
andrurogerzcompnerd
authored andcommitted
[android] add documentation for debugging Android with ds2
1 parent 4e02352 commit 75271f5

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

Android.md

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Debugging Android apps using lldb and ds2
2+
3+
ds2 can run as a debug server on an Android device or emulator to enable remote debugging of native
4+
code in Android applications. While ds2 is capable of connecting to gdb, this guide will focus on
5+
using [lldb](https://lldb.llvm.org/).
6+
7+
## Setup
8+
9+
### Installing adb
10+
Debugging Android requires the [Android Debug Bridge (adb)](https://developer.android.com/tools/adb)
11+
be installed on your workstation. It comes as part of the Android SDK Platform Tools, which can be
12+
downloaded [here](https://developer.android.com/tools/releases/platform-tools#downloads) without
13+
installing Android Studio.
14+
15+
### Enable Device Debugging
16+
If you are using a physical Android device, debugging must be enabled via the device's
17+
[developer options](https://developer.android.com/studio/debug/dev-options).
18+
19+
This step is unnecessary if you are using an Android emulator.
20+
21+
### Make the Application Debuggable
22+
The Android application you intend to debug must have `andriod:debuggable="true"` in its
23+
`AndroidManifest.xml` file:
24+
```xml
25+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
26+
...
27+
<application
28+
android:debuggable="true"
29+
...
30+
31+
```
32+
While the property can be set directly, it is typically set via a debug
33+
[build variant](https://developer.android.com/build/build-variants).
34+
35+
### Grant the Application Network Permission
36+
The application you intend to debug must have the `android.permission.INTERNET` permission declared
37+
in its `AndroidManifest.xml` file:
38+
```xml
39+
<uses-permission android:name="android.permission.INTERNET" />
40+
```
41+
If your application does not have this permission, you cannot debug it using ds2.
42+
43+
This requirement is necessary because:
44+
1. ds2 must run in the context of an application's sandbox to debug the application
45+
2. When running in an application's sandbox, ds2 is limited to the set of permissions granted to
46+
that application
47+
3. ds2 connects to the debugger via a TCP connection, so it requires network access
48+
49+
There are no other permissions required for ds2 to debug an Android application.
50+
51+
## Running ds2
52+
53+
### Deploying ds2 to the Android device
54+
Use adb to deploy the ds2 binary from your workstation to the `/data/local/tmp` directory on your
55+
Android device:
56+
57+
```bash
58+
$ adb push /path/to/ds2 /data/local/tmp
59+
```
60+
> **_NOTE:_** For the Android emulator, copy the `x86_64` version of ds2. For an Android device,
61+
copy the `arm64-v8a` version.
62+
63+
Ensure the binary is executable using `chmod +x` in the device shell:
64+
```bash
65+
$ adb shell chmod +x /data/local/tmp/ds2
66+
```
67+
### Copying ds2 into your application's sandbox
68+
ds2 can be executed directly from its `/data/local/tmp` location to debug programs launched via
69+
`adb shell`. However, to debug processes in an Android application, ds2 must be run in the context
70+
of that application's sandbox using `run-as`.
71+
72+
Android applications can read from the `/data/local/tmp` directory, but, per security policy, they
73+
cannot execute progams from this location. To work-around this restriction, you must first copy the
74+
ds2 binary to the application's private storage using `run-as cp`:
75+
```bash
76+
$ adb shell run-as com.example.TestApp cp /data/local/tmp/ds2 ./
77+
```
78+
This command copies the ds2 executable to root of the application's working directory (e.g.
79+
`/data/user/0/com.example.TestApp`). Once copied, you can execute ds2 from this location to debug
80+
the application.
81+
82+
To confirm ds2 can run in the sandbox, execute it with no arguments using `run-as`:
83+
```
84+
$ adb shell run-as com.example.TestApp ./ds2
85+
Usage:
86+
./ds2 [v]ersion
87+
./ds2 [g]dbserver [options]
88+
./ds2 [p]latform [options]
89+
```
90+
### Port forwarding
91+
To connect the debugger from your workstation to an instance of ds2 running on your Android device,
92+
use adb's port forwarding to forward a TCP port to use for the connection:
93+
```bash
94+
$ adb forward tpc:5432 tcp:5432
95+
```
96+
The exact port number you choose doesn't really matter as long as it is not already in use. Make
97+
note of the port number since you will need it later.
98+
### Running ds2
99+
Launch ds2 on your Android device in "platform" mode. Tell it to listen on the same port number that
100+
you forwarded with adb.
101+
```bash
102+
$ adb shell run-as com.example.TestApp ./ds2 platform --server --listen *:5432
103+
```
104+
ds2 will now block waiting for an incoming connection from a debugger. If this command fails, make
105+
sure the application has network permission (see above) and that there isn't already an instance of
106+
ds2 running with the same port number.
107+
108+
## Debugging with lldb
109+
110+
### Connecting
111+
You are now ready to connect the debugger. Launch lldb from the command line:
112+
```bash
113+
$ lldb
114+
```
115+
From the `(lldb)` prompt, run `platform select remote-android`:
116+
```bash
117+
(lldb) platform select remote-android
118+
Platform: remote-android
119+
Connected: no
120+
```
121+
Connenct to the running ds2 instance using `platform connect connect://localhost:5432`, specifying
122+
the same port number that ds2 is listening on in the connect URI:
123+
```bash
124+
(lldb) platform connect connect://localhost:5432
125+
Platform: remote-android
126+
Triple: aarch64-unknown-linux-android
127+
OS Version: 34 (5.10.198-android13-4-00050-g12f3388846c3-ab11920634)
128+
Hostname: localhost
129+
Connected: yes
130+
WorkingDir: /data/user/0/com.example.TestApp
131+
Kernel: #1 SMP PREEMPT Mon Jun 3 20:51:42 UTC 2024
132+
```
133+
Note the `WorkingDir` value: it should be the root of your application's data directory.
134+
### Attaching to a process
135+
With a platform connection established between lldb and ds2, you can now attach the debugger to a
136+
running process using its process ID (pid). To determine the pid for the process you wish to debug,
137+
list the processes running in your applications' sandbox with `platform process list`:
138+
```bash
139+
(lldb) platform process list
140+
2 matching processes were found on "remote-android"
141+
142+
PID PARENT USER TRIPLE NAME
143+
====== ====== ========== ============================== ============================
144+
8298 8296 u0_a284 aarch64-unknown-linux-android ds2
145+
8883 1139 u0_a284 aarch64-unknown-linux-android app_process64
146+
```
147+
Because ds2 is running in your application's sandbox, this command will list only processes that
148+
are also running in the sandbox. You should see both the ds2 process and an application process for
149+
each of your application's running processes. If you only see ds2, make sure your application is
150+
is running and try again.
151+
152+
Once you know the pid for the process you wish to debug, use the `attach --pid` command to attach
153+
the debugger to it:
154+
```
155+
(lldb) attach --pid 8883
156+
Process 8883 stopped
157+
* thread #1, name = 'example.TestApp', stop reason = signal SIGSTOP
158+
frame #0: 0x00000072cc1cad28 libc.so`__epoll_pwait + 8
159+
libc.so`__epoll_pwait:
160+
-> 0x72cc1cad28 <+8>: cmn x0, #0x1, lsl #12 ; =0x1000
161+
0x72cc1cad2c <+12>: cneg x0, x0, hi
162+
0x72cc1cad30 <+16>: b.hi 0xc6530 ; __set_errno_internal
163+
0x72cc1cad34 <+20>: ret
164+
Executable module set to "/home/user/.lldb/module_cache/remote-android/.cache/00418409-0550-60A6-0094-DA0030D00989/app_process64".
165+
Architecture set to: aarch64-unknown-linux-android0
166+
(lldb)
167+
```
168+
This command spawns an additional ds2 instance (running in gdbserver mode) which attaches to the
169+
process and sets-up the debug session with lldb.
170+
171+
Once attached, you can debug the process with standard gdb and lldb commands. An lldb tutorial can
172+
be found at [llvm.org](https://lldb.llvm.org/use/tutorial.html).

0 commit comments

Comments
 (0)