Android FrameWork 學習之Android 系統源碼調試


這是很久以前訪問掘金的時候 無意間看到的一個關於Android的文章,作者更細心,分階段的將學習步驟記錄在自己博客中,我覺得很有用,想作為分享同時也是留下自己知識的一些欠缺收藏起來,今后做項目的時候會用到。

好了,廢話不多說了。直接來吧。。

Android 7.0系統源碼下載\編譯:http://blog.csdn.net/cjpx00008/article/details/67185045(這個鏈接並不是下載地址,而是對安卓系統編碼的一個闡述,源碼官網可以下載的)

這是Android 7.0系統源碼下載\編譯

原文

最近計划着研究下Android 7.0的系統源碼,之前也沒做過什么記錄,這次正好將學習的內容記錄下來,方便以后復習鞏固。

既然要學習我們的系統源碼,那我們第一步要做的就是下載源碼並進行編譯了。

硬件環境要求

1. 編譯環境

按照官方的說法,編譯Android 2.3.x及以上版本的系統源碼需要64位的系統運行環境來支持,而編譯2.3.x以下的版本則需要32位的系統運行環境。

2. 硬盤空間

官方建議最好預留100G的磁盤空間來下載源碼,150G的磁盤空間用來編譯源碼,如果使用了ccache(一個高速編譯緩存工具,可以大幅加快gcc的編譯速度),那么則需要更大的空間來支持。

所以盡可能地保證自己的磁盤空間夠大吧,之前就因為磁盤空間預留不夠導致源碼編譯過程中空間不足,狠狠地把自己坑了一把。

3. 內存空間

如果你是在虛擬機上跑Linux,官方建議至少需要16G的內存空間,我的機器只有8G的內存空間跑虛擬機,目前跑起來也沒太大問題,就是編譯源碼的過程非常漫長,不知道是否跟內存大小有關。

軟件環境要求

1. 操作系統

Android系統的源碼的編譯支持Linux跟Mac OS兩種操作系統,一般情況下,Android系統源碼都是在Linux Ubuntu系統上進行開發與測試的,所以如果你准備使用Linux系統來進行源碼編譯,那一般推薦安裝Ubuntu版本的Linux。

下面列出了各Android版本與編譯系統版本的對應關系

Linux:

Android版本 GNU/Linux
Android 6.0 (Marshmallow) - Android最新版本 Ubuntu 14.04 (Trusty)
Android 2.3.x (Gingerbread) - Android 5.x (Lollipop) Ubuntu 12.04 (Precise)
Android 1.5 (Cupcake) - Android 2.2.x (Froyo) Ubuntu 10.04 (Lucid)

Mac OS

Android版本 Mac OS (Intel/x86)
Android 6.0 (Marshmallow) - Android最新版本 Mac OS v10.10 (Yosemite) or later with Xcode 4.5.2 and Command Line Tools
Android 5.x (Lollipop) Mac OS v10.8 (Mountain Lion) with Xcode 4.5.2 and Command Line Tools
Android 4.1.x-4.3.x (Jelly Bean) - Android 4.4.x (KitKat) Mac OS v10.6 (Snow Leopard) or Mac OS X v10.7 (Lion) and Xcode 4.2 (Apple’s Developer Tools)
Android 1.5 (Cupcake) - Android 4.0.x (Ice Cream Sandwich) Mac OS v10.5 (Leopard) or Mac OS X v10.6 (Snow Leopard) and the Mac OS X v10.5 SDK

2.JDK 版本要求

不同的Android版本編譯也需要對應的JDK環境,這里列出了各版本之間的對應關系

Android版本 JDK版本(Ubuntu) JDK版本(Mac OS)
Android目前最新版本 OpenJDK 8 jdk 8u45 or newer
Android 5.x (Lollipop) - Android 6.0 (Marshmallow) OpenJDK 7 jdk-7u71-macosx-x64.dmg
Android 2.3.x (Gingerbread) - Android 4.4.x (KitKat) Java JDK 6 Java JDK 6
Android 1.5 (Cupcake) - Android 2.2.x (Froyo) Java JDK 5  

搭建編譯環境

據上面列出的軟硬件要求,我們可以根據自己要編譯的Android版本以及自己的設備來選擇合適的系統及JDK,接下來我們就來說說如何搭建編譯環境。

這里我們主要針對Android 7.0的需要的編譯環境分別對Linux和Mac OS進行配置:

設置Linux系統編譯環境

1.安裝JDK

Android 7.0目前需要openJDK 8的JDK環境

Ubuntu 15.04+

如果你的系統是Ubuntu 15.04及以上版本的話,直接運行如下指令即可直接安裝:

 

Ubuntu 14.04

如果你使用的是Ubuntu 14.04版本,現在並沒有專門針對14.0.4可用的open jdk8的包,

但是Ubuntu 15.04 OpenJDK 8的包可以在14.0.4上成功地運行,所以我們下載Ubuntu 15.04 OpenJDK 8的安裝包來手動安裝:

  1. 從 archive.ubuntu.com上依次下載下面列出的64位的open JDK 8 的.deb安裝包 
    openjdk-8-jre-headless_8u45-b14-1_amd64.deb 
    openjdk-8-jre_8u45-b14-1_amd64.deb 
    openjdk-8-jdk_8u45-b14-1_amd64.deb

  2. 安裝.deb包 
    先運行apt-get指令更新軟件列表

      sudo apt-get update

      接着依次對上面下載的三個deb文件運行如下指令進行安裝:

 

      sudo dpkg -i 下載的文件地址

     最后運行 apt-get -f 指令修復安裝依賴的包

 

      sudo apt-get -f install

 

  1. 更新系統默認使用的JDK版本 
    如果你的系統安裝了多個版本的JDK,可以通過下面的指令執行切換,會彈出可選的JDK版本,根據你的需要選擇對應的版本就可以了:

2.安裝所需要的工具包

Ubuntu 14.04

我們編譯過程中會用到下面的依賴包,執行如下指令統一安裝:

3.設置源碼編譯輸出路徑

默認情況下,編譯好的系統源碼會在源碼所在目錄的out文件夾下, 
如果你希望調整輸出目錄的路徑,可以執行下面的指令指定輸出目錄:

4.設置USB接口訪問設備

在linux下,默認情況是不允許普通用戶直接通過USB接口來訪問設備的.

推薦方法是以根用戶身份在 /etc/udev/rules.d/51-android.rules 路徑創建文件。

我們可以通過如下指令來實現(注意用你的系統username替換指令中的):

設置Mac OS系統編譯環境

Mac OS的文件系統默認情況下保留了大小寫實際上卻又不區分大小寫。 
目前的Git指令無法支持這樣的文件系統,會導致一些莫名其妙的錯誤,所以在Mac OS上編譯Android系統源碼,我們必須先創建一塊區分大小寫的磁盤鏡像。

創建一塊區分大小寫的磁盤鏡像

這里我們直接通過命令行來創建:

該指令會在系統根目錄下生成一個android.dmg或是android.dmg.sparseimage文件,一旦掛載,將被作為支持Android開發所需格式的驅動鏡像分區。

如果之后你需要更大的空間,你可以通過下面的指令進行空間調整:

你還可以在 ~/.bash_profile 文件中,添加幫助函數來掛載跟取消掛載:

之后我們就可以通過執行mountAndroid指令來執行掛載鏡像,通過umountAndroid指令來取消掛載。

安裝JDK

安裝工具依賴包

1. 安裝xcode命令行工具
$ xcode-select --install

對於老版本的Mac OS系統(10.8或者10.8之前的),我們需要到蘋果開發者站點進行下載安裝. 
如果你還沒有注冊成為蘋果開發者,你需要先注冊一個蘋果賬號來進行下載.

2. 到 macports.org 上下載對應Mac OS版本的macports(類似於Linux下的apt-get,用來幫助你安裝其他應用程序)

注意:確保 /opt/local/bin 在路徑 /usr/bin前,如果沒有,在 ~/.bash_profile 文件中進行添加

export PATH=/opt/local/bin:$PATH

注意:如果根目錄下沒有 .bash_profile 文件,那就手動創建一個

3. 通過macports安裝make, git以及GPG
$ POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg

如果使用的是Mac OS X v10.4版本的系統,還需要安裝bison:

$ POSIXLY_CORRECT=1 sudo port install bison

注意:如果是編譯Android 4.0.x及以下版本的系統,gmake 3.8.2版本存在一個bug,需要還原到gmake 3.8.1

優化編譯環境(可選)

設置ccache

我們可以自由選擇是否開啟ccache編譯工具。

ccache是一個高速編譯緩存工具,它通過將頭文件高速緩存到源文件之中而改進了構建性能,因而通過減少每一步編譯時添加頭文件所需要的時間而提高了C\C++的構建速度。

從編譯的全過程來看,不使用ccache的情況下,編譯過程中會多次解析相同的頭文件,浪費了處理器周期,更重要的是浪費了開發者的時間,因為他們要等待這一過程的完成。在一個團隊中,這一影響可能會更為明顯,因為團隊成員可能會反復編譯解析相同的頭文件。

所以,一般對於專門用來編譯系統的服務器或是大容量的生產環境,這個功能比較有用,它可以加速重新編譯的速度。

注意:如果你只是個人開發者,不是專門的編譯服務器,不需要進行增量構建的話,那么使用ccache可能會因為高速緩存缺失而降低你的構建速度。

開啟ccache

要開啟ccache,在源碼樹的根路徑下執行下面的指令:

緩存的大小一般設置為50G-100G

接着在 .bashrc (或者etc/profile)中添加下面的指令

export USE_CCACHE=1

默認情況下,緩存會存在home根目錄的~/.ccache中,但是如果你使用的是NFS或者其他的非本地文件系統,那么你同樣需要在.bashrc指定緩存目錄地址

在Mac OS的系統中,你需要將linux-x86替換成darwin-x86:

prebuilts/misc/darwin-x86/ccache/ccache -M 50G

當編譯的Android系統是4.0.x或者更老的版本,ccache的緩存路徑會有所不同

prebuilt/linux-x86/ccache/ccache -M 50G

這個設置會一直存儲在CCACHE_DIR中。

在Linux上,你可以通過以下指令開啟對ccache的監聽:

$ watch -n1 -d prebuilts/misc/linux-x86/ccache/ccache -s

下載源碼

編譯環境配置好之后,我們就可以開始下載我們的源碼了

安裝Repo

Repo是google用Python寫的一個腳本工具,Android使用git作為代碼管理工具,一個Android系統由N多個git庫構成,如果手動進行一個個下載,那簡直是一件非常痛苦的事,而repo就是用來對這些git庫進行維護管理跟下載的。

通過Repo工具,我們可以輕松地完成Android系統源碼的下載。

1.在系統home根路徑下創建bin目錄並且添加到path路徑中:

2.下載repo工具並設置其可執行

初始化Repo客戶端

1.創建一個空目錄用來存放我們的Android系統源碼,名字自己隨便定

2.初始化repo倉庫

從主干master下載源碼,目前最新版本

如果需要下載某個特定版本系統的分支,可以在上述命令后加-b 版本分支號,這里我指定Android 7.0的版本分支

 

 

具體的版本分支號可以到這個地址查看(需要翻牆): 
Android系統個版本分支號

3.同步源碼到本地

這時執行sync指令便可以自動下載源碼到本地了

使用國內鏡像下載源碼

由於國內網絡的問題,上述操作的源碼下載需要翻牆才能進行,速度會受到很大影響,幾十G的系統源碼可能需要花上上周的時間才能下完,

因此我們可以選擇國內的鏡像進行源碼下載:

清華大學的鏡像站 
參照頁面上的描述對上面的指令稍作調整便可以了,站點上寫得比較詳細,這里我們就不作贅述了。

根據網速的不同,一般一天之內能夠下載完畢。

對於下載下來的源碼,我們並不能直接刷到我們的目標設備上或者是使用模擬器運行,我們必須對源碼進行編譯生成對應的image二進制鏡像文件, 
當然你也可以直接從官網下載對應系統版本的鏡像文件:

里我們還是自己來編譯下源碼,熟悉下整個編譯過程。

源碼編譯

首先我們通過命令行進入到源碼目錄中,我這里目錄的名稱是aosp

 

cd aosp

清空輸出目錄

為了確保我們編譯生成的文件不受之前build構建的文件影響,我們在源碼目錄中執行下面的指令,該指令會清空out輸出目錄中的所有文件

$ make clobber

設置編譯環境

首先我們通過源碼build目錄中的 envsetup.sh 腳本文件初始化我們的編譯環境,執行

$ source build/envsetup.sh

$ . build/envsetup.sh

這兩個指令的效果是一樣的,會初始化一些有用的命令工具

我們后面執行的一些指令必須在初始化 envsetup之后才能執行

選擇編譯目標

接着我們通過 lunch 指令來選擇我們需要編譯的目標 
執行lunch指令

$ lunch

會彈出可選目標項:

所有的構建目標由BUILD-BUILDTYPE的形式組成: 
BUILD對應codename

這是官方提供的一份對照表:

這是官方提供的一份對照表:

Device Code name Build configuration
Pixel XL marlin aosp_marlin-userdebug
Pixel sailfish aosp_sailfish-userdebug
HiKey hikey hikey-userdebug
Nexus 6P angler aosp_angler-userdebug
Nexus 5X bullhead aosp_bullhead-userdebug
Nexus 6 shamu aosp_shamu-userdebug
Nexus Player fugu aosp_fugu-userdebug
Nexus 9 volantis (flounder) aosp_flounder-userdebug
Nexus 5 (GSM/LTE) hammerhead aosp_hammerhead-userdebug
Nexus 7 (Wi-Fi) razor (flo) aosp_flo-userdebug
Nexus 7 (Mobile) razorg (deb) aosp_deb-userdebug
Nexus 10 mantaray (manta) full_manta-userdebug
Nexus 4 occam (mako) full_mako-userdebug
Nexus 7 (Wi-Fi) nakasi (grouper) full_grouper-userdebug
Nexus 7 (Mobile) nakasig (tilapia) full_tilapia-userdebug
Galaxy Nexus (GSM/HSPA+) yakju (maguro) full_maguro-userdebug
Galaxy Nexus (Verizon) mysid (toro) aosp_toro-userdebug
Galaxy Nexus (Experimental) mysidspr (toroplus) aosp_toroplus-userdebug
Motorola Xoom (U.S. Wi-Fi) wingray full_wingray-userdebug
Nexus S soju (crespo) full_crespo-userdebug
Nexus S 4G sojus (crespo4g) full_crespo4g-userdebug

BUILD_TYPE 對照表:

構建類型 用途
user 有限的訪問權限,主要用於發布正式產品,沒有root跟調試權限
userdebug 跟user類型差不多,但是多了root跟debug調試權限
eng 擁有各種調試工具的開發版設置,擁有root跟debug權限

如果作為開發使用的話,那我們一般都是選 -eng

這里我自己是准備在模擬器上運行編譯的image鏡像,並且我電腦的cpu是intel x86的,所以我選擇了 6. aosp_x86-eng

我們可以根據自己的需要選擇對應的cpu類型。

注意:我們知道,Android官方的模擬器速度很慢, 
Intel特意提供了一個叫HAXM的虛擬硬件加速技術,全稱為:Intel Hardware Accelerated Execution Manager.

只要你的CPU是intel的產品並且支持VT(virtualization Technology)就可以使用HAXM技術將你的模擬器的速度提升至真機的水平。

目前Intel只提供了windows版和MAC版,Linux系統只有通過安裝KVM來達到這個效果。

安裝KVM

首先我們檢測下自己的cpu是否支持 hardware virtualization(硬件虛擬化)

egrep -c '(vmx|svm)' /proc/cpuinfo

輸出的值如果是大於0的,則表明你的cpu支持

如果你使用的是vmware虛擬機安裝的linux,注意要設置下虛擬機的cpu來支持硬件虛擬化,先關閉虛擬機,然后右鍵虛擬機=》設置,選中cpu,勾選虛擬化Intel VT項,這樣就能支持KVM了。

對於Ubuntu 10.0.4以上的版本,我們通過下面的指令安裝KVM即可

sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils

如果在安裝KVM的過程中有什么疑問的話,可以訪問下面這個網址查找方法:https://help.ubuntu.com/community/KVM/Installation

這樣,在編譯完目標intel cpu的鏡像文件后,我們運行模擬器就會自動進行加速了。

編譯源碼

好了,一切就緒,我們可以開始編譯我們的源碼了, 
我們在源碼路徑下通過 make -jN 指令來進行源碼編譯,這里的N一般建議設置為cpu核心線程數的1-2倍。

$ make -j4

一般情況下,我們等待源碼編譯完成就可以了,不過從Android 7.0 N開始,make指令默認會開啟Jack編譯工具鏈來進行Java代碼的編譯,這個過程中可能會出現一些問題。

什么是Jack編譯工具鏈(The Jack toolchain)?

我們知道,我們平時編譯Android代碼的時候會先將Java代碼編譯成.class文件,最終再轉換成.dex文件,如圖:

而Jack編譯工具鏈則跳過了編譯成.class文件這一過程,直接將Java代碼編譯成.dex文件

它的優勢:

  • 完全開放源碼 
    源碼均在AOSP中,合作伙伴可貢獻源碼

  • 加快編譯源碼 
    Jack 提供特殊的配置,減少編譯時間:pre-dexing, 增量編譯和Jack編譯服務器.

  • 支持代碼壓縮,混淆,重打包和multidex

  • 不在使用額外單獨的包,例如ProGuard。

如果想進一步了解Jack,可以訪問Compiling with Jack(需翻牆),這里就不作太多解釋了。

按照官方的說法Jack可以加快編譯速度

但實際編譯過程中,在我的設備上Jack會占用大量內存,並且拖慢編譯速度,還會報錯,而且官方文檔上寫的配置方式對Jack並不起作用。

Jack編譯過程中遇到的問題
編譯過程中報Out of memory error並中斷編譯

在執行make指令后,當第一次編譯Java代碼的時候,Jack會被啟用,這個時候經常會卡住,並且一段時間后報錯Out of memory error

按照官方的說法,Jack並行編譯的時候占用的資源太大導致內存溢出了

可以通過在 $HOME/.jack 文件中減小 SERVER_NB_COMPILE 的值來減小並行編譯數量, SERVER_NB_COMPILE 的值默認為4

但實際情況是Jack沒有在根路徑下生成 .jack 文件,並且手動創建設置 SERVER_NB_COMPILE 后重啟Jack服務也沒有效果。

經測試發現make編譯過程中當Jack第一次被啟用時會在home根路徑下生成.jack-server目錄

可以通過修改該目錄中config.properties文件里的 
.jack.server.max-service
值來設置並發線程數。

同時,你也可以設置增加Jack的內存容量來解決這個問題,指令如下

export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4096m"

然后進入到輸出路徑的bin目錄下:

cd /home/cjpx00008/aosp/out/host/linux-x86/bin

執行下面的指令重啟Jack服務

./jack-admin stop-server./jack-admin start-server

我改了service大小,同時增加了內存,后來編譯的過程中沒有發生其他問題。

有辦法關閉Jack編譯嗎?

既然Jack有問題,那我們可以關閉Jack編譯嗎?

目前來說我還沒有找到如何在Android 7.0編譯的時候關閉Jack,如果有知道的小伙伴歡迎留言告訴我哈,感激不盡!!

運行編譯出的image鏡像

經過漫長的等待,我們的源碼終於編譯結束了,是時候來運行編譯出的image鏡像了。

這時我們只要在源碼目錄下執行 emulator 指令即可運行模擬器

$ emulator

第一次啟動時間可能會有點長,耐心等待即可 

運行成功了,是不是有點小激動呢!

注意:如果你的命令行窗口關閉重開了,那emulator指令可能會提示找不到命令,我們可以在源碼根目錄環境下,通過envsetup.sh重新初始化命令,運行lunch指令選擇編譯目標,這個時候你再運行emulator就不會提示找不到指令了(每次關閉命令行窗口都需要重新運行如下指令才能執行emulator)

也可以通過配置環境變量來設置emulator指令,不過我沒有成功,哈哈

$ source build/envsetup.sh$ lunch$ emulator

好啦,到此,我們的源碼就編譯完畢啦,下一篇我們來聊聊如何使用Android Studio導入Android系統源碼,並通過AS進行Java源碼調試,以及使用GDB來調試系統Native C\C++源碼。

 

到了這里,就是一長篇文章告一段落了,之后對Java代碼調試,通過命令行實現。  (*打個星號)

開始...

我們知道,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
(這個位置我找了很久,沒找到)

引用 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

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

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 文件根據自己需要調整要加載的源碼。

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

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

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

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

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

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

 

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

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

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

 

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

開始調試源碼

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

確保 Android Studio 允許 ADB 調試

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

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

 

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

點擊 WebViewBrowser 打開 app

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

 

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

 

 


 

如圖所示我們可以看到,代碼成功進入了斷點,然后我們就可以隨心所欲地調試我們想要的調試的 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:

     

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

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

     

     

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

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

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

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

    # gdbclient <app pid> 可以啟用 gdb 調試對應 PID 進程 gdbclient 2157

    等待進入 gdb 調試命令界面

  5. 使用 GDB b 命令打斷點

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

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

     

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

    我們輸入設置斷點命令:

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

     

    輸入指令后顯示 
    
    Breakpoint 2 at 0x7f69e9892c11: file frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp, line 71. 說明我們的斷點設置成功了。
  6. 在命令行輸入c 開始監聽

     

     

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

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

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


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

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 gdbclient <app pid>

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

 

 兩篇文章先到這里結束,技術文章很多,但是真正使用起來又可以總結出新的結論和技術操作上的更新。

轉載出自:https://juejin.im/entry/5934cfd8fe88c20061ccc63e   謝謝提供!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM