编译命令详解
-
make/mma/mmma
编译时会把所有的依赖模块一同编译,mmm/mm
不会; -
通常,首次编译时采用
make/mma/mmma
编译; -
当依赖模块已经编译过的情况,则使用mmm/mm编译。
示例:
mmm frameworks/opt/net/wifi/service
,编译wifi-service
模块,等同于make wifi-service
单编模块
单编镜像
make bootimage -jN
make userdataimage -jN
make systemimage -jN
make vendorimage -jN
确认模块名称
如何知道我修改了某个文件之后要编译哪个模块呢?根据当前文件所在的模块,具体模块名到Android.mk
或Android.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的源码,比如Settings
、Launcher
等,修改后直接编译对应的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
得到结果
编译得到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
得到结果
这里并不是把wifi-events.rc
push到对应的路径,这个时候需要找出真正的编译产物生成到哪儿了,根据wifi-service
模块的Android.mk
文件描述,此模块编译生成wifi-service.jar
,可以全局搜索wifi-service.jar
的位置
find ./ -name wifi-service.jar
进入该目录,查看一下wifi-service.jar
的创建时间是否跟编译时间一致
跟我们编译的时间一致,说明这个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成功
执行
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