Android FrameWork學(xué)習(xí)(二)Android系統(tǒng)源碼調(diào)試

通過上一篇 Android FrameWork學(xué)習(xí)(一)Android 7.0系統(tǒng)源碼下載\編譯 我們了解了如何進(jìn)行系統(tǒng)源碼的下載和編譯工作。

為了更進(jìn)一步地學(xué)習(xí)跟研究 Android 系統(tǒng)源碼,今天我們來講講如何進(jìn)行 Android 系統(tǒng)源碼的調(diào)試,只有學(xué)會(huì)了如何進(jìn)行系統(tǒng)源碼的調(diào)試,才能幫助我們更高效地閱讀跟理解源碼。

我們知道,Android Framework 的代碼主要由Java、C\C++等代碼組成,因此,對(duì)于系統(tǒng)源碼的調(diào)試,我們這里將其分為了兩部分

  • Java 相關(guān)代碼的調(diào)試
  • C\C++ Native 相關(guān)代碼的調(diào)試

一、Java 相關(guān)代碼的調(diào)試

對(duì)于 Java 相關(guān)代碼的調(diào)試,這里我們主要使用 Android Studio 開發(fā)工具來進(jìn)行。

導(dǎo)入源碼到 Android Studio

要在 Android Studio 中調(diào)試源碼,那第一步自然是導(dǎo)入系統(tǒng)源碼到 Android Studio 中了。

1. 編譯 idegen

對(duì)于 Android 源碼的導(dǎo)入, Google 官方給我們提供了一個(gè)很方便的工具 idegen

它位于我們所下載的系統(tǒng)源碼路徑中:

developement/tools/idegen

引用 README 的一句話

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

idegen 工具會(huì)自動(dòng)生成針對(duì) Android 開發(fā)工具(Android Studio和Eclipse)的配置文件。

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

首先打開命令行工具,cd 進(jìn)入到源碼路徑下,

執(zhí)行如下指令:

#初始化命令工具
soruce build/envsetup.sh 
#編譯 idegen 模塊,生成idegen.jar
mmm development/tools/idegen/
#生成針對(duì) Android 開發(fā)工具的配置文件 
sudo ./development/tools/idegen/idegen.sh

在執(zhí)行完上述指令后,會(huì)在源碼路徑下生成下面三個(gè)文件

Paste_Image.png

android.ipr:工程相關(guān)的設(shè)置,比如編譯器配置、入口,相關(guān)的libraries等。

android.iml:描述了modules,比如modules的路徑,依賴關(guān)系等。

android.iws:包含了一些個(gè)人工作區(qū)的設(shè)置。

2. 導(dǎo)入源碼

接下來我們可以開始導(dǎo)入源碼了.

如果你是第一次導(dǎo)入源碼, Android Studio 可能需要占用大量的內(nèi)存,我們需要設(shè)置下我們的 VM 選項(xiàng)。

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

如果你使用的是 Mac ,那么在 AS 目錄的 Contents/Info.plist 目錄中進(jìn)行添加。

由于 Android 的系統(tǒng)源碼非常龐大,一次性導(dǎo)入 Android Studio 的話需要加載非常長(zhǎng)的時(shí)間

因此,在正式開始導(dǎo)入前,我們可以打開 android.iml 文件根據(jù)自己需要調(diào)整要加載的源碼。

Paste_Image.png

這里 <excludeFolder> 表示不需要加載的目錄,我們根據(jù)自己的需要使用 <excludeFolder> 標(biāo)簽添加對(duì)應(yīng)的目錄地址即可。

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

Paste_Image.png

這時(shí) Android Studio 就會(huì)開始加載源碼了

在沒有添加修改 <excludeFolder> 的情況下,這個(gè)加載的時(shí)間會(huì)比較長(zhǎng),經(jīng)過一段時(shí)間的等待后,代碼就加載完畢了,如圖:

Paste_Image.png

這里紅色的目錄代表被 exclude 排除了,代碼加載 scan index 的時(shí)候會(huì)過濾掉該目錄。

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

Paste_Image.png
Paste_Image.png

3. 配置代碼依賴,確保代碼跳轉(zhuǎn)正確

為了閱讀和調(diào)試代碼的時(shí)候能夠保證代碼跳轉(zhuǎn)正確,我們需要配置下相關(guān)依賴。

首先是 AOSP 源碼的跳轉(zhuǎn),我們通過 File -> Project Structure 打開 Module,然后選中 Dependencies, 保留 JDK 跟 Module Source 項(xiàng),并添加源碼的 external 和 frameworks 依賴,如圖:

Paste_Image.png

然后是 SDK 的設(shè)置,確保關(guān)聯(lián)對(duì)應(yīng)版本的 SDK 于系統(tǒng)版本一直

Paste_Image.png

開始調(diào)試源碼

調(diào)試前要設(shè)置 Project 的 SDK , File -> Project 下打開 Project Structure,選中 Project 設(shè)置對(duì)應(yīng)版本的 SDK,于系統(tǒng)版本一致:

Paste_Image.png

確保 Android Studio 允許 ADB 調(diào)試

Paste_Image.png

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

此時(shí)點(diǎn)擊 Android Studio 工具欄的 attach debugger to Android process 按鈕,會(huì)打開 Choose Process 窗口,我們根據(jù)自己需要調(diào)試的代碼選擇對(duì)應(yīng)的進(jìn)程:

Paste_Image.png

這里假設(shè)我們要調(diào)試 Android 自帶瀏覽器的源碼,如圖,我們?cè)谒娜肟谖募? WebViewBrowserActivity 中的 loadUrlFromUrlBar 方法中打上斷點(diǎn)。

Paste_Image.png

點(diǎn)擊 WebViewBrowser 打開 app


Paste_Image.png

打開之后,點(diǎn)擊 attach to Android process 按鈕打開 choose Process,可以看到 webViewBrowser 運(yùn)行的進(jìn)程,選中,ok

Paste_Image.png

然后我們?cè)?app 的 url 輸入欄輸入 網(wǎng)址進(jìn)行跳轉(zhuǎn)

Paste_Image.png
Paste_Image.png

如圖所示我們可以看到,代碼成功進(jìn)入了斷點(diǎn),然后我們就可以隨心所欲地調(diào)試我們想要的調(diào)試的 Java 代碼了。


二、Native C\C++ 相關(guān)代碼調(diào)試

對(duì)于 Framework Native 代碼,我們這里使用 GDB 工具來進(jìn)行調(diào)試。

什么是 GDB 呢?

它是一款 GNU 項(xiàng)目調(diào)試工具,它的功能非常強(qiáng)大,可以用來調(diào)試 C 、C++、Object-C、Pascal 等語言編寫的項(xiàng)目。

對(duì)于使用習(xí)慣了可視化 IDE 的同學(xué)們來說,它最大的缺點(diǎn)可能就是它不支持圖形化了

但是 GDB 提供的指令非常靈活,通過指令我們

  • 可以隨心所欲地啟動(dòng)程序,
  • 可以根據(jù)自己的需要設(shè)置斷點(diǎn),
  • 可以查看斷點(diǎn)處的變量,代碼信息
  • 可以查看程序運(yùn)行的調(diào)用棧

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

一般情況下,使用 gdb 來調(diào)試 Android 源碼需要在 Android 設(shè)備上安裝 gbdserver attach 關(guān)聯(lián)我們需要調(diào)試的進(jìn)程,再使用 gdb 指令去連接 gdbserver 進(jìn)行調(diào)試

不過官方給我們提供了 gdbclient 工具,可以讓我們方便地進(jìn)行 gdb 調(diào)試。

開始 GDB 調(diào)試

這里我們就基于 gdbclient 來進(jìn)行實(shí)際的 gdb 調(diào)試演示:

跟上面 Java 調(diào)試一樣,我們這里還是以系統(tǒng)自帶的瀏覽器為例。

1. 點(diǎn)擊啟動(dòng)圖標(biāo)打開瀏覽器 app:

Paste_Image.png

2. 打開一個(gè)命令行終端,cd 進(jìn)入到系統(tǒng)源碼目錄(我的源碼路徑為 aosp),初始化命令工具:

#進(jìn)入源碼路徑
cd aosp
#初始化命令工具
source build/envsetup.sh
#選擇編譯的源碼的版本,參考上一篇文章
lunch
初始化命令工具
Paste_Image.png

3. 通過 adb 指令來查找要調(diào)試進(jìn)程的 PID

# 通過 shell ps 指令查找相關(guān)進(jìn)程,grep 搜索過濾 webview 進(jìn)程
adb shell ps -A | grep webview
Paste_Image.png

如圖,2157 為系統(tǒng)自帶瀏覽器 app 所在進(jìn)程的 PID

4. 使用 gdbclient <app pid> 命令工具啟用 gdb 調(diào)試 PID 對(duì)應(yīng)進(jìn)程

# gdbclient <app pid> 可以啟用 gdb 調(diào)試對(duì)應(yīng) PID 進(jìn)程
gdbclient 2157
Paste_Image.png

等待進(jìn)入 gdb 調(diào)試命令界面

Paste_Image.png

5. 使用 GDB b 命令打斷點(diǎn)

在 gdb 指令中,我們使用b <代碼文件>:行號(hào) 來設(shè)置斷點(diǎn).

這里我們選擇 frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp 代碼文件的 drawFrame 方法打上斷點(diǎn),位于文件 71 行:

Paste_Image.png

該方法主要用于繪制幀,當(dāng)瀏覽器 app 的界面發(fā)生變化時(shí)會(huì)觸發(fā)該方法。

我們輸入設(shè)置斷點(diǎn)命令:

b frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp:71
Paste_Image.png

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

6. 在命令行輸入c 開始監(jiān)聽

Paste_Image.png

c 即 continue,此時(shí)界面上出現(xiàn) Continuing 說明開始監(jiān)聽進(jìn)程了

我們點(diǎn)開模擬器,隨意操作,觸發(fā)界面變化時(shí),便會(huì)進(jìn)入繪制幀的代碼斷點(diǎn)了:

Paste_Image.png

如圖,顯示進(jìn)入斷點(diǎn),這樣代表我們的代碼調(diào)試成功了。


這里我們只是演示了一個(gè)大概流程,

gdb 代碼的調(diào)試需要你對(duì)源碼有一定的熟悉,知道哪個(gè)進(jìn)程會(huì)調(diào)用哪個(gè)文件方法。

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

GDB十分鐘教程

這里補(bǔ)充一點(diǎn),如果你希望在某個(gè)進(jìn)程啟動(dòng)時(shí)就監(jiān)聽,可以使用下面的指令關(guān)聯(lián)目錄,得到 pid,再通過 gdbclient 來進(jìn)行調(diào)試

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

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

如何調(diào)試Android Native Framework

用Android Studio調(diào)試Framework層代碼


結(jié)語

正如文章開頭所說,只有學(xué)會(huì)了如何調(diào)試 Framework 源碼,才能幫助我們更好地學(xué)習(xí) Android Framework,希望這篇文章能給大家一些幫助,如果有更好地調(diào)試方法,歡迎大家給我留言咯!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容