If you want to do it well, you must first sharpen your tools. If you want to learn Android source code in depth, you must first master the Android compilation commands.
1. Introduction
Regarding the Android Build system, I have planned to sort out this topic very early, but I haven't started writing it for a long time, so I decided to share it with you. Let’s look at the following instructions first. I believe that those who have compiled Android source code are very familiar with it.
source /opt/android1204_17.conf source lunch make -j12
I remember when I first came into contact with Android, my colleague told me that I could compile the Android source code using the above instructions. Although the instructions were short, I couldn't remember them completely or forgot the order in a few days. Every time I compiled, I also needed to check my own cloud notes. The cold instructions were always difficult for me to remember. Later I decided to carefully study the meaning of this instruction. To know the truth, you still need to know the reason. In this way, you can understand and remember it more deeply, so that you can establish a strong connection with your own knowledge system, and perhaps you can gain unexpected results. As expected, let me share with you the Android Build (compilation) system that you have learned in-depth in the process of studying the meaning of the above instructions.
2. Compile commands
After you prepare the compilation environment, the first step in compiling Android source code is source build/, where the source command is used to run shell script commands, and the function is equivalent to ".", so the command is also equivalent to . build/. The file declares the commands available to the current session terminal. It should be noted here that the current session terminal means that these instructions must be executed again every time a new terminal is opened. At first I didn't understand why the newly opened terminal could not directly execute the make command, but I finally understood it here.
Next, let’s explain the cited commands at the beginning of this article:
source /opt/android1204_17.conf //Initialize jdk environment variable (this is not required, it varies from manufacturer to manufacturer)
source //Initialize the compilation environment, including the subsequent lunch and make instructions
lunch //Specify the target device and compile type for this compilation
make -j12 //Start compilation, default to compiling the entire system, where -j12 represents the number of compiled jobs is 12.
All the compilation commands can find the corresponding function in the file, such as the above commands lunch and make, which can be found in the file.
function lunch(){ ... } function make(){ ... }
The specific implementation will not be explained here. The following is a detailed summary of the usage and functions of each instruction.
2.1 Code Compilation
Compile command explanation
m Execute compilation in the root directory of the source tree
mm Compile all modules in the current path, but do not include dependencies
mmmm [module_path] Compile all modules under the specified path, but do not include dependencies
mma compiles all modules in the current path and includes dependencies
mmma [module_path] Compile all modules under the specified path and include dependencies
make [module_name] No parameters means compiling the entire Android code
The following lists the compilation instructions for some modules:
Module make command mmm command
init make init mmm system/core/init
zygote make app_process mmm frameworks/base/cmds/app_process
system_server make services mmm frameworks/base/services
java framework make framework mmm frameworks/base
framework resources make framework-res mmmm frameworks/base/core/res
jni framework make libandroid_runtime mmm frameworks/base/core/jni
binder make libbinder mmm frameworks/native/libs/binder
The above mm command is also applicable to mm/mma/mmma. The compilation system uses incremental compilation and will only compile the changing target files. When you need to recompile all relevant modules, you need to add parameter -B after compiling the command, such as make -B [module_name], or mm -B [module_path].
Tips:
The implementation of commands such as m, mm, mm, mmma, and mmma is done through make.
mmmm/mm compilation efficiency is very high, while make/mma/mmma compilation is slow;
When making/mma/mmma is compiled, all dependency modules will be compiled together, but mmmm/mm will not;
Recommendation: Use make/mma/mmma to compile for the first time; when the dependency module has been compiled, use mmm/mm to compile.
2.2 Code Search
Search instructions Explanation
cgrep All C/C++ files perform search operations
jgrep All Java files perform search operations
ggrep All Gradle files perform search operations
mangrep [keyword] All files perform search operations
sepgrep [keyword] All sepolicy files perform search operations
resgrep [keyword] All local res/*.xml files perform search operations
sgrep [keyword] All resource files perform search operations
The final implementation method of the above instructions is based on grep instructions, and the usage formats of each instruction:
xgrep [keyword] //x represents the search command in the above table
For example, search for the specific location of the file where the launcher keyword is located in all files, and directive
mangrep launcher
For example, search for selinux permission information of all system_app
sepgrep system_app
Tips: Android source code is very large. Directly using grep to search code, not only is the method clumsy and a waste of time, but also searches for many meaningless obfuscation results. Selecting the appropriate code search instructions according to specific needs can save code search time, improve the accuracy of search results, and facilitate target code positioning.
2.3 Navigation commands
Navigation command explanation
croot switch to Android root directory
cproj switch to the root directory of the project
godir [filename] Jump to the directory containing a file
Tips: When you need to compile after modifying a file, after executing cproj, it will jump to the root directory of the current module, that is, the directory where the file is located, and then execute the mm instruction to compile the target module; when entering the source code level is very deep, you need to return to the root directory and use a croot instruction to complete it; in addition, the cd- instruction can be used to quickly switch to the last directory.
2.4 Information query
Query command explanation
hmm query all command help information
findmakefile query the file path of the project where the current directory is located
print_lunch_menu Query the optional product of lunch
printconfig query the values of various compiled variables
gettop query the root directory of Android source code
gettargetarch Get TARGET_ARCH value
Tips: When you forget all the previous instructions, you can execute an hmm to output the help information of these instructions.
Other instructions:
make clean: performs a clean operation, equivalent to rm -rf out/
make update-api: update the API. After the framework API is changed, the command must be executed. The API is recorded in the directory frameworks/base/api;
3. Compilation system
The Android compilation system is part of the Android source code and is used to compile the Android system, the Android SDK and related documents. The compilation system is composed of Make files, Shell and Python scripts, the most important of which is the Make file. For the compilation system, please refer to Understand the Android Build system.
3.1 Makefile classification
The Make files of the entire Build system are divided into three categories:
The system core Make file: defines the framework of the Build system, all files are located in the path /build/core, and other Make files are written based on this framework;
Make files for products: define the Make files for a specific model of mobile phone, and the file path is located in /device. In this directory, two sub-directories are often divided into company names and product names, such as /device/qcom/msm8916;
Make file for modules: The entire system is divided into individual modules, each module has a special Make file with the name "", which defines the compilation method of the current module. The Build system will scan the entire source tree for a problem named "" and perform the compilation of the corresponding module.
3.2 Compile products
The products compiled by make are all located in the /out directory. This directory mainly focuses on the following directories:
/out/host: The product of Android development tools, including various SDK tools, such as adb, dex2oat, aapt, etc.
/out/target/common: Some common compilation products, including Java application code and Java libraries;
/out/target/product/[product_name]: Compilation products for specific devices and platform-related C/C++ code and binary files;
In the /out/target/product/[product_name] directory, there are several heavyweight image files:
: Mounting is the root partition, mainly containing system files for Android OS;
: Mainly including files and configuration files;
: is mounted in /data, mainly containing data related to users and applications;
Of course, there are also images that will not be introduced here.
3.3 Analysis
All files of each module in the source tree usually have their own folder accordingly, and there is a name "" in the root directory of the module.
file. The compilation system is compiled in modules. Each module has a unique module name. A module can depend on multiple other modules. The dependencies between modules are referenced through the module name. That is to say, when a module needs to rely on a jar package or apk, the jar package or apk must be defined as a module first, and then rely on the corresponding module.
For files, the following two lines are usually
LOCAL_PATH := $(call my-dir) //Set when the compilation path is the path where the current folder is locatedinclude $(CLEAR_VARS) //Clear the variables in the compilation environment (variables set by other modules)
To facilitate module compilation, the compilation system has set up many compilation environment variables, as follows:
LOCAL_SRC_FILES: All source files contained in the current module;
LOCAL_MODULE: The name of the current module (with uniqueness);
LOCAL_PACKAGE_NAME: The name of the current APK application (with uniqueness);
LOCAL_C_INCLUDES: The header file path required for C/C++;
LOCAL_STATIC_LIBRARIES: The library name required by the current module when static linking;
LOCAL_SHARED_LIBRARIES: The dynamic library name that the current module depends on at runtime;
LOCAL_STATIC_JAVA_LIBRARIES: Java static library that the current module depends on;
LOCAL_JAVA_LIBRARIES: The Java shared library that the current module depends on;
LOCAL_CERTIFICATE: Sign the certificate name of the current application, such as flatform.
LOCAL_MODULE_TAGS: The tags contained in the current module can contain multiple tags, and the possible values are debgu, eng, user, development or optional (default value)
For these environment variables, the compilation system also defines some convenient functions, as follows:
$(call my-dir): Get the current folder path;
$(call all-java-files-under, <src>): Get all Java files in the specified directory;
$(call all-c-files-under, <src>): Get all C files in the specified directory;
$(call all-Iaidl-files-under, <src>): Get all AIDL files in the specified directory;
$(call all-makefiles-under, <folder>): Get all Make files in the specified directory;
Example:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Get Java files in all subdirectories LOCAL_SRC_FILES := $(call all-subdir-java-files) # The dynamic Java library name of the current module dependency LOCAL_JAVA_LIBRARIES := # The name of the current module LOCAL_MODULE := demo # Compile the current module into a static Java library include $(BUILD_STATIC_JAVA_LIBRARY)