As an Android developer, YOU must be very familiar with APK (AndroidPackage). If you click build in Gradle or run gradlew tasks on the command line, AndroidStudio will start the build process and output the APK file. I do this a lot and I’m used to it, but sometimes I wonder how that string of code became APK and what the process was.

Overview of the build process

Let’s start with a build flow chart from the official website

The typical Android application module building process usually follows the following steps: 1. The compiler converts your source code into a DEX (Dalvik Executable) file (which includes bytecode running on your Android device) and everything else into compiled resources. 2.APK packer combines DEX files and compiled resources into a single APK. However, an APK must be signed before the application can be installed and deployed to an Android device. 3. The APK wrapper signs your APK: A using the debug or publish keystore. If you are building a debug version of your application (that is, an application dedicated to testing and analysis), the packer signs your application using the debug keystore. Android Studio automatically configures new projects using the debug keystore. B. If you are building a release application that you intend to distribute, the wrapper signs your application using the release keystore. To create a publishing keystore, read Signing your application in Android Studio. 4. Before the final APK is generated, the packer optimizes the application using the Zipalign tool to reduce the amount of memory it takes up when running on the device.Copy the code

The flow chart given on the official website is still quite abstract, many details are hidden, the following is a very classic Apk packaging flow chart released by Google. The following is a brief analysis of the process based on the figure below.

1. Package resource files

Resource files (files in the RES folder) are generated by Packaging Android Asset Packaging Tool (AAPT)R.javaClass (resource index table) and.arscResource files.

The R file generated by aapt is 4 bytes long

public static final int design_appbar_state_list_animator=0x7f020000;

  • First byte0x7fRepresents the packageID, which defines the source of the resource. The system resource bundle is ox01, the SharedLibrary-type resource bundle is 0x00, and the normal App package is 0x7f.
  • Subbyte02Denotes typeID, used to represent resource types such as drawable, layouts, Anims, color, menu, etc.
  • After 2 bytes0000Represents EvtryID, which refers to the order in which each resource appears in the corresponding TypID.

The.arsc resource file generated by AAPT corresponds to the Resources. Arsc obtained by unpacking APK (apK is essentially a zip package), which is actually the resource index table of App. In simple terms, the memory address of a resource can be located through the r.java file and resources.arsc. If you are interested, check out this blog post

Frameworks the entrance to the aapt compile source/base/tools/aapt/Main CPP, which to assert the folder path, the res folder path, the AndroidManifest file will take different strategies

Assets in the asset directory are not compiled. Assets in the Assets directory are entered into the APK intact. That is, assets are not compressed. Aapt compresses drawable resources under RES (except in raw directories)

Aapt text XML Resource file compiled into the binary Resource file method buildResources function in the frameworks/base/tools/aapt/Resource. The CPP can be found, focused on the overlay characteristics under here.

Overlay is a way of dealing with compile-time replacement resources in Android. If the values/string. XML under res1 and res2 have the same string ID, the value /string. XML under res1 and res2 have the same string ID. In the end, only the previous (RES1) description will be used. So the overlay is going to take the path that you define first as the base package.

In one case, if we defined a resource Sting a under res2, but the base pack didn’t define it, we would get an error. In this case, we would need to add an auto-add-overlay to add all the new resources.

Here’s how to buildResources in aapt source code

status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuilder>& builder)
{
    // First, look for a package file to parse.  This is required to
    // be able to generate the resource information.
    sp<AaptGroup> androidManifestFile =
            assets->getFiles().valueFor(String8("AndroidManifest.xml"));
    if (androidManifestFile == NULL) {
        fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n");
        return UNKNOWN_ERROR;
    }
    status_t err = parsePackage(bundle, assets, androidManifestFile);
    if(err ! = NO_ERROR) {returnerr; }... // apply the overlay files to the baseset
    if(! applyFileOverlay(bundle, assets, &drawables,"drawable") | |! applyFileOverlay(bundle, assets, &layouts,"layout") | |! applyFileOverlay(bundle, assets, &anims,"anim") | |! applyFileOverlay(bundle, assets, &animators,"animator") | |! applyFileOverlay(bundle, assets, &interpolators,"interpolator") | |! applyFileOverlay(bundle, assets, &transitions,"transition") | |! applyFileOverlay(bundle, assets, &xmls,"xml") | |! applyFileOverlay(bundle, assets, &raws,"raw") | |! applyFileOverlay(bundle, assets, &colors,"color") | |! applyFileOverlay(bundle, assets, &menus,"menu") | |! applyFileOverlay(bundle, assets, &fonts,"font") | |! applyFileOverlay(bundle, assets, &mipmaps,"mipmap")) {
        returnUNKNOWN_ERROR; }... //preProcess & makeFileResources ... // compile resources // Finally, we can now we can compile XML files }Copy the code

In Gradle aAPT can be configured using aaptOptions DSL, and in Android.mk there are LOCAL_AAPT_FLAGS configuration items

Here is just a simple description of the aapt process, the specific details are quite many, from XML parsing to the specific type of compilation process, to the binary Manifest generation and other details are not expanded, due to my limited c++ ability, a lot of things did not understand, it is not wrong.

2. Process aiDL files

If there are AIDL files, they will be packaged into Java interface classes using the AIDL tool (source code in System/Tools/AIDL)

Android Interface Definition Language (AIDL) is the Android Interface Definition Language. The purpose is to facilitate inter-process communication, especially when multi-process concurrency is involved. Gityuan’s Binder communication series provides a thorough understanding of the Android Binder communication architecture

3. Compilers

R.java+ project source +aidl. Java through javac generation. Class file.

The Javac compilation process can be roughly divided into three phases

  • The process of parsing and populating symbol tables

    The steps of parsing include lexical analysis and grammatical analysis

    Lexical analysis is the conversion of the string flow of source code into a collection of tokens, individual characters being the smallest element of the programming process, and tokens being the smallest element of the compilation process. Keywords, variable names, operators, and so on can all be tags

    Parsing is the process of constructing an abstract syntax tree based on Token sequences, which is a tree representation used to describe the syntax structure of program code. Each node of the syntax tree represents a syntax structure in the program, such as packages, types, modifiers, interfaces, etc

  • Annotation processing by the plug-in annotation processor

    Plug-in annotation processor that can read, modify, and add any element in the abstract syntax tree. APT (Annotation Processing Tool) in Android works in this phase.

  • Semantic analysis and bytecode generation process

    After parsing, the compiler gets an abstract syntax tree representation of the program code. The syntax tree can represent a well-structured abstraction of the source program, but there is no guarantee that the source program is logical. Semantic analysis is mainly to examine the context-related properties of the correct structure. Semantic analysis typically goes through annotation checking, data and control flow analysis, and decoding before moving on to the final stage of JavAC compilation: bytecode generation. The general process is as follows:

    Annotation inspection -> Data and Control Flow Analysis -> Decoding sugar -> bytecode generation

Javac compile action entrance is com. Sun. View Javac. Main. JavaCompiler class, mainly logic centralization in the compile () and compile2 () method, interested can go and see

4. Dex (Generate dex files)

Source.class files and third-party jars or libraries are packaged into dex files using the DX tool.

The.class files generated above are ready to run in the JVM, but there is a special processing required to run in the Android runtime: the DX processing, which translates, reconstructs, interprets, compresses, and so on.

The most we know about the operation of DEX may be Tinker’s hot repair scheme. Tinker’s basic idea is to use the principle of parental delegation to put the relevant dex of patch in the front of the array to ensure that classloader finds and loads the patch first. Understanding the dex file format is essential if you want to learn more about details, such as how to keep resource ids unchanged and how resource Diff works. As for the file format of DEX, there is a detailed introduction on the official website, which will not be explained here.

AndroidStudio provides proguard, D8, R8 and other tools to handle this process. Android also optimizes dex for Dalvik virtual machines and Art virtual machines

  • Dexopt is an operation to verify and optimize the DEX file. The optimization result of the dex file becomes the Odex file, which is similar to the DEX file but uses some optimization opcodes (such as optimization call virtual instructions).

  • Dex2oat is an AOT-ahead compilation of a dex file that requires a dex file and then compiles it, resulting in a locally executable ELF file that can be executed directly by the local processor.

5. Apkbuilder (Generate unsigned APK)

The ApkBuilder tool packages all uncompiled resources,.arSC resources, and.dex files into a completed APK file

6. Jarsigner (Signature)

The Jarsigner tool verifies the signature of an unsigned APK. Get a signed apK (signed.apk)

Details can be obtained by typing Jarsigner on the command line. If there are no special requirements, use the following command to complete the signing

Jarsigner -verbose -keystore [private keystore path] -signedjar [signed file store path] [unsigned file path] [your certificate name]

7. Zipalign

The zipAlign tool aligns signed. Apk in 6

The main process of alignment is to offset all resource files in the APK package to an integer multiple of 4 bytes from the start of the file, so that APK files can be accessed faster through memory mapping. The main purpose of alignment is to reduce runtime memory usage.

Tool list

The name of the Function is introduced The path
aapt Android resource packaging tool ${ANDROID_SDK_HOME}/platform-tools/appt
aidl Android API tool for converting. Java files ${ANDROID_SDK_HOME}/platform-tools/aidl
javac Java Compiler ${JDK_HOME}/javac
dex Convert the. Class file to a. Dex file recognized by the Davik VM ${ANDROID_SDK_HOME}/platform-tools/dx
apkbuilder Generated apk package ${ANDROID_SDK_HOME}/tools/opkbuilder
jarsigner Jar file signing tool ${JDK_HOME}/jarsigner
zipalign Bytecode alignment tool ${ANDROID_SDK_HOME}/tools/zipalign