Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Dalvik 分析之准備篇

Dalvik 分析之准備篇

編輯:Android開發實例

 前言:dalvik 是 Android 的重要組成部分 ,掌握其運行機制對理解整個Android系統有著相當之大的幫助。本文將介紹GDB單步調試和Dexdump工具的使用,期望為探索dalvik打下一定的基礎。

  1. Dalvik 之編譯 為了能夠更方便的調試dalvik,我們需要編譯一個在X86上運行的dalvik和相關工具。編譯步驟如下:
  1. 首先進入到Android 源碼根目錄
  2. source build/envsetup.sh (不是網上有些文章寫的只輸入 build/envsetup.sh)
  3. lunch 2 在此之後可以看到TARGET_PRODUCT 為sim。TARGET_ARCH為x86
  4. make  或者 make dalvikvm 和 make dexdump   (make 為編譯所有程序,比較耗時,有時甚至某些模塊編譯不過,如為節省時間,可使用make dalvikvm直接編譯dalvik, make dexdump直接編譯dexdump)
  2. Gdb調試dalvik之准備工作 在用gdb啟動dalvik時,需要設置一些環境,比較繁瑣,這裡創建一個腳本來簡化這些過程,腳本名為grund.sh,放於Android源碼根目錄。下面為腳本內容。   #!/bin/sh base=`pwd` root=$base/out/debug/host/linux-x86/pr/sim/system export ANDROID_ROOT=$root bootpath=$root/framework export BOOTCLASSPATH=$bootpath/core.jar:$bootpath/ext.jar:$bootpath/framework.jar:$bootpath/android.police.jar export ANDROID_DATA=/tmp/dalvik_test mkdir -p $ANDROID_DATA/dalvik-cache exec gdb $root/bin/dalvikvm    3. Gdb 調試 dalvik
  1. 准備一個簡單的java 程序,如hello.java,編譯後將hello.jar拷貝至Android 源碼根目錄。 (hello.java與makefile見附錄)
  2. 進入到Android 源碼根目錄
  3. ./grund.sh (執行上述腳本,之後會看到gdb提示符)
  4. 在gdb提示符後輸入 “set args –cp hello.jar hello”
  5. 這個時候就可以設置斷點,單步跟蹤了!如有對gdb不熟的同學,請google之。 main()函數為入口函數,先在main.c 212行設置斷點(在gdb提示符後輸入 “b 212”)
  6. 在gdb提示符後輸入”r”, OK,我們會看到dalvik被gdb啟動執行,然後停於212行,執行JNI_CreateJavaVM函數前先看看gDvm的內容(輸入p gDvm)。 然後執行JNI_CreateJavaVM函數(輸入“n”),再看看gDvm的內容。對比執行前後的變化,可大概知道JNI_CreateJavaVM函數所做的事情。
  7. main.c 249 行代碼用於加載hello.class,在249行設置斷點。在此中斷後,看下slashClass的內容(輸入“p slashClass“),slashClass正是”hello”字符串。接下來單步進入執行之(輸入”s”),然後查看下函數調用棧(輸入”bt”)。可知現在正在執行的是jni.c 中的FindClass函數。通過此方法,可知函數指針指向的是何函數。
  8. main.c 255行代碼用於取得hello.java 中main函數編譯後的字節碼。類似於g步驟,可知此時執行的函數為jni.c中的GetStaticMethodID函數
  9. main.c 273行代碼執行main函數編譯後的字節碼,類似於g步驟,可知此時執行的函數為jni.c 中的2681行。此處為宏定義,不容易找到。但通過gdb調試,可以准確的定位。如此時繼續運行程序,”hello world” 就會出現在我們的眼前!
  此處只做簡單分析,為拋磚引玉用,各位同學可以藉此探究自己感興趣的內容。在接下來的文章中會詳細分析class加載與字節碼的執行。   4. dexdump查看jar文件   Dexdump 可執行文件放於out目錄下, 可使用”find out/ -name dexdump”命令來找到dexdump。 “dexdump –f hello.jar” 命令可打印jar文件的頭部信息。 “dexdump –d hello.jar” 可打印所編譯的字節碼。   頭部信息如下: Opened 'hello.jar', DEX version '035' DEX file header: magic               : 'dex 035' checksum            : f2f85a9c signature           : 0404...7831 file_size           : 740 header_size         : 112 link_size           : 0 link_off            : 0 (0x000000) string_ids_size     : 14 string_ids_off      : 112 (0x000070) type_ids_size       : 7 type_ids_off        : 168 (0x0000a8) field_ids_size      : 1 field_ids_off       : 232 (0x0000e8) method_ids_size     : 4 method_ids_off      : 240 (0x0000f0) class_defs_size     : 1 class_defs_off      : 272 (0x000110) data_size          : 436 data_off            : 304 (0x000130)     其中string_ids,type_ids,field_ids,method_ids, class_defs皆可理解為索引。通過這些索引,可以查到真正的數據存放位置。Data_off為真正的數據存放位置。     字節碼如下:     #1              : (in Lhello;)       name          : 'main'       type          : '([Ljava/lang/String;)V'       access        : 0x0009 (PUBLIC STATIC)       code          -       registers     : 3       ins           : 1       outs          : 2       insns size    : 10 16-bit code units 000148:                                        |[000148] hello.main:([Ljava/lang/String;)V 000158: 6200 0000                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // [email protected] 00015c: 1a01 0900                              |0002: const-string v1, "hello world" // [email protected] 000160: 6e20 0200 1000                         |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // [email protected] 000166: 2a00 0000 0000                         |0007: goto/32 #00000000       catches       : (none)       positions     :         0x0000 line=4         0x0007 line=5       locals        :    Virtual methods   -  source_file_idx   : 10 (hello.java)     附錄: Hello.java : public class hello{       public static void main(String args[]) {                   System.out.println("hello world");                   while(true) {}       } }   Makefile: ANDROID_SRC_DIR := /android/platform_sim   android_dir_dx = $(ANDROID_SRC_DIR)/out/host/linux-x86/bin/dx   all:       javac hello.java       $(android_dir_dx) --dex --output=hello.jar hello.class clean:       @rm *.jar *.class
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved