Running adb in a rootless Podman Distrobox container
Tags: tutorial, android, productivity, container
Published: 2024-05-23 19:20:19

`adb` stands for [_Android Debug Bridge_](https://developer.android.com/tools/adb). It's a part of [SDK Platform Tools](https://developer.android.com/tools/releases/platform-tools), which is bundled with [Android Studio](https://developer.android.com/studio). 

For Linux users, they might want to use `adb` with `scrcpy` (https://github.com/Genymobile/scrcpy), which is a very powerful tool for controlling Android devices from PC. Installing `scrcpy` from the distro's repo would bring in `adb` by default, so it's not necessary to download `adb` directly from Google.

# Why would anyone use `adb` in a container?

Like most apps that anyone would want to run in a container: 
- It _doesn't_ pile up your system with a ton of packages/dependencies.
- You always get the latest _official_ release of apps, regardless of your Linux distro.
- You can easily delete _all_ the app data and its configurations.
- It works with _immutable_ OSes very well. 
- Minimizing the apps' system access through a _rootless_ environment.
- Maybe more. 😎

> Note, Distrobox gives you a convenient over raw Podman/Docker setup, and it also integrates very well in the system. But if you want the _absolute_ security, please consider setting up a rootless Podman container without using Distrobox. However, I will go with Distrobox, as I think a rootless Distrobox container already gives you a sane amount of security-convenient ratio.

👉️ Table of contents:

1. Know Your Device
2. `udev` Rules Setup on the Host
3. Preparing the Container
4. Testing `adb`
5. Automatically Update the Container

---

# 1. Know Your Device

You can identify your device easily with:

```
lsusb
```

It will list all USB related devices. Look for a line that's corresponding to your Android device. For example:

```
Bus 001 Device 009: ID 1234:5678 Google Inc. Nexus/Pixel Device (charging + debug)
```

The important part is your device ID, which is `1234:5678` in this example. We'll use this ID in the next step.

---

# 2. `udev` Rules Setup on the Host

In `/etc/udev/rules.d/51-android.rules` I put:

```
SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTRS{idProduct}=="5678", MODE="0666", GROUP="yourusername"
```

- If yours doesn't have `51-android.rules` in `/etc/udev/rules.d/`, please create a new one.
- Replace `ATTR{idVendor}=="1234"` and `ATTRS{idProduct}=="5678"` with your real device ID.
- Replace `yourusername` with your real username.

---

# 3. Preparing the Container

## 3.1. Install Distrobox and Podman on the Host

For example, on openSUSE Tumbleweed:

```
sudo zypper install distrobox podman
```

## 3.2. Configure Distrobox to use Podman

```
echo 'container_manager="podman"' > ~/.config/distrobox/distrobox.conf
```

## 3.3. Create a New Distrobox Container for `adb`

```
distrobox create -i docker.io/library/archlinux:latest -n adb-dbx -H ~/distrobox/adb-dbx --volume /dev/bus/usb/:/dev/bus/usb --volume /etc/udev/rules.d/:/etc/udev/rules.d --additional-packages "adwaita-cursors" 
```

I use Arch container image because:

- It's a rolling image, so every necessary package or dependency would always be updated.
- It really depends on your needs. If you plan to use this container with `scrcpy`, the best container for `adb` would be Arch, since you will get all the codecs from the main repo. If you plan to use this container as a dev box, Tumbleweed image would be better because Chrome is _not_ available _officially_ on Arch. But if you only want to run `adb`, the container image wouldn't matter much.

I volume `/dev/bus/usb/` and `/etc/udev/rules.d/` in the container because they're needed for `adb` to work.

---

# 4. Testing `adb`

```
adb devices
```

This should return your device properly. If it's not, please check whether you have `adb` process already running in the background. In that case, please end the process first.

---

# 5. Automatically Update the Container

We can use systemd's service and timer to update/upgrade all Distrobox's containers like this:

## dbx-upgrade.service
```
[Unit]
Description=Upgrade all rootless Distrobox containers.
RequiresMountsFor=/run/user/1000/containers

[Service]
Type=exec
ExecStart=-bash -c "distrobox-upgrade --all"
Restart=on-failure
RestartSec=60
TimeoutStopSec=5min
RemainAfterExit=yes
```

Save this file as `~/.config/systemd/user/dbx-upgrade.service`.

## dbx-upgrade.timer
```
[Unit]
Description=Run distrobox-upgrade --all daily.

[Timer]
OnCalendar=daily
RandomizedDelaySec=5min
Persistent=true

[Install]
WantedBy=timers.target
```

Save this file as `~/.config/systemd/user/dbx-upgrade.timer`.

## Enable the Timer
```
systemctl --user daemon-reload && systemctl --user enable dbx-upgrade.timer
```

---

Cover Photo by [Edho Fitrah](https://unsplash.com/@dhofit?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash) on [Unsplash](https://unsplash.com/photos/person-standing-in-front-of-bridge-sBUhP60IlAo?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash)