このリポジトリは、Waydroid本体をUbuntuホストで動かし、DockerはADB操作・診断・任意の
ループバックプロキシに限定する構成です。nested-waydroidは再現実験用であり、本番構成ではありません。
現在のアプリデータを別PCへ複製し、clone後に1コマンドで復元する手順は README-PORTABLE.md を参照してください。
- Docker内での安定運用: 起動例は作れますが、Waydroid(LXC)をDockerへネストし、
privileged、host cgroup、binderfs、mount操作を与える必要があります。公式の本番構成ではなく、 更新・cgroup・AppArmor・mount propagationの影響も受けるため、安定運用可能とは判定しません。 - 実SSID一覧: 標準Waydroidイメージでは表示・スキャンできません。Linuxのveth/Ethernet接続を Androidへ見せているので、周辺APをスキャンする物理Wi-Fi HALがありません。
- Androidから物理Wi-Fiへ直接接続: 標準構成ではできません。USB NICをLinuxコンテナへ移して
iwで使えることと、AndroidのSettings/WifiManagerから使えることは別です。 - インターホンと同じLAN: 「同じL2の独立端末」とは限りませんが、標準NATでもAndroidからLANへの unicastは可能です。本リポジトリのproxy ARP/routing構成ではLAN側IPを追加でき、今回の環境で動作確認済みです。 ただし、Wi-Fiホスト上で別MACを持つ独立したL2端末になる構成ではありません。
- Broadcast/Multicast/mDNS: 標準NATではセグメントを越えません。Avahi reflector、SSDP relay、 機器固有UDP relayを追加して中継します。本リポジトリではAiphoneアプリの探索通信 (要求UDP/51711、応答UDP/51712)を専用relayで中継し、親機を検出できることを確認済みです。
- 推奨: Ubuntu 24.04上でWaydroidを直接実行し、headless Westonとsystemdで常駐させます。 ADB操作だけDocker化し、探索通信は必要なプロトコルだけ中継します。SSIDまたは端末完全性が認証条件なら、 常時給電したAndroid実機が最も確実です。
詳細な根拠は feasibility.md と wifi-limitations.md にあります。
2026-08-01に、Wi-Fi接続したUbuntuホスト上のWaydroidからAiphoneアプリ
(package: jp.co.aiphone.refine)を起動し、物理LAN上の親機を探索できることを確認しました。
確認時の構成は次のとおりです。
| 項目 | 確認時の値 |
|---|---|
| ホストのWi-Fi interface | wlp0s20f3 |
| ホストの物理LAN | 192.168.0.0/24 |
| ルーター | 192.168.0.1 |
| 親機 | 192.168.0.17 |
| Waydroidの通常IP | 192.168.240.112 |
| Waydroidへ追加したLAN側IP | 192.168.0.250 |
成功に必要だったのは、Waydroidへの物理LAN側IP追加、対象packageへのFake Wi-Fi、wlan0互換dummy
interface、Aiphone専用の双方向UDP relayです。別環境ではinterface名、subnet、空きIP、親機IPを読み替えてください。
外部PC -- SSH/ADB tunnel --> Ubuntu Server (wlan0, 家庭内LAN)
|-- Waydroid (host LXC, waydroid0/veth, NAT)
| `-- Android / adbd / target app
|-- Weston headless + systemd
|-- optional mDNS/SSDP/UDP relay
`-- Docker adb-tools / loopback adb-proxy
|
インターホン <------ unicast / verified discovery relay ------+
- Ubuntu Server 22.04 (jammy) または24.04 (noble)、x86_64
- 推奨は24.04。新しいHWE/6.8系カーネルと長い残存サポート期間のためです。22.04も公式リポジトリの 対象ですが、実際のカーネルconfigとGPU/ソフトウェア描画を必ず検査します。
- Docker EngineとCompose plugin(ADBツール用)
- 4GB以上のRAM、Android image/data用に20GB以上の空き容量を推奨
CONFIG_ANDROID_BINDER_IPC、CONFIG_ANDROID_BINDERFS- namespaces、cgroup v2、veth/bridge、overlayfs、netfilter/NAT
/dev/driはGPU描画時のみ必要。ソフトウェア描画なら必須ではありません。- 新しいWaydroidは
/dev/ashmemがなければsys.use_memfd=trueを設定します。したがってmodern Ubuntuでashmem_linuxは必須ではありません。binderは必須です。
確認:
uname -a
grep -E 'CONFIG_ANDROID_BINDER(_IPC|FS)=' /boot/config-"$(uname -r)"
grep -E 'binder|overlay' /proc/filesystems
docker version
docker compose versioncp config/network.env.example config/network.env
# HOST_LAN_IF、ROUTER_IP、INTERCOM_IPを編集
sudo WAYDROID_USER="$USER" ./scripts/install-host-dependencies.shスクリプトは公式Waydroid aptリポジトリ、binderfs、headless compositor、ADB/診断ツールを準備します。 ダウンロードしたリポジトリスクリプトをrootで実行するため、運用組織では実行前に内容と署名方針を監査してください。
Googleサービス不要なら:
sudo waydroid init -s VANILLA
sudo systemctl enable --now waydroid-container.service
waydroid statusGoogle Playが必要なら、新規初期化時に代わりに次を使います。
sudo waydroid init -s GAPPSVANILLAとGAPPSを同じデータへ重ねて初期化しません。GAPPS imageでもPlay Protect未認証になる場合があり、 公式手順に従ってAndroid IDをGoogleのuncertified-deviceページへ登録します。Google認証情報やADB秘密鍵は リポジトリに保存しないでください。Play Integrityの合格は保証されません。
GPUが利用できず起動しない場合だけ、config/waydroid.cfg の[properties]を
/var/lib/waydroid/waydroid.cfgの同じセクションへマージし、適用します。
sudoedit /var/lib/waydroid/waydroid.cfg
sudo waydroid upgrade -o設定ファイル全体をサンプルで上書きしてはいけません。
インストールスクリプトがunitと/etc/default/waydroid-headlessを配置します。
sudo systemctl enable --now waydroid-docker.service
systemctl status waydroid-docker.service waydroid-container.service
sudo journalctl -u waydroid-docker.service -f
waydroid status
waydroid shell getprop ro.build.version.releaseこのunitは非rootユーザーとしてD-Bus sessionとWeston headless backendを起動します。物理画面は不要です。
WAYDROID_USERを変更した場合は次を実行します。
sudoedit /etc/default/waydroid-headless
sudo loginctl enable-linger <user>
sudo systemctl restart waydroid-docker.service./scripts/install-apk.sh ./app.apk
waydroid app list
waydroid app launch com.example.appx86_64 host用Waydroidではx86/x86_64 APKが基本です。ARM-only APKはそのままでは動きません。
communityのwaydroid_scriptでlibndk-translationまたはlibhoudiniを追加できる場合がありますが、
公式imageの標準機能ではなく、全ABI/JNI/DRMを保証しません。導入前にimageをバックアップし、入手物を監査してください。
まずWaydroid IPを確認し、ホスト上のADB鍵をAndroid画面で一度認証します。
cat /var/lib/misc/dnsmasq.waydroid0.leases
waydroid adb connect
adb devices -lDocker toolboxを使う場合(別のADB鍵なので初回承認が必要):
docker compose --profile tools up -d adb-tools
docker compose exec adb-tools adb connect 192.168.240.2:5555
docker compose exec adb-tools adb devices -l外部へADBを平文公開しません。config/network.envのIPをCompose環境へ渡してloopback proxyを起動し、
SSH tunnelを使います。
set -a; source config/network.env; set +a
docker compose up -d adb-proxy
# 外部PCで
ssh -N -L 5555:127.0.0.1:5555 ubuntu@server
adb connect 127.0.0.1:5555
scrcpy -s 127.0.0.1:5555scrcpyは専用server portを恒久公開せず、ADB transportを利用します。headless compositorでのscrcpy可否は
GPU/codec/imageごとに確認してください。認証プロンプトを確認できない場合は一時的なローカルWayland画面、
既に認証済みのADB鍵、または実機を利用し、ro.adb.secure=0にはしません。
外部操作例:
adb shell monkey -p com.example.app 1
adb shell input tap 500 800
adb shell input swipe 500 1000 500 300 500
adb shell input text 'test'
adb exec-out screencap -p > screenshot.png
adb shell screenrecord --time-limit 30 /sdcard/demo.mp4
adb pull /sdcard/demo.mp4
adb shell uiautomator dump /sdcard/window.xml
adb pull /sdcard/window.xmlまずNAT/unicastだけで検証します。
./scripts/test-network.sh all | tee network-test.logアプリがAndroid自身のIPと親機が同一subnetであることを要求する場合、Wi-Fi uplinkではmacvlanの代わりに
routed/proxy-ARP方式を使えます。config/network.envで未使用のANDROID_LAN_IPを指定し、ルーターの
DHCP配布範囲から除外(または固定予約)してから適用します。
sudo ./scripts/setup-network.sh ./config/network.env
systemctl status waydroid-same-lan.service
sudo nsenter -t "$(sudo lxc-info -P /var/lib/waydroid/lxc -n waydroid -pH)" -n ip -br addrAndroidには従来の192.168.240.x(Internet/NAT)と物理LAN側IPの両方が付きます。Wi-Fi AP側からは
親PCと同じMACに複数IPが見える構成です。同一subnetのunicastは可能になりますが、L2 broadcastを
透過するものではないため、探索方式に応じて以下のrelayも併用します。アプリが
NetworkCapabilities.TRANSPORT_WIFIを必須にする場合は、そのpackageだけをFAKE_WIFI_PACKAGESへ指定します。
これは接続種別の報告を変えるだけで、SSID scanや物理Wi-Fi HALを追加する設定ではありません。
対象アプリの探索が失敗した場合に限り、relayを一つずつ有効化します。
sudoedit config/network.env
# 例: ENABLE_MDNS_REFLECTOR=yes
sudo ./scripts/setup-network.sh ./config/network.env
sudo ./scripts/test-network.sh capture 30- mDNS: Avahi reflector (
224.0.0.251:5353) - SSDP:
udp-broadcast-relay-redux(239.255.255.250:1900)、別途レビューしてインストール - UDP broadcast: 機器の実ポートを
BROADCAST_PORTSへ指定
別LAN端末を受信側にして往復テストします。
./scripts/test-network.sh listen 37020
./scripts/test-network.sh send-broadcast 192.168.1.255 37020 hello
./scripts/test-network.sh send-multicast 239.255.255.250 1900 testプロセス起動だけを合格にせず、wlan側とwaydroid0側のtcpdump、Android発信、LAN端末発信の4点を確認します。
詳細は networking.md を参照してください。
まず、ホスト側のinterface名、subnet、親機IP、Waydroidの現在のIPを確認します。
ip -br address
ip route
cat /var/lib/misc/dnsmasq.waydroid0.leasesconfig/network.envを次のように設定します。以下は確認時の値なので、特にHOST_LAN_IF、各IP、
ANDROID_LAN_IPを自分のLANに合わせて変更してください。ANDROID_LAN_IPにはDHCP配布範囲外の未使用IP、
またはルーターで固定予約したIPを使います。
HOST_LAN_IF=wlp0s20f3
WAYDROID_IF=waydroid0
ROUTER_IP=192.168.0.1
INTERCOM_IP=192.168.0.17
WAYDROID_IP=192.168.240.112
ENABLE_SAME_LAN_IP=yes
ANDROID_LAN_IP=192.168.0.250
LAN_PREFIX_LENGTH=24
FAKE_WIFI_PACKAGES=jp.co.aiphone.refine
ENABLE_ANDROID_WLAN0_COMPAT=yes
ANDROID_WIFI_COMPAT_IF=wlan0ネットワーク設定を適用し、Waydroidからルーターと親機へ到達できることを確認します。
sudo ./scripts/setup-network.sh ./config/network.env
systemctl status waydroid-same-lan.service --no-pager
./scripts/test-network.sh all | tee network-test.log確認時の構成では、Android側のeth0に通常IPとLAN側IPの両方が付き、物理LAN宛ての通信では
192.168.0.250がsource addressとして選ばれます。
pid=$(sudo lxc-info -P /var/lib/waydroid/lxc -n waydroid -pH)
sudo nsenter -t "$pid" -n ip -br address
sudo nsenter -t "$pid" -n ip route get 192.168.0.17次に、別terminalでAiphone専用relayを起動したままにします。このrelayはroot権限でraw socketを使い、 WaydroidからのUDP/51711 broadcastを物理LANへ転送し、親機からLAN側IPのUDP/51712へ返る応答を Waydroid側へ戻します。
set -a
source config/network.env
set +a
sudo ./scripts/aiphone-discovery-relay.py \
--inside "$WAYDROID_IF" \
--outside "$HOST_LAN_IF" \
--source-ip "$ANDROID_LAN_IP" \
--broadcast-ip 192.168.0.255 \
--port 51711 \
--response-port 51712--broadcast-ipは自分のsubnetのbroadcast addressへ変更してください。その状態でアプリを起動し、
親機探索を実行します。relay側に次の2種類のlogが出れば、要求と応答の両方向を中継できています。
relayed ... bytes from UDP source port ...
relayed response: <親機IP>:<port> -> <Waydroid LAN側IP>:51712 (... bytes)
うまく検出できない場合は、両interfaceで同時にpacketを確認します。
sudo tcpdump -ni waydroid0 'udp port 51711 or udp port 51712'
sudo tcpdump -ni wlp0s20f3 'udp port 51711 or udp port 51712'
adb logcat | grep -E 'FakeWifi|aiphone|refine'waydroid-same-lan.serviceは再起動後も有効ですが、現在のAiphone専用relayはforeground processです。
ホストまたはrelayを再起動した場合は、アプリで探索する前にrelayをもう一度起動してください。
sudo ./scripts/setup-binder.sh
docker compose --profile experimental build nested-waydroid
docker compose --profile experimental up -d nested-waydroid
docker compose exec nested-waydroid waydroid statusこのserviceのprivileged: trueは、内側のLXCがnamespace、mount、network、device/cgroupを操作するためです。
これはホストroot相当の危険な境界で、binderfsと/dev/driを渡すだけのcapability集合では安定して起動できません。
Docker内systemdは内側のWaydroid container service管理には便利ですが、ネスト固有の問題を解消しません。
実機で合格するまでrestart: unless-stoppedを本番保証と解釈しないでください。
AndroidのWifiManagerが返すネットワーク種別、SSID、BSSID、DHCP情報は実測します。
waydroid shell cmd wifi status
waydroid shell dumpsys wifi
waydroid shell dumpsys connectivity
waydroid shell ip addrvethをWi-Fiに偽装しても実SSIDスキャンにはなりません。位置情報権限を与えてもHALにscan resultがなければ SSIDは得られません。USB Wi-Fiの詳細は wifi-limitations.md を参照してください。
nested-waydroidのprivileged modeは隔離境界として扱いません。信頼しないAPKを実行しないでください。- ADB 5555を
0.0.0.0へ公開せず、既定のloopback bindとSSH tunnelを維持してください。 - ADB秘密鍵、Google cookie/password、APKライセンス情報をcommitしません。
- multicast reflectorはLAN間の情報を漏らします。対象interface/サービス/UDP portを最小化します。
- Waydroidは実機TEE/verified boot認証を提供しません。SafetyNet/Play Integrity/root/emulator判定の回避は扱いません。
- 対象APKの提供元、署名、利用規約、自動操作の許可を確認してください。
停止のみ:
sudo ./scripts/cleanup.shWaydroidデータとこのCompose projectのvolumeも削除(確認文字列が必要、復元不可):
sudo ./scripts/cleanup.sh --purge-dataAvahi設定とバックアップはネットワーク影響を確認して手動復元します。 トラブル時は troubleshooting.md を参照してください。