Android System & AOSP Engineering/AOSP Framework & Custom Services

AOSP 고급 디버깅: dumpsys 덤프 분석부터 service call 트랜잭션 주입까지

임베디드 친구 2025. 5. 30. 22:37
반응형

나만의 시스템 서비스를 설계하고, 권한 세팅과 SELinux 정책을 얹어 타겟 기기에 올리는 데 성공했다면 이제 가장 짜릿하면서도 고단한 단계인 트러블슈팅과 디버깅(Debugging) 단계가 우리를 기다리고 있습니다. 안드로이드 프레임워크 개발은 일반 앱 개발과 달라서 코드에 사소한 널 포인트(NullPointer) 예외나 데드락이 발생하면 앱 프로세스 하나만 죽고 끝나는 게 아니라, 시스템 전체의 심장인 system_server가 폭파되면서 기기가 무한 리부팅(Bootloop)되는 대참사로 이어지기 십상입니다.

화면이 켜지지 않거나 내 커스텀 API를 호출했을 때 아무런 반응이 없다면, 블랙박스 상태인 OS 런타임 내부의 목소리를 들을 줄 알아야 합니다. 자바 프레임워크 가동 상태를 보여주는 고수준의 dumpsys 분석부터 시작해서, 바인더 드라이버 통로의 흐름을 계측하는 커널 레이어의 binder_debugfs, 그리고 터미널에서 바인더에 직접 로우(Raw) 데이터를 밀어 넣는 service call 테스트까지, OS 레벨의 버그를 단숨에 잡아내는 실전 프레임워크 디버깅 파이프라인을 완전히 마스터해 보겠습니다.

Generated by Gemini AI.

📌 핵심 요약 3줄

  1. 등록된 시스템 서비스는 일반 앱과 달리 액티비티 매니저의 제어를 받지 않으므로 service check와 dumpsys <서비스명> 단독 명령어로 런타임 상태를 조회해야 합니다.
  2. 바인더 통신 흐름이 꼬이거나 멈췄을 때는 커널 내 가상 파일 시스템인 binder_debugfs 경로를 열어 프로세스 간 트랜잭션 적체 상태를 정밀 추적합니다.
  3. API 동작을 테스트하기 위해 매번 클라이언트 앱을 빌드할 필요 없이, adb shell service call 명령어로 터미널에서 바인더 함수를 다이렉트로 원격 제어할 수 있습니다.

1. 안드로이드 시스템 레이어별 트러블슈팅 디버깅 툴셋

문제가 발생한 소스 스택의 위치와 증상에 따라 엔지니어가 꺼내 들어야 하는 핵심 adb 진단 도구 맵입니다.

분석 대상 레이어 핵심 진단 명령어 툴의 주된 분석 목적 및 트러블슈팅 기능
바인더 레지스트리 adb shell service list

adb shell service check custom
ServiceManager에 내 커스텀 시스템 서비스가 정상적인 문자열 키값으로 안착해 상주 중인지 유무 확인
자바 시스템 런타임 adb shell dumpsys custom 서비스 인스턴스가 메모리에 유지하는 내부 멤버 변수 상태, 연결된 클라이언트 정보 등 커스텀 덤프 통계 데이터 출력
리눅스 시스템 콜 adb shell strace -p <PID> 로우 레벨 네이티브 단에서 서비스 프로세스가 파일 시스템, 커널 드라이버와 주고받는 I/O 이벤트를 실시간 로깅
커널 바인더 드라이버 adb shell cat

/sys/kernel/debug/binder/transactions
바인더 스레드 풀이 고갈되었거나 프로세스 간 통신(IPC) 도중 동기식 락(Lock)이 걸려 응답이 없는 데드락 구간 계측
인터페이스 입력 테스트 adb shell service call custom 1 i32 5 클라이언트 앱 구동 없이, 바인더 인터페이스의 특정 함수 번호(Transaction Code)에 테스트 인자값을 다이렉트로 주입 가동

2. service list 및 dumpsys를 이용한 런타임 인프라 점검

기기가 부팅되었을 때 내 서비스가 메모리에 안전하게 상주해 앱들의 요청을 받아들일 런타임 준비가 되었는지 검증하는 기법입니다.

2.1 서비스 등록 및 생존 여부 조회

내가 지정한 바인더 문자열 이름표(예: custom_hardware)가 시스템 전역 바인더 허브에 정식 등록되었는지 스캔합니다.

Bash
 
# 내 서비스 이름이 목록에 살아있는지 단독 확인
$ adb shell service check custom_hardware
  • 정상 등록 시 아웃풋: Service custom_hardware: found
  • 비정상/구동 실패 시 아웃풋: Service custom_hardware: not found -> SystemServer.java 초기화 소스 스택으로 돌아가 예외 터진 구간을 찾아야 합니다.

2.2 고수준 상태 백업 정보 추출 (dumpsys)

내 서비스가 정상 작동 중일 때 내부 핵심 메모리 상태 변수들을 터미널 창에 스트리밍합니다.

Bash
 
# 내 커스텀 시스템 서비스 전용 dumpsys 아웃풋 호출
$ adb shell dumpsys custom_hardware

이 명령어가 제대로 돌려면 앞선 포스팅에서 팁으로 다뤘던 내 시스템 서비스 소스 내부의 protected void dump(...) 메서드 오버라이딩 처리가 선행되어 있어야 깔끔한 포맷팅 데이터를 확인할 수 있습니다.


3. logcat과 strace를 활용한 시스템 거동 추적

자바 코드의 흐름과 하부 네이티브 드라이버 시스템 콜 영역의 거동을 엮어서 분석하는 트래킹 기법입니다.

3.1 logcat 태그 및 프로세스 필터링

시스템 서버는 워낙 방대한 가동 로그를 뿜어내므로 내 서비스 태그만 정밀 타겟팅해야 눈이 편안해집니다.

Bash
 
# 내 서비스 태그 이름인 "CustomHWService" 로그만 필터링하여 추적
$ adb logcat -s CustomHWService:V

3.2 strace를 통한 네이티브 시스템 콜 계측

만약 하부 C++ 라이브러리나 커널 드라이버 파일(/dev/...)을 건드리다가 서비스가 멈춰버린다면 리눅스 커널 시스템 콜 추적 도구인 strace를 붙여 하부 파일 I/O를 낚아챕니다.

Bash
 
# 1. system_server 프로세스 또는 독립형 커스텀 데몬의 프로세스 ID(PID) 확보
$ adb shell ps -A | grep custom_service

# 2. 확인된 PID(예: 1420)를 타겟팅하여 시스템 콜 추적 가동
$ adb shell strace -p 1420

⚠️ 최신 AOSP 환경 주의사항: userdebug 빌드라 하더라도 SELinux 정책이 Enforcing 상태면 strace가 프로세스에 붙지 못하고 접근 거부 에러가 납니다. 실행 전 필히 **adb shell setenforce 0**을 때려 허용(Permissive) 모드로 돌려놓고 계측해야 합니다.


4. binder_debugfs와 service call을 이용한 저수준 IPC 핸들링

커널 메모리 레벨에서 일어나는 통신 트래픽을 검사하고, 터미널에서 바인더 원격 함수를 다이렉트로 트리거하는 고성능 검증 기술입니다.

4.1 Binder Transaction 적체 현상 분석 (binder_debugfs)

특정 API를 호출했는데 무한 블로킹에 빠지거나 프로세스가 응답 불능이 된다면 커널 내 가상 파일 시스템인 binder_debugfs의 트랜잭션 테이블을 출력해 봅니다.

Bash
 
# 현재 안드로이드 커널 상에서 오고 가는 실시간 바인더 트랜잭션 통계 덤프 출력
$ adb shell cat /sys/kernel/debug/binder/transactions

출력 결과물에서 내가 만든 서비스의 PID 번호를 검색해 보면, 현재 어떤 클라이언트 앱의 PID가 내 서비스를 붙잡고 놓아주지 않는지, 혹은 바인더 스레드 풀(binder_thread)이 가득 차서 처리가 지연되고 있는지 동기식 락(Lock) 경합 상태를 낱낱이 파헤칠 수 있습니다.

4.2 service call 명령어를 통한 강제 바인더 트랜잭션 주입

테스트용 클라이언트 앱 코딩을 생략하고 터미널에서 내 시스템 서비스의 특정 AIDL 인터페이스 함수를 직접 가동해 볼 수 있는 강력한 기능입니다. 만약 AIDL 파일의 첫 번째 함수가 void performAction(int value) 구조라면 아래와 같이 입력합니다.

Bash
 
# 형식: adb shell service call <서비스명> <함수번호> <인자타입> <값>
$ adb shell service call custom_hardware 1 i32 255
  • 1: AIDL 파일에 정의된 메서드 선언 순서(Transaction Code 번호)
  • i32 255: 32비트 정수형(Integer) 인자값으로 255라는 데이터를 함수 파라미터로 던지겠다는 의미입니다.
  • 이를 활용하면 커널 거부 현상이나 자바 예외 메커니즘이 터지는지 호스트 PC 터미널에서 즉시 피드백을 받을 수 있어 검증 속도가 비약적으로 상승합니다.

🛠️ 개발을 위한 팁 (Tips)

  1. service call 결과를 사람이 읽을 수 있는 문자열로 받기: service call 명령어로 문자열 리턴값이 있는 시스템 함수를 호출하면 터미널 창에 16진수 바이트 배열(Result: Parcel(00000000 00000012 ... ))이 쏟아져 나와 해독하기가 무척 어렵습니다. 이럴 때는 호출 명령어 맨 뒤에 // 문자열 디코딩 옵션을 붙이거나 결과를 파일로 받아 파이썬 스크립트로 헥사디시멀 코드를 디코딩하면 시스템 서비스가 반환하는 내부 텍스트 메시지를 직관적으로 복원해 디버깅 생산성을 높일 수 있습니다.
  2. system_server만 소프트 리부팅하여 시간 아끼기: 프레임워크 자바 소스를 수정하고 이미지를 동기화한 뒤 기기를 완전히 껐다 켜려면 콜드 부팅 시간 때문에 수 분이 소요됩니다. 이때 터미널에 adb shell stop && adb shell start 명령을 날려보세요. 리눅스 커널 레이어는 그대로 둔 채 안드로이드 자바 프레임워크의 총수 장령인 런타임 지고지순 프로세스(system_server)만 깔끔하게 죽였다가 가동하므로 15초 내외로 수정한 시스템 서비스 초기화 로직을 고속으로 재검증할 수 있습니다.

⚠️ 흔히 하는 실수 (Common Mistakes)

  1. am startservice 명령어를 시스템 서비스에 던지는 행위: 프레임워크 커스텀 입문 단계에서 가장 많이 저지르는 아키텍처 오개념 적용 실수입니다. adb shell am startservice 명령어는 액티비티 매니저 스택 내부에 인텐트(Intent)를 발행하여 일반 앱 패키지에 속한 독립 컴포넌트 서비스를 깨울 때 쓰는 도구입니다. SystemServer.java 스레드에 상주하는 프레임워크 시스템 서비스는 이러한 인텐트 구동 대상이 아니므로 이 명령어를 적용하면 시스템이 서비스를 찾지 못해 무반응 에러가 납니다. 프레임워크 서비스의 연동 테스트는 오직 service call 명령어로 집행해야 합니다.
  2. SELinux Enforcing 모드에서의 strace 부착 실패: 시스템 서비스 프로세스가 특정 동작 중 뻗어버릴 때 strace -p <PID>를 치면 strace: attach: ptrace(PTRACE_SEIZE, ...): Permission denied라는 에러 메시지가 뜨며 툴 가동이 거부되는 실수를 자주 겪습니다. 안드로이드 리눅스 커널의 보안 모듈이 프로세스 메모리 영역을 마음대로 훔쳐보는 ptrace 시스템 콜을 불법 해킹 징후로 판단해 차단하기 때문입니다. 반드시 디버깅 착수 전 adb root를 획득하고 adb shell setenforce 0 규칙을 먹여 커널 방화벽을 잠시 내리는 조치를 선행해 주어야 도구가 정상 동작합니다.

5. 결론

안드로이드의 프레임워크 사용자 정의 시스템 서비스 개발 파이프라인에서 디버깅 역량은 내가 설계한 아키텍처의 논리적 모순을 해결해 주는 강력한 돋보기와 같습니다.

단순히 logcat에 찍히는 자바 예외 메시지에만 의존하던 기존 앱 개발 방식에서 벗어나, service check를 이용해 바인더 테이블을 스캔하고, binder_debugfs를 통해 커널의 IPC 통신 흐름을 계측하며, service call로 하부 트랜잭션을 터미널에서 정밀 주입하는 일련의 저수준 기법들을 마스터한다면 OS 코어 레벨에서 발생하는 그 어떤 까다로운 병목 현상이나 데드락 현상도 두려움 없이 정면 돌파할 수 있습니다. 플랫폼 이미지를 구운 뒤 특정 시스템 레이어에서 응답 거부 에러가 나거나 바인더 트랜잭션 코드가 꼬여 디버깅에 난항을 겪고 계신다면, 혼자 고민하지 마시고 하단 댓글 창에 에러 덤프 문맥을 공유해 주세요. 같이 로우 레벨 단에서 원인을 시원하게 파헤쳐 봅시다!

반응형