Configure Android Phone USB Passthrough for a KVM VM on Ubuntu Server

In this post, I configure Android phone USB passthrough for a KVM virtual machine on an Ubuntu Server host.

The goal is:

Physical Android phone
→ Ubuntu KVM host
→ KVM VM
→ adb devices inside the VM

This is useful when the Android phone is physically connected to the KVM host, but I want to use it inside a VM for Android or Flutter development.

This post does not cover installing KVM from scratch. If you have not installed KVM and Cockpit yet, refer to my previous post:


Environment

In this example:

KVM host: Ubuntu Server
VM name: client
Phone: Samsung Galaxy phone
Phone USB ID: 04e8:6860

Inside the VM:

VM user: administrator
Use case: adb / Flutter development

The Android phone is physically plugged into the KVM host, not directly into the VM.


  1. Check the USB Device on the KVM Host

Run this on the KVM host:

lsusb

In my case, I saw two Samsung devices:

Bus 002 Device 004: ID 04e8:4001 Samsung Electronics Co., Ltd PSSD T7
Bus 007 Device 005: ID 04e8:6860 Samsung Electronics Co., Ltd Galaxy series, misc. (MTP mode)

The Samsung T7 external SSD is:

04e8:4001

Do not pass this device through to the VM unless you really mean to.

The Android phone is:

04e8:6860

So the values I need are:

Vendor ID:  04e8
Product ID: 6860

  1. Create a libvirt USB Passthrough XML File

Run this on the KVM host:

sudo mkdir -p /etc/libvirt/usb
sudo nano /etc/libvirt/usb/samsung-phone.xml

Add this XML:

<hostdev mode='subsystem' type='usb'>
  <source startupPolicy='optional'>
    <vendor id='0x04e8'/>
    <product id='0x6860'/>
  </source>
</hostdev>

The important part is:

<vendor id='0x04e8'/>
<product id='0x6860'/>

I also use:

startupPolicy='optional'

This allows the VM to start even when the phone is not currently plugged in.


  1. Attach the USB Device to the VM

If the VM is already running, run this on the KVM host:

sudo virsh attach-device client /etc/libvirt/usb/samsung-phone.xml --live --config

The options mean:

--live    Apply to the currently running VM
--config  Save to the persistent VM configuration

If the VM is stopped, run:

sudo virsh attach-device client /etc/libvirt/usb/samsung-phone.xml --config
sudo virsh start client

Confirm the VM configuration:

sudo virsh dumpxml client | grep -A8 -B2 "04e8"

Expected output:

<hostdev mode='subsystem' type='usb'>
  <source startupPolicy='optional'>
    <vendor id='0x04e8'/>
    <product id='0x6860'/>
  </source>
</hostdev>

  1. Check the Device Inside the VM

SSH into the VM and run:

lsusb | grep Samsung

Expected output:

Bus 001 Device 006: ID 04e8:6860 Samsung Electronics Co., Ltd Galaxy series, misc. (MTP mode)

At this point, USB passthrough is working.

However, ADB may still fail because Linux USB permissions inside the VM are separate from KVM USB passthrough.


  1. Install Android USB Permission Rules Inside the VM

Inside the VM, install the Android udev rules package:

sudo apt update
sudo apt install -y android-sdk-platform-tools-common

This package is separate from the Android SDK you may install manually. Its purpose here is to provide Linux udev rules for Android USB devices.

Make sure the VM user is in the plugdev group:

sudo usermod -aG plugdev administrator

Log out and log back in:

exit

After logging back in, confirm:

id

The output should include:

plugdev

Now test ADB:

adb kill-server
adb start-server
adb devices

If everything is correct, the result should eventually become:

List of devices attached
R5CR80PJYZF     device

If ADB shows:

R5CR80PJYZF     unauthorized

unlock the phone and accept the USB debugging authorization prompt.


  1. Manually Detach on Unplug and Reattach on Replug

When the phone is passed through to the VM, unplugging the physical phone from the KVM host may not immediately remove the USB device from the guest VM.

In other words, after unplugging the phone, the VM may still show the Samsung USB device:

lsusb | grep Samsung

This does not always mean the phone is still usable. It may simply be a stale USB device state inside the guest.

When the phone is physically unplugged, I can manually detach it from the running VM on the KVM host:

sudo virsh detach-device client /etc/libvirt/usb/samsung-phone.xml --live

After that, the VM should no longer show the phone:

lsusb | grep Samsung

When I plug the phone back into the KVM host, first confirm that the host sees it again:

lsusb | grep -i Samsung

Expected output:

ID 04e8:6860 Samsung Electronics Co., Ltd Galaxy series

Then attach it back to the running VM:

sudo virsh attach-device client /etc/libvirt/usb/samsung-phone.xml --live

Now check inside the VM again:

lsusb | grep Samsung
adb devices

Expected ADB result:

List of devices attached
R5CR80PJYZF     device

This manual detach/attach flow confirms the correct behavior:

Physical unplug  → VM should stop seeing the phone
Physical replug  → VM should see the phone again

The optional auto-sync section later automates this same behavior with a host-side udev rule and systemd service.


  1. Optionally Automatically Sync USB State After Unplug and Replug

The previous step showed the manual way to keep the VM USB state in sync with the physical phone state.

When the phone is unplugged, the VM should detach the USB device.

When the phone is plugged back in, the VM should attach it again.

To automate that behavior, I use a host-side udev rule to trigger a systemd service.

This step must be configured on the KVM host, not inside the VM.

  • Create the Host-Side Script

Run this on the KVM host:

sudo vi /usr/local/sbin/samsung-phone-client-usb.sh

Add:

#!/usr/bin/env bash
set -u

ACTION="${1:-add}"
VM="client"
XML="/etc/libvirt/usb/samsung-phone.xml"
VIRSH="/usr/bin/virsh -c qemu:///system"

if ! $VIRSH domstate "$VM" 2>/dev/null | grep -q "running"; then
  exit 0
fi

wait_for_phone() {
  for i in {1..15}; do
    if /usr/bin/lsusb -d 04e8:6860 >/dev/null 2>&1; then
      return 0
    fi
    sleep 1
  done

  return 1
}

case "$ACTION" in
  add)
    # Wait until the phone is fully visible on the host.
    if ! wait_for_phone; then
      exit 0
    fi

    # Clear stale live state if it exists.
    $VIRSH detach-device "$VM" "$XML" --live >/dev/null 2>&1 || true

    # Retry attach because udev can fire before libvirt can use the device.
    for i in {1..10}; do
      if $VIRSH attach-device "$VM" "$XML" --live >/dev/null 2>&1; then
        exit 0
      fi
      sleep 1
    done

    exit 1
    ;;

  remove)
    # The physical device may already be gone. Ignore detach errors.
    $VIRSH detach-device "$VM" "$XML" --live >/dev/null 2>&1 || true
    ;;

  *)
    exit 1
    ;;
esac

Make it executable:

sudo chmod +x /usr/local/sbin/samsung-phone-client-usb.sh
  • Create the systemd Service

Run this on the KVM host:

sudo vi /etc/systemd/system/samsung-phone-client-usb@.service

Add:

[Unit]
Description=Handle Samsung phone USB %i for client VM
After=libvirtd.service

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/samsung-phone-client-usb.sh %i

Reload systemd:

sudo systemctl daemon-reload
  • Create the Host udev Rule

Run this on the KVM host:

sudo vi /etc/udev/rules.d/90-samsung-phone-kvm.rules

Add:

ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="04e8", ATTR{idProduct}=="6860", RUN+="/usr/bin/systemctl --no-block start samsung-phone-client-usb@add.service"
ACTION=="remove", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="4e8/6860/*", RUN+="/usr/bin/systemctl --no-block start samsung-phone-client-usb@remove.service"

This rule is different from Android ADB udev rules.

This host-side rule does this:

USB add/remove event
→ systemd service
→ virsh attach-device / detach-device
→ phone is attached to or detached from the VM

The Android ADB rule inside the VM does this:

USB device inside VM
→ normal user can access it
→ adb devices works

They solve different problems.

Reload the host udev rules:

sudo udevadm control --reload-rules
sudo systemctl daemon-reload

Now monitor the service logs:

sudo journalctl -u 'samsung-phone-client-usb@*' -f

Unplug the phone and plug it back in.

You should see the remove and add services run.

Then check inside the VM:

lsusb | grep Samsung
adb devices

Did this guide save you time?

Support this site

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top