KDEConnect/Android Emulator: Difference between revisions
No edit summary |
Johnveness (talk | contribs) (Tidying) |
||
(11 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
== Running KDE Connect in an Android Emulator == | |||
== Running | The Android emulator uses the default qemu [https://wiki.qemu.org/Documentation/Networking#User_Networking_.28SLIRP.29 User Networking (SLIRP) backend] which does not allow the emulator to be directly accessible from the host nor the local network. This prevents kdeconnect running on the desktop from seeing kdeconnect running in an emulator. In order to get a fully working network in the emulator it needs to be configured to use the tap networking backend which as an added bonus offers much better performance than the default user backend. | ||
The Android emulator uses the default qemu [https://wiki.qemu.org/Documentation/Networking#User_Networking_.28SLIRP.29 User Networking (SLIRP) backend] which does not allow the emulator to be directly accessible from the host nor the local network | |||
Running the emulator with the tap backend will create a virtual network device on the host machine that can | Running the emulator with the tap backend will create a virtual network device on the host machine that can then be configured as if it is a real ethernet card allowing you to create virtually any type of network topology. The most straightforward topology that can be created is [[Special:myLanguage/KDEConnect/Android_Emulator#The_public_bridge_setup|the public bridge setup]]. In this setup we simply put both the emulator's virtual interface and the desktop's lan interface into a bridge so they will share the same network space (e.g. single IP-subnet). Another topology that can be used is [[Special:myLanguage/KDEConnect/Android_Emulator#The_routing_with_iptables_setup|the routing with iptables setup]]. This involves a little more work but will work in situations where your lan device does not support bridging (e.g. some wireless drivers). | ||
<span id="The public bridge setup"></span> | <span id="The public bridge setup"></span> | ||
Line 9: | Line 8: | ||
== The public bridge setup == | == The public bridge setup == | ||
Setting up your system and the | Setting up your host system and the Android emulator to use the public bridge setup requires changes on both sides. These changes are described in the following sections. | ||
=== Configuring the host machine === | === Configuring the host machine === | ||
First you will have to unconfigure your | First you will have to unconfigure your LAN interface, create the bridge, add your LAN interface to it and assign the bridge an IP address. Assuming your LAN interface is eth0 and the bridge interface you want to create is br0: | ||
{{Input|1=<nowiki> | {{Input|1=<nowiki> | ||
sudo ifconfig eth0 0.0.0.0 | sudo ifconfig eth0 0.0.0.0 | ||
Line 20: | Line 19: | ||
dhclient br0 | dhclient br0 | ||
</nowiki>}} | </nowiki>}} | ||
To make the above changes permanent do the following | To make the above changes permanent do the following [https://www.linux-kvm.org/page/Networking taken from kvm docs] and reboot your system: | ||
{| class="wikitable" | {| class="wikitable" | ||
!System !! Changes | !System !! Changes | ||
Line 73: | Line 72: | ||
To list available devices to use as <avd_name> use: | To list available devices to use as <avd_name> use: | ||
{{input|1=<nowiki>emulator -list-avds</nowiki>}} | {{input|1=<nowiki>emulator -list-avds</nowiki>}} | ||
If you want to run more than | If you want to run more than one emulator at a time you will also have to provide a MAC address to be used by the emulator: | ||
{{input|1=<nowiki> | {{input|1=<nowiki> | ||
MAC=`printf '52:54:00:12:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256))` | MAC=`printf '52:54:00:12:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256))` | ||
emulator -avd <avd_name> -qemu --device virtio-net-pci,netdev=n1,mac=${MAC} -netdev tap,id=n1,"helper=/usr/libexec/qemu-bridge-helper --br=br0"&</nowiki>}} | emulator -avd <avd_name> -qemu --device virtio-net-pci,netdev=n1,mac=${MAC} -netdev tap,id=n1,"helper=/usr/libexec/qemu-bridge-helper --br=br0"&</nowiki>}} | ||
=== Configuring the Android emulator === | |||
Now that we have the host system setup its time to make things work in the emulator. | |||
First put Android in airplane mode by dragging down the notification bar and pressing the airplane icon. | |||
Then get a root shell in the emulator: | |||
Then get a root shell in the emulator | |||
{{input|1=<nowiki> | {{input|1=<nowiki> | ||
adb -s emulator-5554 shell | adb -s emulator-5554 shell | ||
su</nowiki>}} | su</nowiki>}} | ||
Next start a dhcpclient on eth1 to configure the interface | Next start a dhcpclient on eth1 to configure the interface. For an emulator with API level > 24 issue: | ||
For | |||
{{input|1=<nowiki>daemonize dhcpclient -i eth1</nowiki>}} | {{input|1=<nowiki>daemonize dhcpclient -i eth1</nowiki>}} | ||
For an emulator with API Level > 22 and <= 24 issue | For an emulator with API Level > 22 and <= 24 issue: | ||
{{input|1=<nowiki>dhcptool eth1</nowiki>}} | {{input|1=<nowiki>dhcptool eth1</nowiki>}} | ||
For anything older issue | For anything older issue: | ||
{{input|1=<nowiki> | {{input|1=<nowiki> | ||
mkdir /data/misc/dhcp | mkdir /data/misc/dhcp | ||
dhcpcd -b eth1 | dhcpcd -b eth1 | ||
</nowiki>}} | </nowiki>}} | ||
Make normal routing take precedent over anything that | Make normal routing take precedent over anything that Google/qemu configured. If <code>ip</code> does not work use <code>busybox ip</code> instead | ||
{{input|1=<nowiki>ip rule add from all lookup main pref 99</nowiki>}} | {{input|1=<nowiki>ip rule add from all lookup main pref 99</nowiki>}} | ||
'''Almost there''' | '''Almost there''' | ||
Take android out of airplane mode and for API levels > 24 wait until wlan0 is up again | |||
For an emulator with API level > 24 make dns lookups work again by | Take android out of airplane mode and for API levels > 24 wait until wlan0 is up again. | ||
For an emulator with API level > 24 make dns lookups work again by issuing: | |||
{{input|1=<nowiki>ip ro add 10.0.2.3 via 192.168.232.1 dev wlan0</nowiki>}} | {{input|1=<nowiki>ip ro add 10.0.2.3 via 192.168.232.1 dev wlan0</nowiki>}} | ||
And for an emulator with API level <= 23 delete the default route sending everything through the SLIRP interface | And for an emulator with API level <= 23 delete the default route sending everything through the SLIRP interface: | ||
{{input|1=<nowiki>ip ro del default via 10.0.2.2</nowiki>}} | {{input|1=<nowiki>ip ro del default via 10.0.2.2</nowiki>}} | ||
You should be able to figure out what to do if the ip command does not | You should be able to figure out what to do if the ip command does not exist. | ||
'''Congratulations you are now the proud owner of an Android emulator with proper networking''' | '''Congratulations you are now the proud owner of an Android emulator with proper networking.''' | ||
=== And then there was a script to do most of the hard work for you === | === And then there was a script to do most of the hard work for you === | ||
Because like me you probably don't want to do that every day I've | Because like me you probably don't want to do that every day I've created a little script to do all the hard work for you. | ||
{{Warning|Be warned though - I'm a Fedora person so running this on anything else will probably require some changes. <br />Please feel free to contribute | {{Warning|Be warned though - I'm a Fedora person so running this on anything else will probably require some changes. <br />Please feel free to contribute your changes!}} | ||
{{Output|<syntaxhighlight style="height: 360px;"> | {{Output|<syntaxhighlight lang="bash" style="height: 360px;"> | ||
#!/bin/sh | #!/bin/sh | ||
# Copyright 2018 Erik Duisters | # Copyright 2018 Erik Duisters | ||
# | # | ||
# This program is free software; you can redistribute it and/or | # This program is free software; you can redistribute it and/or | ||
Line 164: | Line 163: | ||
sleep 5 | sleep 5 | ||
SDK=" | SDK="" | ||
while | while [[ -z $SDK ]] | ||
do | do | ||
SDK=`adb -s $EMULATOR shell getprop ro.build.version.sdk | sed 's/.*\([0-9][0-9]\).*/\1/'` | SDK=`adb -s $EMULATOR shell getprop ro.build.version.sdk | sed 's/.*\([0-9][0-9]\).*/\1/'` | ||
Line 235: | Line 234: | ||
echo "Configuration complete" | echo "Configuration complete" | ||
</syntaxhighlight>}} | </syntaxhighlight>}} | ||
<span id="The routing with iptables setup"></span> | |||
== The routing with iptables setup == | == The routing with iptables setup == | ||
{{Note| | {{Note|When using this setup both parties will not receive each others broadcast packets so you will have to connect by IP address.}} | ||
=== Configuring the host machine === | |||
Since you do not want to run the emulator as the super user you will have to grant normal users permission to use tap devices. | |||
:Create a net udev rule that creates the net/tun device file with the needed permission: | |||
:{{Input|1=<nowiki>sudo vi /etc/udev/rules.d/00-net-tun.rules</nowiki>}} | |||
:The contents should be: | |||
:{{Output|1=<nowiki>KERNEL=="tun", GROUP="netdev", MODE="0660", OPTIONS+="static_node=net/tun"</nowiki>}} | |||
:Create a new group netdev and add yourself to it: | |||
:{{Input|1=<nowiki> | |||
sudo groupadd netdev | |||
sudo usermod -a -G netdev `whoami`</nowiki>}} | |||
:Now reboot your system so the changes take effect. | |||
Configure the host system to support the routed setup | |||
:Create and bring up a new tap device: | |||
:{{Input|1=<nowiki> | |||
sudo ip tuntap add tap0 mode tap user `whoami` | |||
sudo ip link set tap0 up | |||
</nowiki>}} | |||
:Allow ip forwarding: | |||
:{{Input|1=<nowiki>sudo sysctl -w net.ipv4.ip_forward=1</nowiki>}} | |||
:Allow proxy_arp so the host will respond to "who has" arp messages for the emulator: | |||
:{{Input|1=<nowiki>sudo sh -c "echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp"</nowiki>}} | |||
:Route all traffic for the emulator through the tap device (use an address in your subnet): | |||
:{{Input|1=<nowiki>sudo ip ro add 192.168.0.100 dev tap0</nowiki>}} | |||
:Allow traffic to and from the emulator (you can use tap+ instead of tap0 to allow all tap devices): | |||
:{{Input|1=<nowiki> | |||
sudo iptables -I FORWARD 1 -i tap0 -j ACCEPT | |||
sudo iptables -I FORWARD 1 -o tap0 -j ACCEPT | |||
sudo iptables -I INPUT 1 -i tap0 -j ACCEPT | |||
sudo iptables -I OUTPUT 1 -o tap0 -j ACCEPT | |||
</nowiki>}} | |||
:Time to start the emulator: | |||
:{{Input|1=<nowiki>emulator -avd <avd-name> -qemu --device virtio-net-pci,netdev=n1 -netdev tap,id=n1,ifname=tap0,script=no,downscript=no</nowiki>}} | |||
=== Configuring the Android emulator === | |||
Now that the host is configured a couple of things need to be configured in the emulator. | |||
:Start a shell in the emulator and become root: | |||
:{{Input|1=<nowiki> | |||
adb -s emulator-5554 shell | |||
su</nowiki>}} | |||
:Assign an IP address to the tap device: | |||
:{{Input|1=<nowiki>ifconfig eth1 192.168.0.100</nowiki>}} | |||
:Configure the default gateway (use the address of your desktop's LAN interface here): | |||
:{{Input|1=<nowiki>ip ro add default via 192.168.0.2</nowiki>}} | |||
:Make normal routing take precedent over anything that Google/qemu configured: | |||
:{{Input|1=<nowiki>ip rule add from all lookup main pref 99</nowiki>}} | |||
:Make DNS lookups work again: | |||
:{{Input|1=<nowiki>ip ro add 10.0.2.3 via 192.168.232.1 dev wlan0</nowiki>}} | |||
Have fun. Remember broadcasts do not work in this setup so you will have to configure the IP address of the host machine in kdeconnect on the emulator (overflow menu->Add devices by IP). |
Latest revision as of 17:34, 28 April 2024
Running KDE Connect in an Android Emulator
The Android emulator uses the default qemu User Networking (SLIRP) backend which does not allow the emulator to be directly accessible from the host nor the local network. This prevents kdeconnect running on the desktop from seeing kdeconnect running in an emulator. In order to get a fully working network in the emulator it needs to be configured to use the tap networking backend which as an added bonus offers much better performance than the default user backend.
Running the emulator with the tap backend will create a virtual network device on the host machine that can then be configured as if it is a real ethernet card allowing you to create virtually any type of network topology. The most straightforward topology that can be created is the public bridge setup. In this setup we simply put both the emulator's virtual interface and the desktop's lan interface into a bridge so they will share the same network space (e.g. single IP-subnet). Another topology that can be used is the routing with iptables setup. This involves a little more work but will work in situations where your lan device does not support bridging (e.g. some wireless drivers).
The public bridge setup
Setting up your host system and the Android emulator to use the public bridge setup requires changes on both sides. These changes are described in the following sections.
Configuring the host machine
First you will have to unconfigure your LAN interface, create the bridge, add your LAN interface to it and assign the bridge an IP address. Assuming your LAN interface is eth0 and the bridge interface you want to create is br0:
sudo ifconfig eth0 0.0.0.0 sudo ip link add br0 type bridge sudo ip link set eth0 master br0 dhclient br0
To make the above changes permanent do the following taken from kvm docs and reboot your system:
System | Changes |
---|---|
RedHat/Fedora |
DEVICE=br0 BOOTPROTO=dhcp ONBOOT=yes TYPE=Bridge STP=no ZONE=<the same zone as eth0 is in> |
Debian | Edit /etc/network/interfaces
# Replace old eth0 config with br0 auto # Use old eth0 config for br0 and configure the bridge iface br0 inet dhcp bridge_ports eth0 bridge_stp off bridge_maxwait 0 bridge_fd 0 |
SuSE |
|
Next you have to allow qemu-bridge-helper to add tap interfaces to this bridge, using your favorite text editor:
sudo vi /etc/qemu/bridge.conf
- and add the following line:
allow br0
You can now start the emulator using the following command replacing <avd_name> with the name of an existing emulator:
emulator -avd <avd_name> -qemu --device virtio-net-pci,netdev=n1 -netdev tap,id=n1,"helper=/usr/libexec/qemu-bridge-helper --br=br0"&
To list available devices to use as <avd_name> use:
emulator -list-avds
If you want to run more than one emulator at a time you will also have to provide a MAC address to be used by the emulator:
MAC=`printf '52:54:00:12:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256))` emulator -avd <avd_name> -qemu --device virtio-net-pci,netdev=n1,mac=${MAC} -netdev tap,id=n1,"helper=/usr/libexec/qemu-bridge-helper --br=br0"&
Configuring the Android emulator
Now that we have the host system setup its time to make things work in the emulator.
First put Android in airplane mode by dragging down the notification bar and pressing the airplane icon.
Then get a root shell in the emulator:
adb -s emulator-5554 shell su
Next start a dhcpclient on eth1 to configure the interface. For an emulator with API level > 24 issue:
daemonize dhcpclient -i eth1
For an emulator with API Level > 22 and <= 24 issue:
dhcptool eth1
For anything older issue:
mkdir /data/misc/dhcp dhcpcd -b eth1
Make normal routing take precedent over anything that Google/qemu configured. If ip
does not work use busybox ip
instead
ip rule add from all lookup main pref 99
Almost there
Take android out of airplane mode and for API levels > 24 wait until wlan0 is up again.
For an emulator with API level > 24 make dns lookups work again by issuing:
ip ro add 10.0.2.3 via 192.168.232.1 dev wlan0
And for an emulator with API level <= 23 delete the default route sending everything through the SLIRP interface:
ip ro del default via 10.0.2.2
You should be able to figure out what to do if the ip command does not exist.
Congratulations you are now the proud owner of an Android emulator with proper networking.
And then there was a script to do most of the hard work for you
Because like me you probably don't want to do that every day I've created a little script to do all the hard work for you.
#!/bin/sh # Copyright 2018 Erik Duisters # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License or (at your option) version 3 or any later version # accepted by the membership of KDE e.V. (or its successor approved # by the membership of KDE e.V.), which shall act as a proxy # defined in Section 14 of version 3 of the license. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # Tested with emulators API 28-15 (excl 20) # API 15 has ash to [[ ]] does not work but networking seems to come up like it should if [ -z "$1" ] then echo "Error: No avd specified use one of" emulator -list-avds exit 1 fi #https://www.linux-kvm.org/page/Networking #https://serverfault.com/questions/308091/set-mac-address-in-qemu-kvm-properties-file MAC=`printf '52:54:00:12:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256))` emulator -avd $1 -qemu -device virtio-net-pci,netdev=n1,mac=$MAC -netdev tap,id=n1,"helper=/usr/libexec/qemu-bridge-helper --br=br0"& sleep 5 #TODO: Need a better way to get the emulator number EMULATOR=`adb devices | grep emulator | tail -n1 | cut -f 1` echo "Waiting until $EMULATOR boot is complete" adb -s $EMULATOR wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;' echo "Boot complete - Configuring bridge mode networking" sleep 5 SDK="" while [[ -z $SDK ]] do SDK=`adb -s $EMULATOR shell getprop ro.build.version.sdk | sed 's/.*\([0-9][0-9]\).*/\1/'` done echo "Emulator has sdk version: ${SDK}" IP="ip" if (($SDK == 18)) then IP="busybox ip" fi echo "Turning airplane mode on" adb -s $EMULATOR shell "su 0 settings put global airplane_mode_on 1" adb -s $EMULATOR shell "su 0 am broadcast -a android.intent.action.AIRPLANE_MODE" if (($SDK > 24)) then echo "Waiting for wlan0 to go down" while ! `adb -s emulator-5554 shell "su 0 ip link show wlan0" | grep -q "state DOWN"`; do sleep 2; done fi echo "Starting dhcpclient for eth1" if (($SDK > 24)) then echo "using dhcpclient" adb -s $EMULATOR shell "su 0 daemonize dhcpclient -i eth1" elif (($SDK > 22)) then echo "using dhcptool" adb -s $EMULATOR shell "su 0 dhcptool eth1" else echo "using dhcpcd" if (($SDK <= 16)) then mkdir /data/misc/dhcp fi adb -s $EMULATOR shell "su 0 dhcpcd -b eth1" fi adb -s $EMULATOR shell "su 0 ${IP} rule add from all lookup main pref 99" sleep 2 echo "Turning airplane mode off" adb -s $EMULATOR shell "su 0 settings put global airplane_mode_on 0" adb -s $EMULATOR shell "su 0 am broadcast -a android.intent.action.AIRPLANE_MODE" if (($SDK > 24)) then echo "Waiting for wlan0 to come UP" while ! `adb -s emulator-5554 shell "su 0 ip link show wlan0" | grep -q "state UP"`; do sleep 2; done sleep 2 echo "Re-enabling dns lookups" adb -s $EMULATOR shell "su 0 ip ro add 10.0.2.3 via 192.168.232.1 dev wlan0" elif (($SDK <= 23)) then adb -s $EMULATOR shell "su 0 ${IP} ro del default via 10.0.2.2" fi echo "Configuration complete"
The routing with iptables setup
Configuring the host machine
Since you do not want to run the emulator as the super user you will have to grant normal users permission to use tap devices.
- Create a net udev rule that creates the net/tun device file with the needed permission:
sudo vi /etc/udev/rules.d/00-net-tun.rules
- The contents should be:
KERNEL=="tun", GROUP="netdev", MODE="0660", OPTIONS+="static_node=net/tun"
- Create a new group netdev and add yourself to it:
sudo groupadd netdev sudo usermod -a -G netdev `whoami`
- Now reboot your system so the changes take effect.
Configure the host system to support the routed setup
- Create and bring up a new tap device:
sudo ip tuntap add tap0 mode tap user `whoami` sudo ip link set tap0 up
- Allow ip forwarding:
sudo sysctl -w net.ipv4.ip_forward=1
- Allow proxy_arp so the host will respond to "who has" arp messages for the emulator:
sudo sh -c "echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp"
- Route all traffic for the emulator through the tap device (use an address in your subnet):
sudo ip ro add 192.168.0.100 dev tap0
- Allow traffic to and from the emulator (you can use tap+ instead of tap0 to allow all tap devices):
sudo iptables -I FORWARD 1 -i tap0 -j ACCEPT sudo iptables -I FORWARD 1 -o tap0 -j ACCEPT sudo iptables -I INPUT 1 -i tap0 -j ACCEPT sudo iptables -I OUTPUT 1 -o tap0 -j ACCEPT
- Time to start the emulator:
emulator -avd <avd-name> -qemu --device virtio-net-pci,netdev=n1 -netdev tap,id=n1,ifname=tap0,script=no,downscript=no
Configuring the Android emulator
Now that the host is configured a couple of things need to be configured in the emulator.
- Start a shell in the emulator and become root:
adb -s emulator-5554 shell su
- Assign an IP address to the tap device:
ifconfig eth1 192.168.0.100
- Configure the default gateway (use the address of your desktop's LAN interface here):
ip ro add default via 192.168.0.2
- Make normal routing take precedent over anything that Google/qemu configured:
ip rule add from all lookup main pref 99
- Make DNS lookups work again:
ip ro add 10.0.2.3 via 192.168.232.1 dev wlan0
Have fun. Remember broadcasts do not work in this setup so you will have to configure the IP address of the host machine in kdeconnect on the emulator (overflow menu->Add devices by IP).