본문으로 건너뛰기
Device MCP
← 블로그

엔지니어링 · 2026. 11. 4. · 읽는 데 5분

Android 에뮬레이터, 이제 60 fps로 미러링합니다

이제 Device MCP는 Android 에뮬레이터가 그리는 모든 프레임을 60 fps로 보여 줍니다. 에뮬레이터 미러링이 왜 끊겼는지, 무엇을 측정했는지, 무엇이 바뀌었는지 설명합니다.

작성: Device MCP 팀

Device MCP에 Android 에뮬레이터가 추가되었을 때, iPhone과 iOS 시뮬레이터는 이미 60 fps로 미러링되고 있었습니다. 에뮬레이터는 그렇지 못했습니다. 스크롤은 뚝뚝 끊겼고, 동영상은 버벅였으며, 화면이 복잡하면 10 fps까지 떨어지기도 했습니다.

이제 Android 에뮬레이터도 60 fps로 미러링합니다. 에뮬레이터가 Mac의 GPU로 그리는 모든 프레임을 Device MCP가 그대로 보여 줍니다. 같은 에뮬레이터에서 재생한 같은 YouTube 동영상의 이전과 지금입니다.

Device MCP에서 같은 Pixel 9 Pro 에뮬레이터로 재생한 같은 YouTube 동영상: 이전에는 scrcpy 비디오로 약 23 fps, 지금은 에뮬레이터 자체 스트림으로 60 fps

동영상 속 숫자는 직접 입력한 것이 아닙니다. 각 녹화본에서 새로 바뀐 화면을 1초 단위로 센 값입니다.

측정한 내용

M5 Max를 탑재한 MacBook Pro에서 Android 16의 Pixel 9 Pro 에뮬레이터 한 대로, YouTube에서 Big Buck Bunny를 1080p60 전체 화면으로 재생했습니다. 설정마다 두 가지 숫자를 읽었습니다. Android 자체가 동영상의 새 프레임을 화면에 얼마나 자주 올렸는지(SurfaceFlinger 자체의 타임스탬프), 그리고 Mac에 도착한 새 화면이 몇 개인지입니다.

설정Android가 그린 프레임실제로 보이는 프레임
이전 Device MCP: 윈도우 없는 에뮬레이터, scrcpy의 H.264 비디오~44 fps~23 fps
Android Studio의 Android 16 기본값(Automatic 그래픽)~45 fps~45 fps
지금의 Device MCP: Mac의 GPU, 에뮬레이터 자체 스트림60 fps60 fps

동영상은 공정한 테스트지만, 가장 어려운 테스트는 아닙니다. 캔버스 애니메이션처럼 화면 전체를 다시 그리는 페이지는 소프트웨어 설정에서 10~15 fps밖에 나오지 않았습니다. "10 fps"라는 제보는 여기서 나온 것입니다.

이전 미러링의 발목을 잡은 것은 두 가지였습니다. 에뮬레이터가 그리는 방식, 그리고 그 화면이 Mac까지 오는 방식입니다.

문제 1: 소프트웨어 렌더링

Android 에뮬레이터는 Mac의 GPU로 그릴 수도 있고, CPU에서 소프트웨어로 그릴 수도 있습니다. Device MCP는 그동안 에뮬레이터를 -no-window로 시작했습니다. 미러링 화면이 곧 에뮬레이터의 윈도우였기 때문입니다. 자체 윈도우가 없으면 에뮬레이터는 소프트웨어 렌더러인 SwiftShader나 Lavapipe를 고릅니다.

Android 16에서는 상황이 더 나빠집니다. Mac에서 에뮬레이터의 Automatic 그래픽 설정은 Android 16 이미지에도 소프트웨어를 선택합니다("API level 36 requires GLES 3.1"). 그래서 Android Studio에서 기본 설정으로 시작한 에뮬레이터도 소프트웨어로 그립니다. 대부분의 화면에서는 문제없지만, 전체 화면 동영상이나 애니메이션은 쓸 수 있는 코어를 모두 차지합니다.

문제 2: Android 안에서 인코딩

Device MCP는 화면을 보는 데 scrcpy를 사용했습니다. scrcpy는 실제 휴대폰에서는 훌륭합니다. Android 안에서 실행되며, 디스플레이를 캡처해 휴대폰의 하드웨어 비디오 인코더로 H.264로 인코딩합니다.

에뮬레이터에는 하드웨어 인코더가 없습니다. 그래서 scrcpy는 Android의 소프트웨어 인코더를 쓰는데, 이 인코더는 에뮬레이터 자체의 가상 CPU에서 실행됩니다. 지금 보고 있는 앱을 그리는 바로 그 CPU입니다. 위 테스트에서 인코더는 에뮬레이터 안의 어떤 것보다 CPU를 많이 썼고, 미러링 화면은 Android가 그린 프레임의 절반 정도만 받았습니다. GPU를 켜도 소용없었습니다. 그러면 scrcpy가 인코딩 전에 프레임마다 GPU에서 다시 복사해 와야 해서, 미러링이 3~5 fps로 떨어졌습니다.

해결책: 에뮬레이터 자체의 화면

Android 에뮬레이터에는 이미 빠른 길이 있습니다. 에뮬레이터는 Mac에서 gRPC 서비스를 실행하는데, 그 호출 중 하나인 streamScreenshot은 에뮬레이터가 화면을 그리는 순간 새 프레임을 그대로 RGB 픽셀로 보냅니다. Android Studio가 Running Devices 윈도우에 에뮬레이터를 보여 주는 방식이 바로 이것입니다.

이제 Device MCP도 같은 방식을 씁니다.

  • 에뮬레이터의 프레임을 직접 읽습니다. 인코딩도 디코딩도 없습니다. Device MCP는 모든 에뮬레이터가 작성하는 디스커버리 파일에서 에뮬레이터의 서비스를 찾고, 각 프레임을 Mac의 픽셀 형식으로 변환해 화면에 올립니다. Pixel 9 Pro 프레임 하나는 11 MB이므로, 초당 60장이면 약 660 MB/s입니다. 네트워크로는 많은 양이지만, Mac 한 대가 자기 자신과 주고받기에는 아무것도 아닙니다.
  • 에뮬레이터를 숨겨진 윈도우로, GPU에서 시작합니다. 이제 Device MCP는 emulator -avd <name> -qt-hide-window -gpu host -grpc-use-token을 실행합니다. Android Studio가 내장 에뮬레이터에 쓰는 플래그에 하드웨어 그래픽을 더한 것입니다. Android Studio에서 AVD를 Software로 설정했다면 Device MCP는 그 설정을 따릅니다.
  • scrcpy는 입력용으로만 남습니다. scrcpy 서버는 비디오를 끈 채로 클릭, 키, 텍스트, 클립보드를 계속 전달합니다. 터치는 이전과 똑같은 위치에 정확히 닿습니다.

Inspector에서 미러링이 어떤 경로를 쓰는지 확인할 수 있습니다. 에뮬레이터의 Mirror 항목은 이제 emulator gRPC로 표시되고, Quality에는 RGB로 받는 전체 패널 해상도가 나옵니다.

동영상을 재생 중인 Pixel 9 Pro 에뮬레이터의 Device MCP Inspector: Mirror emulator gRPC, Quality RGB 2856×1280, Frame rate 60 fps

다른 곳에서 시작한 에뮬레이터

따로 바꿀 것은 없습니다. 60 fps로 스트리밍할 수 없는 에뮬레이터(Android Studio가 소프트웨어 모드로 시작했거나, 스크립트가 -no-window로 시작한 에뮬레이터)를 미러링하려고 하면, Device MCP가 알아서 그 에뮬레이터를 빠른 방식으로 다시 시작합니다. 부팅 화면이 15~20초 동안 표시되며, 에이전트의 MCP 호출은 에뮬레이터가 돌아올 때까지 기다립니다. 이 재시작은 Device MCP를 실행할 때마다 에뮬레이터당 한 번 일어납니다.

알아 둘 점이 몇 가지 있습니다.

  • 첫 재시작은 콜드 부팅입니다. 소프트웨어로 그리던 중에 저장된 Quick Boot 스냅샷은 GPU에서 불러올 수 없으므로, 열려 있던 앱은 닫힙니다. 설치한 앱과 앱 데이터는 그대로 남습니다. 이후의 재시작에서는 스냅샷이 유지됩니다.
  • 디버그 세션이 끝납니다. Android Studio가 그 에뮬레이터에서 앱을 실행하거나 디버깅하고 있었다면, Device MCP가 에뮬레이터를 다시 시작할 때 그 세션은 중지됩니다. Android Studio의 Running Devices 윈도우는 에뮬레이터를 알아서 다시 연결합니다.
  • 직접 지정한 플래그가 우선입니다. -writable-system, -http-proxy, -port, 소프트웨어 -gpu처럼 Device MCP가 넘기지 않는 옵션으로 시작한 에뮬레이터는 그대로 둡니다. 그 에뮬레이터는 낼 수 있는 속도로 미러링됩니다.

에이전트에게 달라지는 점

에이전트의 스크린샷은 이전과 마찬가지로 Android 자체에서 가져옵니다. 하지만 에이전트가 화면에 무엇이 있는지 묻는데 접근성 트리로는 알 수 없을 때(예를 들어 게임이나 웹 뷰), Device MCP는 미러링 화면의 이미지도 읽습니다. 이미지 속 텍스트를 인식하는 것입니다. 그 이미지가 이제 2048픽셀로 축소된 H.264 프레임이 아니라 압축되지 않은 2856×1280 전체 패널이므로, 작은 텍스트도 더 깔끔하게 읽어 냅니다.

측정 방법

동영상은 Device MCP 윈도우를 두 번 녹화한 것입니다. 같은 에뮬레이터, 같은 YouTube 동영상, 같은 품질 설정으로 연달아 녹화한 다음, 영화의 장면 전환에 맞춰 나란히 맞췄습니다. 에뮬레이터 스트림은 화면이 바뀔 때만 프레임을 보내므로, 업데이트 하나하나를 새 화면으로 셉니다. scrcpy의 디코더는 직전 프레임과 거의 차이가 없는 프레임도 보여 주므로, 이전 경로에서는 눈에 띄게 바뀐 프레임만 셉니다. 화면 기록 도구 자체가 60프레임 중 57~58프레임을 잡기 때문에, 동영상의 카운터는 60에 조금 못 미칩니다. "Android가 그린 프레임" 열은 SurfaceFlinger의 프레임 타임스탬프에서, Android Studio의 수치는 Running Devices 윈도우가 읽는 것과 같은 스트림을 읽어서 얻었습니다. 수치는 사용하는 Mac, AVD, 화면 내용에 따라 달라지겠지만, 격차는 그대로입니다.

사용해 보기

Device MCP를 업데이트하고, 사이드바에서 에뮬레이터를 시작한 다음, 움직이는 것을 재생해 보세요.

Big Buck Bunny © copyright 2008, Blender Foundation, peach.blender.org. CC BY 3.0 라이선스로 제공됩니다.

다음 단계

Device MCP는 Proxyman, Tiny Shield, TCP Viewer를 만든 Proxyman LLC가 만듭니다.