Files
tdc114plus/docs/policy_android_studio_wsl_adb_2026-07-03.md

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.md
  • docs/scenario_android_emulator_device_integration_test_2026-07-03.md
  • docs/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차 시도만 허용한다.
  • 10048 bind 실패가 1회라도 재현되면 즉시 Windows portproxy 방식으로 전환한다.
  • Docker Flutter에는 ADB_SERVER_SOCKET을 명시적으로 전달한다.
  • 2026-07-08 확인 결과, Windows adb.exe devicesdevice인데 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에서 직접 접근 불가 portproxy0.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 server10048 오류로 실패 외부 바인딩 방식 지연 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 준비

  1. Windows Android Studio를 실행한다.
  2. Device Manager에서 emulator를 시작한다.
  3. 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

아래 결과가 나오면 더 반복하지 않는다.

  • 10048
  • 0.0.0.0:5037 bind 실패
  • 기존 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와 일치하지 않는 구조일 가능성이 높다.

동일 증상이 실제로 발생한 경우에만 아래 순서로 보조 경로 전환을 검토한다.

  1. 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
  1. WSL에서 <EMULATOR_PORT> 연결을 확인한다.
nc -vz <WINDOWS_HOST_IP> <EMULATOR_PORT>
  1. 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'
  1. 이 방식이 성공하면 scripts/flutter-docker.sh 또는 scripts/integration_tests.sh에 선택 환경변수를 추가한다.

예상 환경변수:

TDC114_ADB_CONNECT_ADDRESS=<WINDOWS_HOST_IP>:<EMULATOR_PORT>
  1. 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
  1. 위 방식이 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_backend
    • baron_gateway
    • baron_userfront
    • ory_kratos
    • ory_hydra
    • ory_keto
    • ory_oathkeeper
    • ory_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 v4tov45037 mapping이 존재한다.
  • integration test에서 직접 연결 보조 경로가 필요하면 netsh interface portproxy show v4tov4에 당일 <EMULATOR_PORT> mapping도 존재한다.
  • WSL에서 <WINDOWS_HOST_IP>:5037 TCP 연결이 성공한다.
  • 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에 기록한다.