Programming/Android & Java2012. 11. 2. 10:48

안드로이드 웹킷의 Native 디버깅 방법


일반적으로 안드로이드에서 Native 코드의 디버깅 방법은 개발자 사이트에가면 쉽게 알 수 있다.

Android NDK에서 주로 제공되는 샘플코드는 어플리케이션 개발자가 직접 C / Java코드를 혼합하여 사용할 경우
Native 코드의 빌드 및 디버깅 방법을 알려주고 있다.

웹킷의 Native 디버깅도 비슷하나 약간의 차이가 있으며 조금 까다롭고 번거롭다.

본 글은 오렐리의 OSCON - Android WebKit Development 의 내용을 참고 하여 작성하였다.

# 환경
리눅스 (우분투 11.04)
안드로이드 빌드 환경
안드로이드 2.3 진저브레드 소스
안드로이드 SDK
GDB(arm-eabi-gdb)
DDD(Data Display Debugger)

# 방법
1. 리눅스 설치

2. 안드로이드 빌드 환경 설정
    여기를 참고하여 안드로이드 빌드 환경을 설정한다. (빌드에 필요한 패키시 설치)

3. 안드로이드 SDK 설치
    여기를 참고하여 SDK를 다운받는다 
    $(SDK)/platform-tools, $(SDK)/tools를 PATH에 추가한다
    이후 Emulator 실행에 필요하다

4. 안드로이드 소스 받기(진저브레드)
    여기를 참고하여 안드로이드를 소스를 다운받는다.

    $ repo init -u https://android.googlesource.com/platform/manifest -b android-2.3.7-r1

    이후 각각 사용되는 안드로이드 소스 위치는 다음과 같다. (참고 용)
    /home/haejung/android
    /home/haejung/android/build/buildspec.mk.default
    /home/haejung/android/external/webkit/Android.mk
    /home/haejung/android/out/target/product/generic

5. buildspec.mk 수정하기 (웹킷을 디버그 모드로 빌드하기)

    /home/haejung/android $ cp build/buildspec.mk.default ./buildspec.mk    
    build/buildspec.mk.default를 안드로이드 소스 루트에 buildspec.mk로 복사한다.
  
    복사한 buildspec.mk에 다음을 추가한다.
    DEBUG_MODULE_libwebcore:=true
    DEBUG_MODULE_libxml2:=true
    TARGET_CUSTOM_DEBUG_CFLAGS:=­O0 ­mlong­calls
    ADDITIONAL_BUILD_PROPERTIES += debug.db.uid=100000

6. external/webkit/Android.mk 수정하기 (웹킷 빌드시 Prelink 기능 비활성화)
    Prelink 활성화 상태로 웹킷을 빌드하면 너무 큰 디버그 심볼이 생성되어 빌드가 중단된다.
    따라서 웹킷의 Android.mk를 수정하여 Prelink 기능을 비 활성화 한다.
 
    /home/haejung/android $ vi external/webkit/Android.mk
    
    #LOCAL_PRELINK_MODULE := false 를
    LOCAL_PRELINK_MODULE := false 로 수정하여 주석상태를 해제한다.

7. 안드로이드 빌드
    빌드에 필요한 환경을 source하고 engineer모드로 설정 후 빌드를 수행한다.
    필요하면 make -j로 job 개수를 지정하여 빌드를 수행한다.(예: make -j2 or make -j4)

    /home/haejung/android $ source build/envsetup.sh
    /home/haejung/android $ lunch full-eng
    /home/haejung/android $ make

8. 에물레이터 실행 (빌드한 안드로이드 바이너리 실행)    

    /home/haejung/android $ export ANDROID_PRODUCT_OUT=/home/haejung/android/out/target/product/generic
    /home/haejung/android $ emulator

9. GDB로 웹킷 디버깅

    에물레이터에서 브라우져를 실행한다.
    프로세스가 있어야 GDB로 Attach 할 수 있다.

    원격 디버깅을 위한 Port Forwarding 한다 (타겟: 사용자 컴퓨터)
    /home/haejung/android $ adb forward tcp:5039 tcp:5039
   
    에물레이터에서 실행중인 브라우저 프로세스 ID를 찾는다. (타겟: 에물레이터)
    /home/haejung/android $ adb shell ps | grep 'browser' | awk '{ print $2}'
    
    이후 화면에 출력된 PID를 사용하여 GDBServer를 실행한다. (타겟: 에물레이터)
    /home/haejung/android $ adb shell gdbserver :5039 --attach PID
    
    (참고) 타겟: 에물레이터는 에물레이터에서 실행해야한다. 즉, adb shell로 에물레이터 쉘에 진입 후
    해야 하지만 adb에서는 위처럼 사용자 컴퓨터에서 진입하지 않고 바로 실행할 수 있다.

    GDB(arm-eabi-gdb) 실행 (타겟: 사용자 컴퓨터)
    /home/haejung/android $ prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-gdb

    GDB 진입 후 라이브러리 심볼 로드 및 접속
    GDB > set solib-absoulte-prefix /home/haejung/android/out/target/product/generic/symbols
    GDB > set solib-search-path /home/haejung/android/out/target/product/generic/symbols/system/lib
    GDB > file /home/haejung/android/out/target/product/generic/symbols/system/bin/app_process
    GDB > target remote :5039

    GDB가 GDBSERVER에 접속 후 라이브러리 로딩이 이루어진다.

    브레이크 걸기(Break) 위치: external/webkit/WebCore/rendering/RenderBlock.cpp::paintObject(PaintInfo&, int, int)
    GDB > b WebCore::RenderBlock::paintObject
    프로세스 계속(Continue)
    GDB > c

    이후에 에물레이터에서 실행중인 브라우저에 클릭하여 새로운 화면이 렌더링 되게 한다.
    
    아래 화면처럼 브레이크가 수행되는 화면을 보고 디버깅을 수행하면 된다.
    
      

    GDB와 DDD는 다른 UI를 보여주는데 그냥 GDB를 사용하기 보다는 DDD를 사용하면 좀더 수월하다

    DDD 설치
    /home/haejung/android $ sudo apt-get install ddd

    DDD 실행 (Backend gdb를 arm-eabi-gdb로 설정해야 한다)
    /home/haejung/android $ ddd --debugger prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-gdb

    추가로 사용하는 스크립트를 함께 업로드 한다.
    필요에 따라 각자 환경에 맞게 수정하여 사용하면 된다.

    환경 설정(SDK, arm-eabi-gdb , ANDROID_PRODUCT_OUT 설정)

    GDB 명령어 스크립트 ( $ ddd --debugger arm-eabi-gdb -x ./gdbinit
    gdbinit

    에물레이터 GDBServer를 브라우저에 Attach

    이상 끝.


Posted by Mocker