移動安全-第四天 安卓編譯,打包原理

正常的編譯原理

按照google給出的編譯步驟如下:

   1> source build/envsetup.sh:加載命令

   2> lunch:選擇平臺編譯選項

   3> make:執行編譯

https://www.cnblogs.com/shakin/p/4615872.html

 

java編譯過程

Android的4種文件類型Java,class,dex,apk

Java文件-----應用程序源文件

Android本身相當一部分都是用java編寫而成(基本上架構圖裏頭藍色的部份都是用Java開發的),android的
應用必須使用java來開發
 

Class文件------Java編譯後的目標文件
不像J2se,java編譯成class就可以直接運行,android平臺上class文件不能直接在android上運行。 由於Google
使用了自己的Dalvik來運行應用, 所以這裏的class也肯定不能在AndroidDalvik的java環境中運行, android
的class文件實際上只是編譯過程中的中間目標文件,需要鏈接成dex文件後才能在dalvik上運行

 

Dex文件-----Android平臺上的可執行文件
Android虛擬機Dalvik支持的字節碼文件格式Google在新發布的Android平臺上使用了自己的Dalvik虛擬機
來定義, 這種虛擬機執行的並非Java字節碼, 而是另一種字節碼: dex格式的字節碼。在編譯Java代碼之後,
通過Android平臺上的工具可以將Java字節碼轉換成Dex字節碼。雖然Google稱Dalvik是爲了移動設備定
做的,但是業界很多人認爲這是爲了規避向sun申請Javalicense。這個DalvikVM針對手機程式/CPU做過最
佳化,可以同時執行許多VM而不會佔用太多Resource。


Apk文件-------Android上的安裝文件
Apk是Android安裝包的擴展名,一個Android安裝包包含了與某個Android應用程序相關的所有文件。apk
文件將AndroidManifest.xml文件、應用程序代碼(.dex文件)、資源文件和其他文件打成一個壓縮包。一個工
程只能打進一個.apk文件

來源: https://www.cnblogs.com/xgjblog/p/5809449.html

 

大概的意思是編譯成java字節碼之後可以在任何平臺使用

下面是一些區別

java執行的流程

而後使用java虛擬機運行

加載的時候關鍵的就是如何加載和獲取程序相關的文件等

加載之後需要進行執行的過程

將程序運行起來之後,就是數據的分佈

 

上文已經說過dex文件和class文件的各自作用,下面是二者的比對

生成的過程

dex結構分成三部分:
文件頭:表明了是dex文件,已經文件的大小等等數據
索引頭:如下圖所示
數據區:數據區,就像是jvm中的堆保存方法+變量。

https://www.jianshu.com/p/cfeb8dec53c3

// Raw header_item.
  struct Header {
    uint8_t magic_[8];
    uint32_t checksum_;  // See also location_checksum_
    uint8_t signature_[kSha1DigestSize];
    uint32_t file_size_;  // size of entire file
    uint32_t header_size_;  // offset to start of next section
    uint32_t endian_tag_;
    uint32_t link_size_;  // unused
    uint32_t link_off_;  // unused
    uint32_t map_off_;  // unused
    uint32_t string_ids_size_;  // number of StringIds
    uint32_t string_ids_off_;  // file offset of StringIds array
    uint32_t type_ids_size_;  // number of TypeIds, we don't support more than 65535
    uint32_t type_ids_off_;  // file offset of TypeIds array
    uint32_t proto_ids_size_;  // number of ProtoIds, we don't support more than 65535
    uint32_t proto_ids_off_;  // file offset of ProtoIds array
    uint32_t field_ids_size_;  // number of FieldIds
    uint32_t field_ids_off_;  // file offset of FieldIds array
    uint32_t method_ids_size_;  // number of MethodIds
    uint32_t method_ids_off_;  // file offset of MethodIds array
    uint32_t class_defs_size_;  // number of ClassDefs
    uint32_t class_defs_off_;  // file offset of ClassDef array
    uint32_t data_size_;  // unused
    uint32_t data_off_;  // unused
    ......
  }

file_size_: 整個文件的大小,單位字節
header_size_: 文件頭的大小,單位字節
string_ids_size_: 字符串列表中字符串的數量
string_ids_off_: 字符串列表在文件中的偏移
type_ids_size_: 類型列表中元素數量
type_ids_off_: 類型列表在文件中的偏移
proto_ids_size_: 方法原型列表元素數量
proto_ids_off_: 方法原型列表在文件中的偏移
field_ids_size_: 字段列表的元素數量
field_ids_off_: 字段列表在文件中的偏移
method_ids_size_: 方法列表元素的數量
method_ids_off_: 方法列表在文件中的偏移
class_defs_size_: 類定義列表中元素數量
class_defs_off_: 類定義列表在文件中的偏移
data_size_: data段的大小
data_off_: data段在文件中的偏移

鏈接:https://www.jianshu.com/p/7afbadd6099f  具體的介紹 很多的

一個真實的例子

 

apk打包過程

Android安裝包的後綴都是.apk, apk是Android Package的縮寫。 解壓apk文件後包含AndroidManifest.xml、assets目錄、classes.dex(還可能有 classes2.dex,classes3.dex...classesN.dex)、lib目錄、META-INF目錄、res目錄和resources.arsc。

    ndroidManifest.xml對應源代碼中的AndroidManifest.xml, 但這裏是編譯過的,文件內容已經不同了。

     assets對應源代碼的assets目錄, 是直接複製過來的。

     classes.dex是包含所有Java文件對應的字節碼。

     lib目錄對應源代碼中的libs目錄,包含so文件。

     META-INF目錄包含CERT.RSA、CERT.SF、MANIFEST.MF等, 保存了各個資源文件的SHA1值,用於校驗資源文件是否被篡改,從而防止二次打包時資源文件被替換。

     res目錄對應源碼的res目錄, 包含各種圖片、xml等。

     resources.arsc包含了各個資源文件的映射, 可以理解爲索引, 通過該文件能找到對應的資源文件信息。

(AAPT - Android Asset Packaging Tool AAPT是Android資源打包工具)資源打包的過程如下:

1.從圖中我們可以看出
(1)除了assets和res/raw資源被原裝不動地打包進APK之外,其它的資源都會被編譯或者處理「2」
(2)除了assets資源之外,其它的資源都會被賦予一個資源ID。包括res/raw也會有資源ID,即R.id.resourceId。
(3)打包工具負責編譯和打包資源,編譯完成之後,會生成一個resources.arsc文件和一個R.java,前者保存的是一個資源索引表,後者定義了各個資源ID常量。

這個在AS中我們編譯的時候也看到了

還是沒明白resources.arsc和R.java存在的意義?我們可以這樣想,一個項目由代碼和資源文件組成,代碼通過對資源的處理來展現業務流程,那我們代碼中肯定要獲取到某個所需要的資源吧?Android爲了方便管理,就定了一個文件,裏面定義了各個專屬資源ID常量,來表示我們項目中存在的資源。寫代碼的時候,我們要用某個資源,是不是都是類似這樣寫:
tvMrchNo = (TextView) findViewById(R.id.tv_mrch_no);

 

apk打包過程圖,其中包括資源打包 代碼的編譯等 資源打包的方法在上邊已經說過了這裏主要是看流程

從上圖中可以看到。完整的打包流程應該是:
(1)打包資源文件。
(2)處理aidl文件,生成相應java 文件。對於沒有使用到aidl的android工程,可以跳過此步驟。
(3)編譯工程源代碼,生成相應class 文件。
這一步調用了javac編譯工程src目錄下所有的java源文件,生成的class文件位於工程的bin\classes目錄下,上圖假定編譯工程源代碼時程序是基於android SDK開發的,實際開發過程中,也有可能會使用android NDK來編譯native代碼,因此,如果可能的話,這一步還需要使用android NDK編譯C/C++代碼,當然,編譯C/C++代碼的步驟也可以提前到第一步或第二步。通過Java Compiler編譯R.java、Java接口文件、Java源文件,生成.class文件。
(4)轉換所有class文件,生成classes.dex文件。Android虛擬機的可執行文件爲dex格式,所以需要此步驟。
(5)打包生成apk。打包後的res文件夾(除res/raw資源被原裝不動地打包進APK之外)、打包後類文件(.dex文件)、libs文件(包括.so文件,當然很多工程都沒有這樣的文件,如果你不使用C/C++開發的話)、resources.arsc、assets、AndroidManifest.xml打包成apk文件。
(6)對apk文件進行簽名。
(7)對簽名後的apk文件進行對其處理。在 Android SDK 中包含一個名爲 “zipalign” 的工具,它能夠對打包後的 app 進行優化。 即對簽名後的apk進行對齊處理。

 

另外一種圖示結構,這裏主要爲了說明的是源碼的編譯流程

 

源碼進行javac編程class文件 然後編譯爲dex文件,然後進行一系列處理,簽名 優化等 最後生成可以打包apk文件

 

 

除了上述標註的,還有以下參考文章

https://www.jianshu.com/p/d29c37dda256

https://blog.csdn.net/brycegao321/article/details/79127159 

https://www.jianshu.com/p/7afbadd6099f

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章