Android FrameWork學習(二)Android系統源碼調試

轉:https://blog.csdn.net/LoongEmbedded/article/details/79427888

點擊打開鏈接

通過上一篇 Android FrameWork學習(一)Android 7.0系統源碼下載\編譯 我們瞭解瞭如何進行系統源碼的下載和編譯工作。

爲了更進一步地學習跟研究 Android 系統源碼,今天我們來講講如何進行 Android 系統源碼的調試,只有學會了如何進行系統源碼的調試,才能幫助我們更高效地閱讀跟理解源碼。

我們知道,Android Framework 的代碼主要由Java、C\C++等代碼組成,因此,對於系統源碼的調試,我們這裏將其分爲了兩部分

1. Java 相關代碼的調試

2. C\C++ Native 相關代碼的調試


一、Java 相關代碼的調試

對於 Java 相關代碼的調試,這裏我們主要使用 Android Studio 開發工具來進行。

導入源碼到 Android Studio

要在 Android Studio 中調試源碼,那第一步自然是導入系統源碼到 Android Studio 中了。

1. 編譯 idegen

對於 Android 源碼的導入, Google 官方給我們提供了一個很方便的工具 idegen

它位於我們所下載的系統源碼路徑中:

developement/tools/idegen
  • 1

引用 README 的一句話

IDEGen automatically generates Android IDE configurations for IntelliJ IDEA 
and Eclipse.

idegen 工具會自動生成針對 Android 開發工具(Android Studio和Eclipse)的配置文件。

既然如此,那我們就來使用 idegen 工具生成導入源碼所需的配置文件。

首先打開命令行工具,cd 進入到源碼路徑下,

執行如下指令:

#初始化命令工具
soruce build/envsetup.sh 
#編譯 idegen 模塊,生成idegen.jar
mmm development/tools/idegen/
#生成針對 Android 開發工具的配置文件 
sudo ./development/tools/idegen/idegen.sh
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在執行完上述指令後,會在源碼路徑下生成下面三個文件

Paste_Image.png

android.ipr:工程相關的設置,比如編譯器配置、入口,相關的libraries等。

android.iml:描述了modules,比如modules的路徑,依賴關係等。

android.iws:包含了一些個人工作區的設置。

2. 導入源碼

接下來我們可以開始導入源碼了.

如果你是第一次導入源碼, Android Studio 可能需要佔用大量的內存,我們需要設置下我們的 VM 選項。

Linux 設備的話在 Android Studio 的 bin/studio64.vmoptions 文件中添加-Xms748m -Xmx748m

如果你使用的是 Mac ,那麼在 AS 目錄的 Contents/Info.plist 目錄中進行添加。

由於 Android 的系統源碼非常龐大,一次性導入 Android Studio 的話需要加載非常長的時間

因此,在正式開始導入前,我們可以打開 android.iml 文件根據自己需要調整要加載的源碼。

Paste_Image.png

這裏 <excludeFolder> 表示不需要加載的目錄,我們根據自己的需要使用 <excludeFolder> 標籤添加對應的目錄地址即可。

接着,選擇 File -> open 選中 android.ipr 文件,打開

Paste_Image.png

這時 Android Studio 就會開始加載源碼了

在沒有添加修改 <excludeFolder> 的情況下,這個加載的時間會比較長,經過一段時間的等待後,代碼就加載完畢了,如圖:

Paste_Image.png

這裏紅色的目錄代表被 exclude 排除了,代碼加載 scan index 的時候會過濾掉該目錄。

在加載完源碼後,我們也可以在 Project Structure 中的 Module 選項中右鍵 exclude 來排除不需要加載的源碼目錄,如圖:

Paste_Image.png

Paste_Image.png

3. 配置代碼依賴,確保代碼跳轉正確

爲了閱讀和調試代碼的時候能夠保證代碼跳轉正確,我們需要配置下相關依賴。

首先是 AOSP 源碼的跳轉,我們通過 File -> Project Structure 打開 Module,然後選中 Dependencies, 保留 JDK 跟 Module Source 項,並添加源碼的 external 和 frameworks 依賴,如圖:

Paste_Image.png

然後是 SDK 的設置,確保關聯對應版本的 SDK 於系統版本一直

Paste_Image.png

開始調試源碼

調試前要設置 Project 的 SDK , File -> Project 下打開 Project Structure,選中 Project 設置對應版本的 SDK,於系統版本一致:

Paste_Image.png

確保 Android Studio 允許 ADB 調試

Paste_Image.png

接着我們參照上一篇文章中講的方法打開 Android 模擬器

此時點擊 Android Studio 工具欄的 attach debugger to Android process 按鈕,會打開 Choose Process 窗口,我們根據自己需要調試的代碼選擇對應的進程:

Paste_Image.png

這裏假設我們要調試 Android 自帶瀏覽器的源碼,如圖,我們在它的入口文件 WebViewBrowserActivity 中的 loadUrlFromUrlBar 方法中打上斷點。

Paste_Image.png

點擊 WebViewBrowser 打開 app

Paste_Image.png

打開之後,點擊 attach to Android process 按鈕打開 choose Process,可以看到 webViewBrowser 運行的進程,選中,ok

Paste_Image.png

然後我們在 app 的 url 輸入欄輸入 網址進行跳轉

Paste_Image.png

Paste_Image.png

如圖所示我們可以看到,代碼成功進入了斷點,然後我們就可以隨心所欲地調試我們想要的調試的 Java 代碼了。


二、Native C\C++ 相關代碼調試

對於 Framework Native 代碼,我們這裏使用 GDB 工具來進行調試。

什麼是 GDB 呢?

它是一款 GNU 項目調試工具,它的功能非常強大,可以用來調試 C 、C++、Object-C、Pascal 等語言編寫的項目。

對於使用習慣了可視化 IDE 的同學們來說,它最大的缺點可能就是它不支持圖形化了

但是 GDB 提供的指令非常靈活,通過指令我們 
* 可以隨心所欲地啓動程序, 
* 可以根據自己的需要設置斷點, 
* 可以查看斷點處的變量,代碼信息 
* 可以查看程序運行的調用棧

一旦你熟悉了它,你便可以玩得飛起!

一般情況下,使用 gdb 來調試 Android 源碼需要在 Android 設備上安裝 gbdserver attach 關聯我們需要調試的進程,再使用 gdb 指令去連接 gdbserver 進行調試

不過官方給我們提供了 gdbclient 工具,可以讓我們方便地進行 gdb 調試。

開始 GDB 調試

這裏我們就基於 gdbclient 來進行實際的 gdb 調試演示:

跟上面 Java 調試一樣,我們這裏還是以系統自帶的瀏覽器爲例。

1. 點擊啓動圖標打開瀏覽器 app:

Paste_Image.png

2. 打開一個命令行終端,cd 進入到系統源碼目錄(我的源碼路徑爲 aosp),初始化命令工具:

#進入源碼路徑
cd aosp
#初始化命令工具
source build/envsetup.sh
#選擇編譯的源碼的版本,參考上一篇文章
lunch
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

初始化命令工具

Paste_Image.png

3. 通過 adb 指令來查找要調試進程的 PID

#通過 shell ps 指令查找相關進程,grep 搜索過濾 webview 進程
adb shell ps -A | grep webview
  • 1
  • 2

Paste_Image.png

如圖,2157 爲系統自帶瀏覽器 app 所在進程的 PID

4. 使用 gdbclient 命令工具啓用 gdb 調試 PID 對應進程

# gdbclient <app pid> 可以啓用 gdb 調試對應 PID 進程
gdbclient 2157
  • 1
  • 2

Paste_Image.png

等待進入 gdb 調試命令界面

Paste_Image.png

5. 使用 GDB b 命令打斷點

在 gdb 指令中,我們使用b <代碼文件>:行號 來設置斷點.

這裏我們選擇 frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp 代碼文件的 drawFrame 方法打上斷點,位於文件 71 行:

Paste_Image.png

該方法主要用於繪製幀,當瀏覽器 app 的界面發生變化時會觸發該方法。

我們輸入設置斷點命令:

b frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp:71
  • 1

Paste_Image.png

輸入指令後顯示 
Breakpoint 2 at 0x7f69e9892c11: file frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp, line 71. 
說明我們的斷點設置成功了。

6. 在命令行輸入c 開始監聽

Paste_Image.png

c 即 continue,此時界面上出現 Continuing 說明開始監聽進程了

我們點開模擬器,隨意操作,觸發界面變化時,便會進入繪製幀的代碼斷點了:

Paste_Image.png

如圖,顯示進入斷點,這樣代表我們的代碼調試成功了。


這裏我們只是演示了一個大概流程,

gdb 代碼的調試需要你對源碼有一定的熟悉,知道哪個進程會調用哪個文件方法。

同時,我們還需要熟悉 gdb 的各種命令,這裏給大家推薦一篇不錯的入門文章,可以快速入門:

GDB十分鐘教程

這裏補充一點,如果你希望在某個進程啓動時就監聽,可以使用下面的指令關聯目錄,得到 pid,再通過 gdbclient 來進行調試

adb shell gdbserver :5039 /system/bin/my_test_app
Process my_test_app created; pid = 3460
Listening on port 5039
  • 1
  • 2
  • 3
gdbclient <app pid>
  • 1

如果你希望通過 Android Studio 來調試 Framework 的 C\C++ 代碼的話,也可以參考下面的兩篇文章,不過個人覺得這種方法有一定的侷限性。

如何調試Android Native Framework

用Android Studio調試Framework層代碼