13 KiB
Android Studio / WSL ADB 연동 재발 방지 정책
작성일: 2026-07-03 상태: v1.3 Windows Android Studio emulator + WSL/Docker Flutter 기준
목적: Windows Android Studio emulator를 WSL 및 Docker 기반 Flutter CLI에서 사용할 때 발생한 ADB 연동 지연을 반복하지 않도록, 지연 원인과 동일 상황 발생 시 우선 처리 방식을 정책으로 고정한다.
관련 문서:
docs/troubleshooting/android-studio-wsl-adb-timetable-260703.mddocs/scenario_android_emulator_device_integration_test_2026-07-03.mddocs/dev_env_tdc114plus_setup_plan_2026-07-02.md
1. 적용 범위
본 정책은 아래 상황에 적용한다.
- Windows Android Studio에서 Android emulator를 실행한다.
- Flutter CLI는 WSL 또는 Docker container 내부에서 실행한다.
- WSL/Docker Flutter에서 Windows emulator 또는 Android device를 인식해야 한다.
scripts/flutter-docker.sh devices또는scripts/integration_tests.sh가 Android target을 필요로 한다.
아래 상황은 본 정책의 직접 적용 대상이 아니다.
- macOS 기반 iOS simulator
- WSL 내부 Android emulator 직접 설치
- 실기기만 사용하고 Windows ADB server를 거치지 않는 구성
2. 기본 원칙
- Windows Android Studio emulator를 사용할 때는 Windows
adb.exe기준으로 먼저 device 상태를 확인한다. - WSL에 Android SDK/ADB가 없다고 판단되면 WSL 내부 emulator 설치로 바로 우회하지 않는다.
adb -a -P 5037 nodaemon server방식은 1차 시도만 허용한다.10048bind 실패가 1회라도 재현되면 즉시 Windowsportproxy방식으로 전환한다.- Docker Flutter에는
ADB_SERVER_SOCKET을 명시적으로 전달한다. - 2026-07-08 확인 결과, Windows
adb.exe devices가device인데 Docker local ADB 직접 연결이offline으로 반복될 수 있으므로 기본 연결은ADB_SERVER_SOCKET=tcp:<WINDOWS_HOST_IP>:5037방식으로 한다. TDC114_ADB_CONNECT_ADDRESS=<WINDOWS_HOST_IP>:<EMULATOR_PORT>기반 Docker local ADB server 방식은ADB_SERVER_SOCKET방식으로 integration test가 실제로 막힐 때만 보조 경로로 사용한다.- Docker Flutter는 ADB key, Gradle, pub cache, Android SDK 하위 cache를 로컬 디렉터리에 유지한다.
- Android emulator에서 host API에 접근할 때는
127.0.0.1이 아니라10.0.2.2를 우선 사용한다. - Baron SSO backend, gateway, userfront, Ory runtime이 모두 살아 있는지 확인하기 전에는 Android 관련 테스트를 시작하지 않는다.
- integration test 실행 전에는 host 기준
./scripts/api-smoke.sh를 먼저 통과시킨다. - 실행 결과와 장애 내용은
docs/test-logs/YYYY-MM-test-execution-log.md에 누적 기록한다.
3. 지연 원인
2026-07-03 작업에서 확인한 주요 지연 원인은 아래와 같다.
| 원인 | 영향 | 다음 대응 |
|---|---|---|
Windows ADB server가 127.0.0.1:5037에 먼저 바인딩됨 |
WSL/Docker에서 직접 접근 불가 | portproxy로 0.0.0.0:5037 -> 127.0.0.1:5037 노출 |
| Android Studio, Device Manager, emulator, ADB client가 ADB server를 자동 재기동 | 기존 PID 종료 후에도 adb -a 재시도 실패 반복 |
adb -a 반복 시도 금지 |
adb -a -P 5037 nodaemon server가 10048 오류로 실패 |
외부 바인딩 방식 지연 | 1회 실패 후 portproxy 전환 |
WSL 내부에 adb, java, sdkmanager, emulator가 없음 |
WSL 단독 Android 환경 전환 불가 | Windows Android Studio emulator 사용 유지 |
| Docker container와 Windows ADB server의 localhost 의미가 다름 | integration test VM service dynamic port 연결 실패 가능 | 필요 시 당일 emulator adbd port를 노출 후 Docker local ADB server 방식 검증 |
| Docker local ADB server가 새 ADB key를 생성 | emulator가 unauthorized 상태로 표시 |
Windows 승인 ADB key를 git ignored .android-adb/에 재사용 |
| Docker Flutter container가 매번 새로 생성됨 | NDK/CMake/Gradle/pub cache 재다운로드로 반복 지연 | .docker-cache/flutter 아래 cache volume 유지 |
scripts/integration_tests.sh 출력이 종료 후 표시되는 구조였음 |
Android 첫 빌드 진행 상태 확인 어려움 | 실시간 출력 방식 유지 |
4. 동일 상황 발생 시 처리 순서
4.1 Windows emulator 준비
- Windows Android Studio를 실행한다.
- Device Manager에서 emulator를 시작한다.
- Windows PowerShell에서
adb.exe devices를 확인한다.
& "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" devices
완료 기준:
emulator-5554 device또는 동일한 Android target이device상태로 표시된다.
4.2 adb -a 1차 시도
필요 시 아래 방식을 1회만 시도한다.
& "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" -a -P 5037 nodaemon server
아래 결과가 나오면 더 반복하지 않는다.
100480.0.0.0:5037bind 실패- 기존 ADB PID 종료 후에도 동일 실패 반복
4.3 portproxy 전환
관리자 PowerShell에서 아래 명령을 적용한다.
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=5037 connectaddress=127.0.0.1 connectport=5037
netsh advfirewall firewall add rule name="ADB 5037 for WSL" dir=in action=allow protocol=TCP localport=5037
netsh interface portproxy show v4tov4
WSL에서 Windows host IP를 확인한다.
awk '/nameserver/ {print $2; exit}' /etc/resolv.conf
이번 환경의 예시는 아래와 같다.
172.21.128.1
4.4 WSL/Docker 연결 확인
WSL에서 TCP 연결을 먼저 확인한다.
nc -vz <WINDOWS_HOST_IP> 5037
Docker Flutter에서 device 인식을 확인한다.
ADB_SERVER_SOCKET=tcp:<WINDOWS_HOST_IP>:5037 ./scripts/flutter-docker.sh devices
완료 기준:
- Android emulator가 Flutter devices 목록에 표시된다.
- Linux desktop만 보이면 Android target 준비가 완료되지 않은 상태로 판단한다.
4.4-A Flutter/Docker 표준 연결 방식
기본 device 인식, 앱 실행, APK 설치 확인은 아래 방식을 표준으로 사용한다.
ADB_SERVER_SOCKET=tcp:<WINDOWS_HOST_IP>:5037 ./scripts/flutter-docker.sh devices
정책 기준:
5037 remote Windows ADB server방식은 현재 Windows emulator 연동의 기본 경로다.- Windows에서 이미
device로 승인된 ADB 세션을 Docker Flutter가 공유한다. - Docker local ADB가 직접 emulator port에 붙었을 때
offline이 반복되면 더 반복하지 않는다. - 직접 emulator port 연결은 아래 보조 경로로만 둔다.
보조 경로:
TDC114_ADB_CONNECT_ADDRESS=<WINDOWS_HOST_IP>:<EMULATOR_PORT> ./scripts/flutter-docker.sh devices
4.5 Android emulator API 주소
Android emulator에서 host machine API를 호출할 때는 아래 주소를 사용한다.
TDC114_API_BASE=http://10.0.2.2:5000
emulator용 local env 파일 예시는 아래와 같다.
scripts/.env.android-emulator.local
민감정보가 포함될 수 있으므로 해당 파일은 git tracked 파일로 추가하지 않는다.
5. Integration test 추가 분기
ADB_SERVER_SOCKET=tcp:<WINDOWS_HOST_IP>:5037 방식은 device 목록 확인과 APK 설치까지는 가능할 수 있다. 다만 Flutter integration test loading 단계에서 VM service dynamic port 연결이 실패할 수 있다.
대표 증상:
WebSocketChannelException
127.0.0.1:<dynamic port> connection refused
이 경우 원인은 remote Windows ADB server가 만든 port forward의 127.0.0.1이 Docker container 내부 localhost와 일치하지 않는 구조일 가능성이 높다.
동일 증상이 실제로 발생한 경우에만 아래 순서로 보조 경로 전환을 검토한다.
- Windows 관리자 PowerShell에서 emulator adbd port를 노출한다.
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=<EMULATOR_PORT> connectaddress=127.0.0.1 connectport=<EMULATOR_PORT>
netsh advfirewall firewall add rule name="ADB emulator <EMULATOR_PORT> for WSL" dir=in action=allow protocol=TCP localport=<EMULATOR_PORT>
netsh interface portproxy show v4tov4
- WSL에서
<EMULATOR_PORT>연결을 확인한다.
nc -vz <WINDOWS_HOST_IP> <EMULATOR_PORT>
- Docker container 내부 local ADB server가 emulator adbd에 직접 붙는지 확인한다.
docker run --rm ghcr.io/cirruslabs/flutter:stable sh -lc 'adb connect <WINDOWS_HOST_IP>:<EMULATOR_PORT> && adb devices'
- 이 방식이 성공하면
scripts/flutter-docker.sh또는scripts/integration_tests.sh에 선택 환경변수를 추가한다.
예상 환경변수:
TDC114_ADB_CONNECT_ADDRESS=<WINDOWS_HOST_IP>:<EMULATOR_PORT>
- Docker local ADB가
unauthorized이면 Windows에서 이미 승인된 ADB key를 재사용한다.
mkdir -p .android-adb
cp /mnt/c/Users/user/.android/adbkey .android-adb/adbkey.new
cp /mnt/c/Users/user/.android/adbkey.pub .android-adb/adbkey.pub.new
mv -f .android-adb/adbkey.new .android-adb/adbkey
mv -f .android-adb/adbkey.pub.new .android-adb/adbkey.pub
chmod 600 .android-adb/adbkey
- 위 방식이
device상태를 만들면 integration test는 아래 명령을 기본값으로 사용한다.
TDC114_SMOKE_ENV_FILE=scripts/.env.android-emulator.local \
TDC114_ADB_CONNECT_ADDRESS=<WINDOWS_HOST_IP>:<EMULATOR_PORT> \
./scripts/integration_tests.sh
5-A. API smoke 선행 원칙
Android integration test 전에 아래 명령을 먼저 실행한다.
./scripts/check-baron-api-env.sh
./scripts/api-smoke.sh
판정 기준:
./scripts/check-baron-api-env.sh가 failure 0, warning 0 상태여야 한다.- 최소한 아래 runtime이 running 또는 healthy 상태여야 한다.
baron_backendbaron_gatewaybaron_userfrontory_kratosory_hydraory_ketoory_oathkeeperory_postgres
- phone-login, employee list, tenant list, orgchart가 모두 HTTP 200이어야 한다.
- unauthorized directory guard는 HTTP 401 또는 403이어야 한다.
실패 시 처리:
./scripts/check-baron-api-env.sh에서 warning이 나오면 Android test보다 runtime 복구를 우선한다.502 Bad Gateway가 나오면 Baron/Ory runtime 중단 가능성을 먼저 의심한다../scripts/check-baron-api-env.sh로 상태를 본다.baron_backend,baron_userfront,ory_*컨테이너를 복구한 뒤 integration test를 재시도한다.orgFront관련 API 확인이 필요한 경우에도 같은 원칙을 적용해 backend/gateway/userfront를 모두 확인한 뒤 진행한다.
5-B. Docker cache 유지 원칙
반복 실행 시 NDK/CMake/Gradle/pub cache 재설치를 막기 위해 scripts/flutter-docker.sh는 아래 로컬 cache 디렉터리를 유지한다.
.docker-cache/flutter/gradle.docker-cache/flutter/pub.docker-cache/flutter/android-sdk/licenses.docker-cache/flutter/android-sdk/ndk.docker-cache/flutter/android-sdk/cmake
운영 원칙:
- 위 cache 디렉터리는 git tracked 파일로 추가하지 않는다.
- cache가 손상되지 않는 한 수동 삭제하지 않는다.
- Flutter Docker image를 바꾸더라도 우선 기존 cache와 호환되는지 확인한다.
- cache가 꼬여 비정상 빌드가 반복되면 해당 하위 디렉터리만 선별 삭제한다.
6. 금지 또는 제한 사항
adb -a -P 5037 nodaemon server실패 후 동일 명령을 여러 번 반복하지 않는다.- Windows ADB PID를 계속 종료하면서 원인 확인 없이 시간을 쓰지 않는다.
- WSL에
adb, Java, Android SDK,/dev/kvm조건이 없는데 WSL 내부 emulator 설치로 즉시 전환하지 않는다. - 민감정보가 포함된
.env.*.local파일을 git tracked 파일로 추가하지 않는다. .android-adb/,.docker-cache/를 git tracked 파일로 추가하지 않는다.- Android emulator API base에
http://127.0.0.1:5000을 기본값으로 쓰지 않는다. 5037 remote ADB server방식에서 integration test VM service 실패가 재현됐는데 같은 방식만 반복하지 않는다.
7. 완료 체크리스트
다음 항목을 모두 만족하면 Android Studio / WSL ADB 연동 준비가 완료된 것으로 본다.
- Windows
adb.exe devices에서 emulator가device상태다. netsh interface portproxy show v4tov4에5037mapping이 존재한다.- integration test에서 직접 연결 보조 경로가 필요하면
netsh interface portproxy show v4tov4에 당일<EMULATOR_PORT>mapping도 존재한다. - WSL에서
<WINDOWS_HOST_IP>:5037TCP 연결이 성공한다. ADB_SERVER_SOCKET=tcp:<WINDOWS_HOST_IP>:5037 ./scripts/flutter-docker.sh devices에서 Android target이 표시된다.- 보조 경로 사용 시
TDC114_ADB_CONNECT_ADDRESS=<WINDOWS_HOST_IP>:<EMULATOR_PORT> ./scripts/flutter-docker.sh devices에서 Android target이device상태로 표시된다. - emulator용 API base가
http://10.0.2.2:5000으로 설정되어 있다. ./scripts/check-baron-api-env.sh가 warning 없이 통과한다.- host 기준
./scripts/api-smoke.sh가 통과한다. - integration test에서 VM service dynamic port 실패가 발생하면 당일
<EMULATOR_PORT>local ADB server 방식으로 분기한다. .android-adb/,.docker-cache/가 로컬에 유지되고 git tracked 상태가 아니다.- 결과를
docs/test-logs/YYYY-MM-test-execution-log.md에 기록한다.