My first project at Software Radio Systems, together with my study colleague Bedran Karakoc during our internship, was building a pipeline for automated Android UE-based end-to-end testing for srsLTE. Back then, this was done using Jenkins and osmo-gsm-tester.
This was over 6 years ago, but the controller still works on recent Android devices.
In this post, I want to show how to set it up and remotely control Android UEs. It is important to mention upfront that remotely controlling Android UEs is not straightforward. Devices behave differently depending on the model and vendor, which can lead to inconsistencies. The goal is not just to control the UE, but to make it usable as part of an automated testing setup.
The controller implements some basic procedures such as toggling airplane mode, retrieving SIM information, or running commands directly on the UE. Other features, like setting the APN, have to be used with caution! This function is not reliable and can create invalid APN entries that are difficult to remove without manual intervention.
I will also show how to set up an SSH server on an Android UE to enable SSH and SCP access. This can be very useful for automation.
The current version of the Android UE controller can be found inside our End-To-End testing framework retina.
Prerequisites
The following points are required:
- A rooted Android UE
- USB access to the device
In this post, I use a OnePlus 9 Pro with serial c3f9a7b2. Replace it with your own if multiple devices are connected. You can retrieve it using:
adb devices
* daemon not running; starting now at tcp:5037
* daemon started successfully
List of devices attached
c3f9a7b2 device
4513b02f unauthorized
b8a4a3ef unauthorized
If a UE shows as unauthorized, confirm the ADB fingerprint on the device screen. Without this step, no commands can be executed on the UE.
I connect to the UE and check if I have root access:
adb -s c3f9a7b2 shell
OnePlus9Pro:/ $ su
OnePlus9Pro:/ #
Enabling Traffic Generation with iperf3
To make the UE useful for testing, I set up iperf3 to generate or receive measurable traffic. It allows controlled uplink and downlink throughput testing using TCP or UDP. This is particularly useful to validate uplink and downlink performance across the RAN.
In the following steps I install a prebuilt iperf3 binary on an off-the-shelf Android UE.
1. Download iperf3 binary
Prebuilt iperf3.9 binaries are available here:
https://github.com/ninjab3s/ogt_androidue_utilities
If you prefer to build the binary yourself, have a look at this repository:
https://github.com/davidBar-On/android-iperf3/
In most cases, the correct version for current UEs is:
- arm64-v8a
You can verify the architecture using the following command from the ADB shell on the UE:
adb shell -s c3f9a7b2 getprop ro.product.cpu.abilist
2. Copy binary to the UE
I place the binary in /data/local/tmp, which is writable without modifying system partitions, persistent across reboots, and suitable for test tools.
adb push -s c3f9a7b2 iperf3.9 /data/local/tmp
3. Make iperf3 globally available
On some devices, /system or / do not have enough space available to store binaries. In addition, they are usually mounted as read-only.
To work around this, I remount the filesystem as writable and create a symlink for the iperf3 binary:
adb -s c3f9a7b2 shell
su
mount -o remount,rw /system
mount -o remount,rw /
ln -s /data/local/tmp/iperf3.9 /system/bin/iperf3
4. Verify installation
iperf3 -v
If the installation was successful, the version information should be printed.
At this point, the UE can generate controlled traffic, which is essential for validating RAN performance and later automation workflows.
Enabling Remote Access (SSH & SCP via dropbearmulti)
To integrate the UE into automated workflows, ADB can become quite clunky. To overcome this, you can run an SSH server and enable SCP.
For this setup, I use dropbearmulti, which provides SSH server functionality and SCP support through a single binary.
1. Copy dropbearmulti to the UE
A prebuilt dropbearmulti binary is available here:
https://github.com/ninjab3s/ogt_androidue_utilities
You can also find alternative downloads if needed.
First, push the binary to the UE:
adb push -s c3f9a7b2 dropbearmulti /data/local/tmp
2. Make it available as ssh and scp
dropbearmulti changes behavior depending on how it is invoked. By symlinking it, I expose both ssh and scp.
adb -s c3f9a7b2 shell
su
mount -o remount,rw /system
mount -o remount,rw /
ln -s /data/local/tmp/dropbearmulti /system/bin/ssh
ln -s /data/local/tmp/dropbearmulti /system/bin/scp
As with iperf3, if /system cannot be modified, the binary can still be executed directly from /data/local/tmp.
Once the symlinks are in place, the UE can use ssh and scp, and the same binary can also act as an SSH server.
3. Start the SSH server
Now I start the SSH server by running dropbearmulti with the appropriate parameters:
/data/local/tmp/dropbearmulti dropbear -R -p <PORT> -T /data/local/tmp/authorized_keys -U 0 -G 0 -N root
This starts the SSH server on the UE with the following options:
dropbearstarts the SSH server mode-Rgenerates host keys if they do not exist-p <PORT>specifies the port the server listens on-T /data/local/tmp/authorized_keysspecifies the file containing allowed public keys-U 0sets the user ID to root-G 0sets the group ID to root-N rootallows login as the root user
Authentication is done using public keys. Since the root password is not known, password-based login is not possible.
To enable access, create an authorized_keys file on the UE:
adb push -s c3f9a7b2 authorized_keys /data/local/tmp/authorized_keys
The file should contain your public SSH key (for example from ~/.ssh/id_rsa.pub).
Once this is in place, you can connect using your private key without requiring a password.
If the process should run in the background, it can be started accordingly using standard shell mechanisms.
4. Verify access
Connect the UE to Wi-Fi and retrieve its IP address. Then try to SSH from a machine on the same network:
ssh root@<UE_IP>
If everything is working, you should get a shell on the UE.
Accessing the UE over USB (ADB port forwarding)
If the UE does not yet have a reachable IP address, SSH access can still be established over USB using ADB port forwarding.
In setups with multiple devices or restricted USB access, running the ADB server as root avoids permission issues. In order for this to work, the ADB server needs to be started as root and with the nodaemon flag:
sudo adb -a nodaemon server start
All UEs that have been authenticated on a non-root ADB instance must be reauthenticated. Each user has their own ADB host key.
If you want to automate this, you can copy the ADB key from ~/.android of the user that originally authenticated the UE. If the same key is reused, the UE will recognize it and will not prompt for authentication again.
Once dropbear is running on the UE, forward a local port from the host to the device. In this example, port 2222:
adb -s c3f9a7b2 forward tcp:2222 tcp:22
After that, you can connect to the UE :
ssh -p 2222 root@<host-ip-running-adb>
This provides SSH access without requiring mobile data, Wi-Fi, or any routable IP on the UE.
You can inspect and manage forwarding rules with:
adb forward --list
adb -s c3f9a7b2 forward --remove tcp:2222
Be aware that if the UE restarts or dropbearmulti crashes for some reason, it has to be restarted manually.
At this point, the UE has two access paths: network-based via its IP, and USB-based via ADB. Combined with traffic generation, it turns the UE into a controllable test node instead of a manually operated device.
Toggling Airplane Mode via ADB
Toggling airplane mode is useful when testing connectivity, forcing network re-attachment, or resetting the UE state. The following commands can also be executed directly on the device when connecting via ssh.
Enable airplane mode
adb -s c3f9a7b2 shell
su
settings put global airplane_mode_on 1
am broadcast -a android.intent.action.AIRPLANE_MODE
The command settings put global airplane_mode_on 1 updates the system setting to enable airplane mode. The broadcast am broadcast -a android.intent.action.AIRPLANE_MODE is required to notify the system so that the change actually takes effect.
Disable airplane mode
adb -s c3f9a7b2 shell
su
settings put global airplane_mode_on 0
am broadcast -a android.intent.action.AIRPLANE_MODE
Here, the value 0 disables airplane mode. As before, the broadcast is necessary to apply the change.
Next Steps
In the following posts, I will integrate this setup with Retina, the OCUDU testing framework, and deploy end-to-end test pipelines that use Android UEs.