framework開發實戰技巧

語言: CN / TW / HK

編譯命令詳解

編譯命令詳解.png

  • make/mma/mmma編譯時會把所有的依賴模塊一同編譯,mmm/mm不會;

  • 通常,首次編譯時採用make/mma/mmma編譯;

  • 當依賴模塊已經編譯過的情況,則使用mmm/mm編譯。

示例:mmm frameworks/opt/net/wifi/service,編譯wifi-service模塊,等同於make wifi-service

單編模塊

編譯模塊詳解.png

單編鏡像

shell make bootimage -jN make userdataimage -jN make systemimage -jN make vendorimage -jN

確認模塊名稱

如何知道我修改了某個文件之後要編譯哪個模塊呢?根據當前文件所在的模塊,具體模塊名到Android.mkAndroid.bp文件中查看,例如修改了這個文件frameworks/opt/telephony/src/java/com/android/internal/telephony/CarrierInfoManager.java,那麼對應找telephony模塊的Android.bp文件,內容如下:

```json filegroup { name: "opt-telephony-srcs", srcs: [ "src/java/android/telephony/*/.java", ], }

filegroup { name: "opt-telephony-htmls", srcs: [ "src/java/android/telephony/*/.html", ], }

filegroup { name: "opt-telephony-common-srcs", srcs: [ "src/java/*/.java", ], }

java_library { //模塊名,java_library表示是一個jar包,所以編譯會生成telephony-common.jar name: "telephony-common", installable: true,

aidl: {
    local_include_dirs: ["src/java"],
},
srcs: [
    ":opt-telephony-common-srcs",
    "src/java/**/I*.aidl",
    "src/java/**/*.logtags",
],

jarjar_rules: ":framework-jarjar-rules",

libs: [
    "android.hardware.radio-V1.0-java",
    "android.hardware.radio-V1.1-java",
    "android.hardware.radio-V1.2-java",
    "android.hardware.radio-V1.3-java",
    "android.hardware.radio-V1.4-java",
    "voip-common",
    "ims-common",
    "telephony-ext",
    "services",
],
static_libs: [
    "android.hardware.radio.config-V1.0-java-shallow",
    "android.hardware.radio.config-V1.1-java-shallow",
    "android.hardware.radio.config-V1.2-java-shallow",
    "android.hardware.radio.deprecated-V1.0-java-shallow",
    "telephony-protos",
    "ecc-protos-lite",
],

product_variables: {
    pdk: {
        // enable this build only when platform library is available
        enabled: false,
    },
},

} ```

關於Android.bp的語法這裏不做過多説明,可參考此篇文章《Android基礎|Android.bp語法淺析》,其中java_library即為模塊的名稱,所以,這裏需要編譯telephony-common,即make telephony-common

如果實在不知道編譯哪個模塊就整編!!!

常見的模塊

根據我個人的工作經驗,經常需要改動的目錄有兩個

  • /frameworks/

  • /packages/apps/

/packages/apps/存放的是系統app的源碼,比如SettingsLauncher等,修改後直接編譯對應的app的名稱即可,app名稱也是在對應的Android.mk裏面找LOCAL_PACKAGE_NAME的值,比如

makefile LOCAL_PACKAGE_NAME := Launcher3

此時可以直接make Launcher3,關於Android.mk的語法介紹,可以參考《Android基礎|Android.mk語法淺析》

/frameworks/則存放的是提供給上層調用的api,比如各種View,各種Service等,此目錄稍微複雜一點,具體分一下幾種情況:

  • 修改了/frameworks/opt/路徑下的文件

那麼直接編譯對應的子模塊就行,比如修改了/frameworks/opt/telephony/,那麼打開telephony下的Android.bp文件,找到java_library節點,下面的name屬性值就是要make的模塊名稱

  • 修改了/frameworks/base/services/路徑下的文件

打開services下的Android.bp文件,找到java_library節點,下面的name屬性值就是要make的模塊名稱,如果找不到java_library,則直接make services即可

  • 修改了/frameworks/base/下非services模塊文件

直接make frameworks即可,但是這個模塊名稱要區分Android 11之前和之後,之前叫 framework,之後叫 framework-minus-apex

  • 修改了/framework/目錄下的res文件

make framework-res

push路徑

編譯完成後如何push文件,文件push到什麼目錄中去,這個一般可以根據編譯生成的位置來決定對應的push路徑,比如:

shell make Settings -j16

得到結果

push路徑1.png

編譯得到Settings.apk,push路徑為/system/product/priv-app/Settings/,完整命令為

shell adb push out/target/product/trinket/system/product/priv-app/Settings/Settings.apk /system/product/priv-app/Settings/

但也有不是這樣的,比如

shell make wifi-service

得到結果

push路徑2.png

這裏並不是把wifi-events.rc push到對應的路徑,這個時候需要找出真正的編譯產物生成到哪兒了,根據wifi-service模塊的Android.mk文件描述,此模塊編譯生成wifi-service.jar,可以全局搜索wifi-service.jar的位置

shell find ./ -name wifi-service.jar

push路徑3.png

進入該目錄,查看一下wifi-service.jar的創建時間是否跟編譯時間一致

push路徑4.png

跟我們編譯的時間一致,説明這個jar包就是我們剛才編譯生成的,此時就可以將此jar包push到/system/framework/

shell adb push out/target/product/trinket/system/framework/wifi-service.jar /system/framework/

上面我們都是push具體文件,有時候編譯一個模塊會生成好多個文件,比如make framework這個時候可以將編譯路徑下的所有文件都push進去

shell adb push out/target/product/trinket/system/framework/* /system/framework/

注意,如果push路徑為私有目錄,則需要在root模式下操作,執行

shell adb root

進入root模式以後還要將文件系統重新掛載一次

shell adb remount

如果是新刷的系統,需要將verity驗證關閉才可以remount成功

push路徑5.png

執行

shell adb disable-verity

關閉verity之後需要重啟一下,執行

adb reboot

上述流程我一般會整理成一個簡單的shell腳本來一鍵執行

shell source build/envsetup.sh lunch trinket-userdebug make wifi-service -j16 adb root adb remount adb push out/target/product/trinket/system/framework/* /system/framework/ adb reboot