Use ADB in Remote Machine

Some times we develop Android on a remote Linux machine (or WSL). We need to use adb in remote machine and connect to the local Android device.

Here is how we can achieve this:

  1. Connect physical devices to / run emulators on local machine.
  2. Run adb in nodaemon server mode on local machine.
  3. Create a TCP port forwarding from local machine to remove machine using socat (or ssh).
  4. Use adb in remote to connect local devices.

image-20210812153212102

Prepare the Environment

Install ADB

Install ADB on both local and remote machine. Please make sure:

  • ADB in local machine and remote machine are the same version.
  • On remote machine, ADB in command line and Android Studio are the same one. Normally Android Studio will install Android SDK automatically on first start. Then we can add the directory to PATH environment.
1
2
3
4
5
6
7
8
9
# show adb path
$ which adb
/home/xxx/Android/Sdk/platform-tools/adb

# show adb version
$ adb version
Android Debug Bridge version 1.0.41
Version 31.0.2-7242960
Installed as /home/xxx/Android/sdk/platform-tools/adb

https://developer.android.com/studio/releases/platform-tools

https://developer.android.com/studio/command-line/adb

(Windows Only) Configure Firewall for ADB

On Windows, we need to enable ADB network access in firewall settings.

(WSL Only) Install socat

For WSL, install socat first. It is used to do the port forwarding.

1
sudo apt update && sudo apt install -y socat

(Remote Linux Machine Only) Configure SSH Key

If you are using remote Linux machine, it is recommended to configure ssh key instead of input password every time.

Start ADB and Port Forwarding Manually

We can start ADB and port forwarding manually or use a script to run automatically.

It is recommended to use a script to do it. But I will show you how to run it manually first so that we can know what we actually do and it will help us debug if something goes wrong.

(Optional) Kill Existing Process

If you have started ADB or port forward before, you need to kill ADB and port forwarding process if exists on both local and remote machine.

For WSL:

Run in windows:

1
adb kill-server

Run in WSL:

1
2
3
4
5
6
7
adb kill-server
# kill adb process
pkill -9 adb
# kill Windows adb.exe process in WSL
pkill -9 adb.exe
# kill socat process
pkill -9 socat

For remote linux machine:

Run in local:

1
2
3
4
5
adb kill-server
# kill adb process
pkill -9 adb
# kill ssh command which contains 5037 (used for port forward)
ps -lef | grep ssh | grep 5037 | awk "{print \$2}" | xargs kill

Run in remote:

1
2
adb kill-server
pkill -9 adb

Check Local Device Status

Run adb devices on local machine to see if the device can be connected successfully.

1
2
3
adb devices
# don't forget to kill server
adb kill-server

Start adb server mode on local machine

Run in Windows or local Linux machine:

1
adb -a -P 5037 nodaemon server start

Setup TCP port forwarding

  • We can use socat to do port forwarding if the local and remote machine are in the same network and can connect directly.
  • We can also use ssh to do port forwarding if we can access remote machine with ssh.
  • Don’t forget to configure firewall if exists.

For WSL, we chose socat to do port forwarding. Run in WSL:

1
2
3
4
5
# get host Windows IP
HOST_IP=`cat /etc/resolv.conf | tail -n1 | cut -d " " -f 2`

# start socat port forward
socat TCP-LISTEN:5037,reuseaddr,fork TCP:${HOST_IP}:5037

For remote Linux machine, we chose ssh to do port forwarding. Run in local Linux machine:

1
2
3
4
5
# change this to your remote Linux machine user and address, make sure you have already configured ssh key, or you can input password manaully
USER='root'
HOST='192.168.1.100'

ssh -R 5037:localhost:5037 -f -N $USER@$HOST -o ServerAliveInterval=240

Start ADB on Remote Machine and Verify

Run in WSL or remote Linux machine to see if it works:

1
adb devices

Start the Environment Automatically for WSL

Usage

  1. Install adb on Windows and change $WSL_HOST_ADB to the adb location following the example format.
  2. Install adb and socat on WSL. Make sure you are using the same adb in terminal and Android Studio. And make sure you installed the same version of adb in Windows and WSL.
  3. Add the following content to your WSL ~/.bashrc and run source ~/.bashrc to refresh.
  4. Run wsl-start-adb-daemon / wsl-stop-adb-daemon to start/stop adb environment.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
WSL_HOST_ADB='/mnt/d/AndroidSdk/platform-tools/adb.exe'

wsl-start-adb-daemon() {
if ! [ -x "$(command -v socat)" ]; then
echo 'Please install socat first:' >&2
echo 'sudo apt update && sudo apt install -y socat'
return 1
fi

# stop service
wsl-stop-adb-daemon
echo

echo "Get adb devices on host..."
$WSL_HOST_ADB devices
sleep 1
$WSL_HOST_ADB kill-server
sleep 1

local HOST_IP=`cat /etc/resolv.conf | tail -n1 | cut -d " " -f 2`

echo "Start services..."
nohup $WSL_HOST_ADB -a nodaemon server start > /dev/null 2>&1 &
nohup socat TCP-LISTEN:5037,reuseaddr,fork TCP:${HOST_IP}:5037 > /dev/null 2>&1 &
sleep 1
echo "Forward adb to ${HOST_IP}:5037."
echo

echo "Get adb devices..."
adb devices
}

wsl-stop-adb-daemon() {
echo "Kill running processes..."
pkill -9 socat

# $WSL_HOST_ADB kill-server > /dev/null 2>&1
# adb kill-server > /dev/null 2>&1

pkill -9 adb.exe
pkill -9 adb
sleep 1
echo "Complete"
}

Start the Environment Automatically for Remote Linux Machine

Usage

  1. Setup ssh key for remote machine.
  2. Install adb on local machine.
  3. Install adb on remote machine and change REMOTE_ADB_PATH value to the adb location. Make sure you are using the same adb in terminal and Android Studio. And make sure you installed the same version of adb in local and remote machine.
  4. Add the following content to your local ~/.bashrc and run source ~/.bashrc to refresh.
  5. Run startRemoteAdb USER HOST / stopRemoteAdb USER HOST to start/stop adb environment.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
REMOTE_ADB_PATH='$HOME/Android/Sdk/platform-tools/adb'

_remoteCmd() {
local USER=$1
local HOST=$2
ssh $USER@$HOST $3
}

_remoteAdb() {
local USER=$1
local HOST=$2
_remoteCmd $USER $HOST "$REMOTE_ADB_PATH $3"
}

startRemoteAdb() {
if [ $# -ne 2 ]; then
echo 'Usage: startRemoteAdb USER HOST'
echo 'Example: startRemoteAdb jzj 192.168.5.200'
return 1
fi

local USER=$1
local HOST=$2

stopRemoteAdb $USER $HOST
echo

echo 'Get adb devices on local...'
adb devices
sleep 1
adb kill-server
sleep 1

echo 'Start services...'
nohup adb -a nodaemon server start > /dev/null 2>&1 &
ssh -R 5037:localhost:5037 -f -N $USER@$HOST -o ServerAliveInterval=240

sleep 1
echo "Forward localhost:5037 to $HOST:5037."
echo

echo 'Remote get adb devices...'
_remoteAdb $USER $HOST devices
}

stopRemoteAdb() {
local USER=$1
local HOST=$2

echo 'Kill running processes...'
_remoteAdb $USER $HOST kill-server
adb kill-server
# kill ssh command which contains 5037
ps -lef | grep ssh | grep 5037 | awk "{print \$2}" | xargs kill

sleep 1
echo 'Complete'
}