framework开发实战技巧

2,969 阅读4分钟

编译命令详解

编译命令详解.png

  • make/mma/mmma编译时会把所有的依赖模块一同编译,mmm/mm不会;

  • 通常,首次编译时采用make/mma/mmma编译;

  • 当依赖模块已经编译过的情况,则使用mmm/mm编译。

    示例:mmm frameworks/opt/net/wifi/service,编译wifi-service模块,等同于make wifi-service

单编模块

编译模块详解.png

单编镜像
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文件,内容如下:

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的值,比如

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路径,比如:

make Settings -j16

得到结果

push路径1.png

编译得到Settings.apk,push路径为/system/product/priv-app/Settings/,完整命令为

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

但也有不是这样的,比如

make wifi-service

得到结果

push路径2.png

这里并不是把wifi-events.rc push到对应的路径,这个时候需要找出真正的编译产物生成到哪儿了,根据wifi-service模块的Android.mk文件描述,此模块编译生成wifi-service.jar,可以全局搜索wifi-service.jar的位置

find ./ -name wifi-service.jar

push路径3.png

进入该目录,查看一下wifi-service.jar的创建时间是否跟编译时间一致

push路径4.png

跟我们编译的时间一致,说明这个jar包就是我们刚才编译生成的,此时就可以将此jar包push到/system/framework/

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

上面我们都是push具体文件,有时候编译一个模块会生成好多个文件,比如make framework这个时候可以将编译路径下的所有文件都push进去

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

注意,如果push路径为私有目录,则需要在root模式下操作,执行

adb root

进入root模式以后还要将文件系统重新挂载一次

adb remount

如果是新刷的系统,需要将verity验证关闭才可以remount成功

push路径5.png

执行

adb disable-verity

关闭verity之后需要重启一下,执行

adb reboot

上述流程我一般会整理成一个简单的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