1、m:编译整个安卓系统
makes from the top of the tree
2、mm:编译当前目录下的模块,当前目录下需要有Android.mk这个makefile文件,否则就往上找最近的Android.mk文件。
builds all of the moudles in the current directory
mma:当前目录新增或删除文件后,可以用mma重新编译。
3、mmm:编译指定路径下的模块,指定的路径下面需要有Android.mk这个makefile文件
builds all of the moudles in the supplies directory
mmma:指定目录下新增或删除文件后,可以用mmma重新编译。
mmm命令 的编译过程:
build/core/main.mk(是Android编译系统的入口文件)
->build/core/config.mk(会定好编译类型和目标文件)
->build/core/definitions.mk(定义在编译过程中用到的宏)
->ONE_SHOT_MAKEFILE->build/core/package.mk(编译Apk库文件)
->build/core/java_library.mk(编译Java库文件)
->build/core/static_java_library.mk(编译Java静态库文件)
->build/core/shared_library.mk->build/core/dynamic_library.mk->build/core/binary.mk->build/core/base_rules.mk
( 计算一些基本变量的值,并创建一些基本的依赖规则)
->build/core/static_library.mk(编译.a静态库文件)
->build/core/executable.mk(编译可执行文件)
->build/core/prebuilt.mk(编译已经预编译好的第三方库文件)
->build/core/Makfile(有system.img、boot.img、recovery.img等镜像文件生成规则)
环境变量ONE_SHOT_MAKEFILE中存放要编译模块的Android.mk的文件路径,如果环境变量值为空,表示执行的是m或者make命令,会对Android源代码中的所有模块进行编译。
mm、mmm是类似的,都是用来编译某些模块。
在修改部分代码的时候,只需要替换一部分差异代码块时,需要进行模块编译
(1)先找到最近是Android.mk,阅读相关内容,判断,该模块编译生成的是否是动态库。(Java库与C库不同,C库中静态库为.a文件,动态库为.so文件,Java的动态库为jar包)
关于apk安装相关的代码在frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 文件中,对该文件进行修改后,寻找Android.mk进行编译。
(2)在离文件最近的Android.mk在frameworks/base/services/core目录中,其中内容如下:
LOCAL_MODULE := services.core //表示这个模块编译后的名称将会是services.core
include $(BUILD_STATIC_JAVA_LIBRARY) //表示模块将编译成静态库
- 静态库就是直接将需要的代码连接进可执行程序;动态库就是在需要调用其中的函数时,根据函数映射表找到该函数然后调入堆栈执行。
所以静态库将会被引用,相对而言,动态库就能达到将修改部分移动至系统中的效果。
(3)接下来,一般情况,将搜寻的范围扩大,向上级目录寻找,能把修改部分的代码编译成动态库的Android.mk
以搜寻静态库名称services.core 为主。但是有一些模块在引用时会出现一些语法,将静态库名称进行拼接,这时以静态库名称查找将会很吃力。
在搜静态库名称之前,先查看上一级目录是Android.mk是否有对应的语法。
在修改PackageManagerService.java时,就是这个情况。
在这里它将所有需要的静态库模块进行了拼接。
(4)最后它将引用include $(BUILD_JAVA_LIBRARY) 来编译出Java模块的名称为“services.jar”。最后只需要将编译出的模块拷贝到系统对应的目录即可。
这需要注意,这里编译的内容并不在services.jar中,而是在oat目录中。
许多Android的ROM包在生成过程中都启用优化,把jar文件抽空,生成odex/oat和vdex文件,以在运行时省掉编译时间。