빌드 구성에debuggable true가 포함된빌드 변형을 사용해야 합니다. 일반적으로 모든 Android 스튜디오 프로젝트에 포함된(build.gradle파일에서는 보이지 않더라도) 기본 'debug' 변형을 선택할 수 있습니다. 하지만 디버그가 가능해야 하는 새 빌드 유형을 정의하는 경우에는 빌드 유형에 `debuggable true`를 추가해야 합니다.
이 속성은C/C++ 코드가 사용된 모듈에도 적용됩니다. (jniDebuggable속성은 더 이상 사용되지 않습니다.)
디버그하려는 라이브러리 모듈에 기반한 앱인 경우 이 라이브러리 또한 디버그 기호를 보유하도록debuggable true를 포함하여 패키징해야 합니다. 앱 프로젝트의 디버그 가능 변형이 라이브러리 모듈의 디버그 가능 변형을 전달받도록 하려면기본 버전 이외의 라이브러리 버전을 게시합니다.
'switch from Run to Debug' 여부를 묻는 대화상자가 표시된다면 앱이 이미 기기에서 실행 중이며 디버깅을 시작하기 위해 다시 시작될 것임을 의미합니다. 실행 중인 앱 인스턴스를 그대로 유지하려면Cancel Debug를 클릭한 후실행 중인 앱에 디버거를 연결합니다.
그러지 않으면 Android 스튜디오에서 APK를 빌드하고 디버그 키로 서명한 후 선택한 기기에 설치하고 실행합니다.C 코드 및 C++ 코드를 프로젝트에 추가하면 Android 스튜디오는Debug창에서LLDB 디버거를 실행하여 네이티브 코드도 디버그합니다.
Debug창이 열려 있지 않으면View > Tool Windows > Debug를 선택하거나 도구 창 모음에서Debug
를 클릭한 후Debugger탭을 클릭합니다(그림 1 참조).
그림 1.현재 스레드와 변수의 객체 트리가 표시된 디버거 창
실행 중인 앱에 디버거 연결하기
앱이 이미 기기에서 실행 중인 경우 다음과 같은 방법을 사용하면 앱을 다시 시작하지 않고도 디버깅을 시작할 수 있습니다.
Attach debugger to Android process
를 클릭합니다.
Choose Process대화상자에서 디버거와 연결할 프로세스를 선택합니다.
에뮬레이터나 루팅된 기기를 사용 중인 경우Show all processes를 선택하여 모든 프로세스를 표시할 수 있습니다.
Debugger드롭다운 메뉴에서다른 디버그 유형을 선택할 수 있습니다. 기본적으로 Android 스튜디오는Auto디버그 유형을 사용하여 프로젝트에 자바 코드가 포함되었는지 C/C++ 코드가 포함되었는지에 따라 최적의 디버거 옵션을 선택합니다.
OK를 클릭합니다.
Debug창이 나타납니다.
참고:Android 스튜디오 디버거와 가비지 수집기는 느슨하게 통합됩니다. Android 가상 머신은 디버거 연결이 해제되기 전까지는 디버거가 인식하는 어떠한 객체도 가비지 수집되지 않도록 보장합니다. 이로 인해, 디버거가 연결되어 있는 동안에는 점차 객체가 누적될 수 있습니다. 예를 들어 실행 중인 스레드를 디버거가 발견하면 이 스레드가 종료되었더라도 디버거 연결이 해제될 때까지는 연결된Thread객체가 가비지 컬렉션되지 않습니다.
디버거 유형 변경하기
자바/Kotlin 코드와 C/C++ 코드를 디버그하는 데는 서로 다른 디버거 도구가 필요하므로 Android 스튜디오 디버거에서는 사용할 디버거 유형을 선택할 수 있습니다. 기본적으로 Android 스튜디오는 프로젝트에서 감지되는 언어에 따라 사용할 디버거를 결정합니다(Auto디버거 유형일 때). 하지만디버그 구성에서(Run > Edit Configurations클릭) 또는Run > Attach debugger to Android process를 클릭하여 나타나는 대화상자에서 수동으로 디버거를 선택할 수 있습니다.
사용할 수 있는 디버그 유형에는 다음이 포함됩니다.
Auto디버깅 중인 코드에 가장 적합한 옵션을 Android 스튜디오에서 자동으로 선택하게 하려면 이 디버그 유형을 선택합니다. 예를 들어 프로젝트에 C 코드나 C++ 코드가 있다면 Android 스튜디오에서 자동으로Dual디버그 유형을 사용하고 그렇지 않은 경우에는Java디버그 유형을 사용합니다.Java자바 또는 Kotlin으로 작성된 코드만 디버그하려면 이 디버그 유형을 선택합니다. 자바 디버거는 네이티브 코드에서 설정한 중단점이나 watchpoint를 무시합니다.Native(C/C++ 코드에서만 사용 가능)LLDB만 사용하여 코드를 디버그하려면 이 디버그 유형을 선택합니다. 이 디버그 유형을 사용할 경우에는 자바 디버거 세션 뷰를 사용할 수 없습니다. 기본적으로, LLDB는 네이티브 코드만 검사하며 자바 코드 내의 중단점을 무시합니다. 자바 코드도 함께 디버그하려면Auto또는Dual디버그 유형으로 전환해야 합니다.
네이티브 디버깅은 다음 요구사항을 충족하는 기기에서만 작동합니다.
이 기기는run-as를 지원합니다.
기기가run-as를 지원하는지 확인하려면 기기에 연결된 ADB 셸에서 다음 명령어를 실행합니다.
run-as your-package-name pwd
your-package-name을 앱의 패키지 이름으로 바꿉니다. 기기에서run-as를 지원하면 명령어는 오류 없이 반환되어야 합니다.
기기에서ptrace가 사용 설정되어 있습니다.
ptrace가 사용 설정되어 있는지 확인하려면 기기에 연결된 ADB 셸에서 다음 명령어를 실행합니다.
sysctl kernel.yama.ptrace_scope
ptrace가 사용 설정되어 있으면 명령어는0값이나unknown key오류를 출력합니다.ptrace가 사용 설정되어 있지 않으면 명령어는0이외의 값을 출력합니다.
Dual(C/C++ 코드에서만 사용 가능)자바와 네이티브 코드 디버깅 간에 전환하려면 이 디버그 유형을 선택합니다. Android 스튜디오는 자바 디버거와 LLDB 모두를 앱 프로세스에 연결(하나는 자바 디버거용, 다른 하나는 LLDB용)하므로, 앱을 다시 시작하거나 디버그 구성을 변경하지 않고도 자바 코드와 네이티브 코드 모두에서 중단점을 검사할 수 있습니다.
그림 2에서는Debug라는 창 제목의 오른쪽에 있는 탭 두 개를 볼 수 있습니다. 앱에 자바 코드와 C++ 코드가 모두 있으므로 한 탭은 네이티브 코드 디버깅용이고 다른 하나는-java로 표시된 자바 코드 디버깅용입니다.
그림 2.네이티브 코드 디버깅용 탭과 자바 코드 디버깅용 탭
참고:컴파일러에 의해 최적화된 네이티브 코드를 디버깅하는 경우 다음과 같은 경고 메시지가 나타날 수도 있습니다.This function was compiled with optimizations enabled. Some debugger features may not be available최적화 플래그(예:-O플래그)를 사용하는 경우 컴파일러에서 컴파일된 코드를 변경하여 더 효율적으로 실행되도록 합니다. 이에 따라 디버거에서 최적화된 컴파일 코드를 다시 원래 소스 코드에 매핑하기가 어려워지므로 예기치 않은 정보나 잘못된 정보를 신고할 수 있습니다. 이런 이유로, 네이티브 코드를 디버그할 때는 컴파일러 최적화를 사용 중지해야 합니다.
시스템 로그 사용
시스템 로그는 앱을 디버그하는 중에 시스템 메시지를 표시합니다. 이 메시지에는 기기에서 실행 중인 앱의 정보가 포함됩니다. 시스템 로그를 사용하여 앱을 디버그하려면 앱의 개발 단계에서 코드에 로그 메시지를 쓰고 예외의 스택 추적을 출력해야 합니다.
코드에 로그 메시지 쓰기
코드에 로그 메시지를 쓰려면Log클래스를 사용합니다. 로그 메시지는 개발자가 앱과 상호작용할 때 시스템 디버그 출력을 수집하여 실행 흐름을 이해하도록 도와줍니다. 로그 메시지는 애플리케이션의 어떤 부분이 실패했는지 알려줍니다. 로깅에 관한 자세한 내용은로그 쓰기 및 보기를 참고하세요.
다음 예시는 개발자의 활동이 시작될 때 이전 상태 정보의 사용 가능 여부를 결정하기 위해 로그 메시지를 추가하는 방법을 보여줍니다.
Android 스튜디오는 다양한 디버깅 작업을 트리거하는 여러 유형의 중단점을 지원합니다. 가장 일반적인 유형은 지정된 코드 줄에서 앱 실행을 일시중지하는 줄 중단점입니다. 일시중지된 상태에서 변수를 검사하고 식을 평가한 다음, 한 줄씩 실행을 계속하여 런타임 오류의 원인을 판별할 수 있습니다.
줄 중단점을 추가하려면 다음 단계를 진행하세요.
실행을 일시중지하려는 코드 줄을 찾은 다음, 이 코드 줄의 왼쪽 여백을 클릭하거나 줄 위에 캐럿을 배치하고 Control+F8을 누릅니다(Mac의 경우 Command+F8).
앱이 이미 실행 중인 경우에는 중단점 추가를 위해 앱을 업데이트할 필요 없이Attach debugger to Android process
를 클릭하면 됩니다. 앱이 실행 중이 아니라면Debug
를 클릭하여 디버깅을 시작합니다.
그림 3.중단점을 설정하면 표시되는 줄 옆 빨간색 점
코드 실행이 중단점에 도달하면 Android 스튜디오에서 앱 실행이 일시 중지됩니다. 그러면Debugger탭의 도구를 사용하여 앱의 상태를 확인할 수 있습니다.
변수의 객체 트리를 검사하려면Variables뷰에서 트리를 펼칩니다.Variables뷰가 보이지 않으면Restore Variables View
를 클릭합니다.
현재 실행 지점에서 식을 평가하려면Evaluate Expression
을 클릭합니다.
(메서드를 입력하지 않고) 코드의 다음 줄로 이동하려면Step Over
를 클릭합니다.
메서드 호출 내의 첫 줄로 이동하려면Step Into
를 클릭합니다.
현재 메서드 밖의 다음 줄로 이동하려면Step Out
을 클릭합니다.
정상적으로 앱 실행을 계속하려면Resume Program
을 클릭합니다.
프로젝트에 네이티브 코드가 사용되는 경우 기본적으로Auto디버그 유형에서는 자바 디버거와 LLDB를 별도의 두 프로세스로서 앱에 연결하므로 앱을 다시 시작하거나 설정을 변경하지 않고도 자바 및 C/C++ 중단점 간에 검사를 전환할 수 있습니다.
참고:Android 스튜디오가 C 코드나 C++ 코드에서 중단점을 감지하도록 하려면 LLDB를 지원하는 디버그 유형을 사용해야 합니다(예: Auto, Native 또는 Dual).디버그 구성을 수정하여 Android 스튜디오가 사용하는 디버그 유형을 변경할 수 있습니다. 다른 디버그 유형에 관해 자세히 알아보려면 다른디버그 유형사용에 관한 섹션을 참조하세요.
Android 스튜디오가 앱을 대상 기기에 배포할 때, Debug 창이 열리고 이 창에는 각 디버거 프로세스별로 탭이나 디버그 세션 뷰가 표시됩니다(그림 4 참조).
그림 4.LLDB를 사용한 네이티브 코드 디버깅
LLDB 디버거가 C/C++ 코드에서 중단점에 도달하면 Android 스튜디오는<your-module>탭으로 전환됩니다.Frames,Variables,Watches창도 사용할 수 있으며 이러한 창은 자바 코드를 디버깅할 때와 똑같은 방식으로 작동합니다.Threads창을 LLDB 세션 뷰에서 사용할 수는 없지만Frames창의 드롭다운 목록을 사용하여 앱 프로세스에 액세스할 수 있습니다. 이 창에 관한 자세한 내용은디버그 창 프레임및변수 검사방법을 설명하는 섹션을 참조하세요.
참고:네이티브 코드의 중단점을 검사하는 중에 Android 시스템에서는 앱의 자바 바이트코드를 실행하는 가상 머신을 정지합니다. 즉, 네이티브 코드의 중단점을 검사하는 동안에는 자바 디버거와 상호작용할 수 없거나 자바 디버거 세션에서 상태 정보를 검색할 수 없습니다.
자바 디버거가 자바 코드에서 중단점에 도달하면 Android 스튜디오는<your-module>-java탭으로 전환됩니다.
LLDB로 디버깅하는 동안 LLDB 세션 뷰의LLDB터미널을 사용하여명령줄 옵션을 LLDB로전달할 수 있습니다. 앱 디버깅을 시작할 때마다 LLDB에서 실행하도록 할 특정 명령어가 있다면 디버거가 앱 프로세스에 연결되기 직전이나 연결된 직후에명령어를 디버그 구성에 추가하면 됩니다.
C/C++ 코드를 디버깅하는 중에는watchpoint라는 특수 유형의 중단점을 설정할 수도 있습니다. watchpoint는 앱이 메모리의 특정 블록과 상호작용할 때 앱 프로세스를 정지할 수 있습니다. 자세히 알아보려면watchpoint 추가방법을 설명하는 섹션을 참조하세요.
중단점 보기 및 구성하기
모든 중단점을 보고 중단점 설정을 구성하려면Debug창 왼쪽의View Breakpoints
를 클릭합니다. 그림 5와 같이Breakpoints창이 나타납니다.
그림 5.현재 중단점이 모두 나와 있고 각 중단점의 동작 설정이 포함된 Breakpoints 창
Breakpoints창 왼쪽에 있는 목록에서 각 중단점을 사용 설정하거나 사용 중지할 수 있습니다. 중단점을 사용 중지하면 Android 스튜디오는 이 중단점에 도달하더라도 앱을 일시중지하지 않습니다. 설정을 구성할 중단점을 목록에서 선택합니다. 처음에 중단점을 사용 중지하고 다른 중단점에 도달한 후에 시스템이 중단점을 사용 설정하도록 구성할 수 있습니다. 또한 중단점에 도달한 후 중단점의 사용 중지 여부를 구성할 수도 있습니다. 예외에 중단점을 설정하려면 중단점 목록에서Exception Breakpoints를 선택합니다.
디버그 창 프레임
Debugger창에 있는Frames창에서는 현재 중단점에 도달하도록 야기한 스택 프레임을 검사할 수 있습니다. 이렇게 하면 스택 프레임을 탐색하고 검토할 수 있으며 또한 Android 앱의 스레드 목록을 검사할 수도 있습니다. 스레드를 선택하려면 스레드 선택기 드롭다운을 사용하여 스택 프레임을 표시합니다. 프레임에 있는 요소를 클릭하면 소스가 편집기에서 열립니다.창 프레임 가이드의 설명대로 스레드 표현을 맞춤설정하고 스택 프레임을 내보낼 수도 있습니다.
변수 검사
Debugger창에 있는Variables창에서는 시스템이 중단점에서 앱을 중지할 때 변수를 검사할 수 있으며Frames창에서는 프레임을 선택할 수 있습니다. 또한Variables창을 사용하면 선택한 프레임 내에서 사용 가능한 정적 메서드 또는 변수를 사용하여 임시 식을 평가할 수 있습니다.
Watches창도 유사한 기능을 제공하지만, 예외적으로Watches창에 추가된 식은 디버깅 세션 간에 유지됩니다. 자주 액세스하는 변수와 필드 또는 현재 디버깅 세션에 유용한 상태를 제공하는 변수와 필드의 경우 감시를 추가해야 합니다. 그림 5처럼Variables창과Watches창이 나타납니다.
변수나 식을Watches목록에 추가하려면 다음 단계를 따르세요.
디버깅을 시작합니다.
Watches창에서Add
를 클릭합니다.
나타나는 텍스트 상자에 감시하려는 변수나 식의 이름을 입력하고 Enter를 누릅니다.
Watches목록에서 항목을 삭제하려면 항목을 선택하고Remove
를 클릭합니다.
Watches목록에서 항목을 선택한 후Up
또는Down
을 클릭하여 요소의 순서를 변경할 수 있습니다.
그림 6.Debugger 창에 있는 Variables 창과 Watches 창
watchpoint 추가
C/C++ 코드를 디버깅하는 중에는watchpoint라는 특수 유형의 중단점을 설정할 수 있습니다. watchpoint는 앱이 메모리의 특정 블록과 상호작용할 때 앱 프로세스를 중지할 수 있습니다. 예를 들어 두 개의 포인터를 메모리 블록에 설정하고 여기에 watchpoint를 할당한 경우 두 포인터 중 하나를 사용하여 메모리 블록에 액세스하면 이 watchpoint가 트리거됩니다.
Android 스튜디오에서 런타임 중에 특정 변수를 선택하여 watchpoint를 만들 수 있지만, LLDB는 변수 자체가 아니라 시스템이 변수에 할당한 메모리 블록에만 watchpoint를 할당합니다. 이는Watches창에 변수를 추가하는 것과는 다릅니다. 이 경우에는 변수 값을 관찰할 수 있지만 시스템이 메모리의 값을 읽거나 변경할 때는 앱 프로세스를 중단할 수 없습니다.
참고:앱 프로세스가 함수를 종료하고 시스템이 메모리에서 로컬 변수 할당을 해제하는 경우, 이들 변수별로 생성했던 watchpoint를 다시 할당해야 합니다.
watchpoint를 설정하려면 다음 요구사항을 충족해야 합니다.
대상 실제 기기나 에뮬레이터가 x86 또는 x86_64 CPU를 사용합니다. 기기가 ARM CPU를 사용하는 경우 메모리에서 변수 주소의 경계를 4바이트(32비트 프로세서) 또는 8바이트(64비트 프로세서)로 정렬해야 합니다. 아래와 같이 변수 선언부에__attribute__((aligned(num_bytes)))를 지정하여 네이티브 코드에서 변수를 정렬할 수 있습니다.// For a 64-bit ARM processor int my_counter __attribute__((aligned(8)));
이미 watchpoint를 세 개 이하 할당했습니다. Android 스튜디오는 x86 또는 x86_64 대상 기기에서 최대 네 개의 watchpoint만 지원합니다. 다른 기기의 경우 더 적은 watchpoint를 지원할 수도 있습니다.
참고:32비트 ARM ABI를 사용하여 앱을 디버깅할 때 watchpoint를 추가하거나 코드 내의 변수에 마우스를 가져가서 값을 조사하면 비정상 종료가 발생할 수 있습니다. 이 문제를 해결하려면 64비트 ARM, x86 또는 x86_64 바이너리를 사용하여 디버그하세요. 이 문제는 향후 Android 스튜디오 버전에서 해결될 예정입니다.
위의 요구사항을 충족한다면 다음과 같이 watchpoint를 추가할 수 있습니다.
중단점에서 앱이 정지된 동안 LLDB 세션 뷰의Variables창으로 이동합니다.
추적하려는 메모리 블록을 차지한 변수를 마우스 오른쪽 버튼으로 클릭하고Add Watchpoint를 선택합니다. watchpoint를 구성하는 대화상자가 나타납니다(그림 7 참조).
그림 7.메모리의 변수에 watchpoint 추가하기
다음 옵션으로 watchpoint를 구성합니다.
Enabled:당분간 watchpoint를 무시하도록 Android 스튜디오에 지시하려면 이 옵션을 선택 해제하면 됩니다. Android 스튜디오는 여전히 watchpoint를 저장하므로, 나중에 디버그 세션에서 watchpoint에 액세스할 수 있습니다.
Suspend:기본적으로, Android 시스템은 watchpoint에 할당된 메모리 블록에 액세스할 때 앱 프로세스를 중단합니다. 이 동작을 원치 않으면 옵션을 선택 해제할 수 있습니다. 그러면 시스템이 watchpoint와 상호작용할 때의 동작을 맞춤설정할 수 있는Log message to console및Remove [the watchpoint] when hit등의 추가 옵션이 나타납니다.
Access Type:시스템이 변수에 할당한 메모리 블록을 대상으로 앱이읽기또는쓰기를 시도할 때 앱이 watchpoint를 트리거할지 여부를 선택합니다. 읽기 또는 쓰기 시에 watchpoint를 트리거하려면Any를 선택합니다.
Done을 클릭합니다.
모든 watchpoint를 보고 watchpoint 설정을 구성하려면Debug창 왼쪽의View Breakpoints
를 클릭합니다. 그림 8과 같은Breakpoints대화상자가 나타납니다.
그림 8.현재 watchpoint가 모두 나와 있고 각 watchpoint의 동작 설정이 포함된 Breakpoints 대화상자
watchpoint를 추가한 후Debug창 왼쪽에서Resume Program
을 클릭하여 앱 프로세스를 계속합니다. 기본적으로, watchpoint를 설정했던 메모리 블록에 앱이 액세스하려고 시도하면 Android 시스템이 앱 프로세스를 중단하며 앱이 마지막으로 실행했던 코드 줄 옆에 watchpoint 아이콘
이 나타납니다(그림 9 참조).
그림 9.watchpoint를 트리거하기 직전에 앱이 실행하는 코드 줄을 나타내는 Android 스튜디오
리소스 값 표시 형식의 보기 및 변경
디버그 모드에서 리소스 값을 확인하고 자바 코드 변수의 다른 표시 형식을 선택할 수 있습니다.Variables탭을 표시하고 프레임을 선택한 상태에서 다음 단계를 따르세요.
Variables목록에서 리소스 줄의 임의의 위치를 마우스 오른쪽 버튼으로 클릭하여 드롭다운 목록을 표시합니다.
드롭다운 목록에서View as를 선택하고 사용할 형식을 선택합니다.
사용 가능한 형식은 선택한 리소스의 데이터 유형에 따라 다릅니다. 다음 옵션 중 하나 이상이 나타납니다.
Class:클래스 정의를 표시합니다.
toString:문자열 형식을 표시합니다.
Object:객체(클래스의 인스턴스) 정의를 표시합니다.
Array:배열 형식으로 표시합니다.
Timestamp:날짜 및 시간을 yyyy-mm-dd hh:mm:ss 형식으로 표시합니다.
Auto:Android 스튜디오가 데이터 유형에 따라 최적의 형식을 선택합니다.
Binary:0과 1을 사용하여 바이너리 값을 표시합니다.
MeasureSpec:상위 요소로부터 선택한 하위 요소로 전달되는 값입니다.MeasureSpec을 참조하세요.
댓글