1. 程式人生 > >Android原始碼中增加模組

Android原始碼中增加模組

Android build system就是編譯系統的意思 
在我們需要向自己編譯的原始碼中增加模組的時候,需要一些規則,當然這個規則都是類似的。 

Android.mk檔案解析 


讓我們來看一個 Android.mk 檔案的樣子 
Java程式碼
  1. LOCAL_PATH := $(call my-dir)

  2. include $(CLEAR_VARS)

  3. LOCAL_MODULE :=Hello

  4. LOCAL_SRC_FILES := hello.c

  5. include $(BUILD_SHARED_LIBRARY)
    複製程式碼
複製程式碼 ① LOCAL_PATH :=$(call my-dir) 
固定寫法, LOCAL_PATH 表示此時位於工程目錄的根目錄中, (call my-dir) 的功能由編譯器提供,被用來返回當前目錄的地址(包含 Android.mk 本身) 
② include $(CLEAR_VARS) 
固定寫法, CLEAR_VARS 這個變數由編譯系統提供,並且要執行一個 GNU makefile 檔案,這個功能會清理掉所有以 LOCAL_ 開頭的內容(比如 LOCAL_MODULE 、 LOCAL_SRC_FILES 等),除了 LOCAL_PATH 。這句話也是必須的,因為如果所有變數都是全域性變數的話,所有的可控的編譯檔案都需要在一個單獨的 GNU 中被解析並執行 
③ LOCAL_MODULE :=Hello 
LOCAL_MODLE 變數必須被定義,用來區分 Android.mk 中的每一個模組。檔名必須是唯一的,不能有空格。注意,編譯器會為你自動加上一些字首和字尾,來保證檔案是一致的。比如:這裡表明一個動態連結庫模組被命名為“ Hello ”,但是最後會生成“ libHello.so ”檔案。但是在 java 中裝載這個庫的時候還要使用“ Hello ”名稱。 
④ LOCAL_SRC_FILES :=hello.c 
LOCAL_SRC_FILES 變數必須包含一個 C 和 C++ 原始檔的列表,這些會被編譯並聚合到一個模組中 
注意:這裡並不需要列標頭檔案和被包含的檔案,因為編譯系統會自動為你計算相關的屬性,原始碼的列表會直接傳遞給編譯器 
⑤ include $(BUILD_SHARED_LIBRARY) 
BUILD_SHARED_LIBRARY 這個變數由系統提供,並且指定給 GNU makefile 的指令碼,它可以收集所有你定義的”include $(CLEAR_VARS)” 中以 LOCAL_ 開頭的變數,並且決定哪些要編譯,哪些應該做的更加準確。我們同樣可以使用 BUILD_STATIC_LIBRARY 來生成一個靜態庫,如果使用 BUILD_STATIC_LIBRARY 編譯系統便會生成一個以“ lib$(LOCAL_MODULE).a ”為檔名的檔案來提供動態庫的呼叫 
⑥ TARGET_ARCH 
TARGET_ARCH 是指架構中 CPU 的名字已經被 Android 開原始碼明確指出了,這裡的 arm 包含了任何 ARM-獨立結構的架構,以及每個獨立的 CPU 版本 
⑦ TARGET_PLATFORM 
Android 平臺的名字在 Android.mk 檔案中被解析,比如 ”android-2.3” 
⑧ TARGET_ROOT_OUT :表示根檔案系統 
用法: CAL_MODULE_PATH:=$(TARGET_ROOT_OUT) 
⑨ TARGET_OUT: 表示 system 檔案系統 
⑩ TARGET_OUT_DATA: 表示 data 檔案系統 
? TARGET_ABI 
TARGET_ABI 平臺目標板和 abi 的連結,這裡要定義 $(TARGET_PLATFORM)-$(TARGET_ARCH_ABI) ,它們都非常有用,特變是當你想測試一個具體的系統映象在幾個真實裝置的時候 
下面是 GNU 編譯出來的巨集,並且它們都必須使用“ $(call <function>) ”才能返回文字化的資訊。 
all-subdir-makefiles :返回一個 Android.mk 檔案所在位置的列表,以及當前 my-dir 的路徑。 
比如: include $(call all-subdir-makefiles) 
this-makefile :返回當前 makefile 的路徑(就是哪個功能被呼叫了) 
parent-makefile :返回 makefile 的包含樹,也就是包含 makefile 的當前檔案 
Application.mk
 


要講 C\C++ 編譯為 so 檔案,光有 Android.mk 檔案是不行的,還需要 Application.mk 檔案。 
Application.mk 檔案存放的位置是 NDK 工程的根目錄, Application.mk 檔案就是用來描述應用程式中所需要的原生的模組(也就是靜態庫和動態庫),每一個 Application.mk 檔案都必須放在應用目錄下的子目錄,例如$NDK/apps/HelloNdk/Application.mk ,作為 GNU makefile 的一部分, Application.mk 檔案必須要定義以下部分 
1、 APP_MODULES 
APP_MODULES 變數是強制性的,並且會列出所有你所需要的模組(通過 Android.mk ) 
2、 APP_PROJECT_PATH 
APP_PROJECT_PATH 變數也是強制性的,並且會給出應用程式工程的根目錄一個絕對路徑。這是用來複制或者安裝一個沒有任何版本限制的 JNI 庫,從而給 APK 生成工具一個詳細的路徑。 
例如: \HelloNDK\Application.mk 
APP_PROJECT_PATH := $(call my-dir)/project 
APP_MODULES := HelloNdk 
這裡定義了工程路徑為 $(call my-dir)/project ,而要編譯的模組則是 HelloNdk ,這樣編譯系統才會找到我們要編譯的庫和原檔案 
3、 APP_CFLAGS 則是當要編譯模組中有任何 C 檔案的時候, C 編譯器的訊號就會被髮出 
4、 APP_OPTIM 
這個變數是可選的,可以定義為釋出版或者測試版 
------------------------------------------------------------------------------------------------------------------------ 
在Android.mk中: 
include $(BUILD_EXECUTABLE)表示生成二進位制可執行檔案 
include $(BUILD_STATIC_LIBRARY)表示生成靜態庫.a檔案,名字叫做lib<工程名>.a 
include $(BUILD_SHARED_LIBRARY)表示生成動態庫.so檔案,名字叫做lib<工程名>.so 

另外需要注意的是,生成的檔案需要放在手機的data/local目錄下,才可以有執行的許可權(未root),如果root了,則會有些目錄是可以執行,但是某些目錄依然不能執行,當然可以用umount命令解決。SD卡是沒有執行許可權的,所以當你生成的比如二進位制可執行檔案放到sdcard中時,是無法執行的。 

可以這樣測試一下哪些是有執行許可權,哪些是沒有的: 
*將手機插入電腦,並開啟USB除錯 
*在終端輸入adb shell進入 
*su(root了的手機) 
*mount:可以看到一大堆的列表,如果對應的目錄的資訊中有noexec,說明這個目錄就沒有執行許可權,剩下的都可以執行二進位制等檔案。 

Android.mk檔案的具體語法參見我的部落格:http://hualang.iteye.com/blog/1140414 

向Android原始碼中增加模組主要有如下幾種: 

1、增加可執行檔案
 
增加可執行檔案,這些可執行檔案一般都是由C/C++生成,下面簡單的介紹一些如何向原始碼中生成可執行檔案 
假設我的原始碼在~/mydroid目錄下 
在external/loulijun/test目錄下,建立兩個檔案,一個C,一個Android.mk 
hello.c 
C程式碼
  1. #include <stdio.h>

  2. int main(void)

  3. {

  4. printf("Hello world!\n");

  5. return 0;

  6. }
    複製程式碼
複製程式碼 Android.mk 
Java程式碼
  1. LOCAL_PATH := $(call my-dir)

  2. include $(CLEAR_VARS)

  3. LOCAL_SRC_FILES :=hello.c

  4. LOCAL_MODULE_TAGS :=optional

  5. LOCAL_MODULE :=test

  6. include $(BUILD_EXECUTABLE)
    複製程式碼
複製程式碼 首先退出到mydroid目錄下,執行 
Java程式碼
  1. . build/envsetup.sh

  2. 或者

  3. source build/envsetup.sh
    複製程式碼
複製程式碼 進行環境變數的配置 
然後進入到test目錄下,執行“mm”(mm表示編譯當前專案),如果想重新執行,可以"mm -B" 

這樣,會在out/target/product/generic/obj/EXECUTABLES/test_intermediates/LINKED/目錄下生成可執行檔案test 

然後將test檔案用adb push test /data/local 到data/local目錄下。 

下面開始執行,你可以在手機中用terminal emulator來執行,也可以以adb shell後,執行 
Java程式碼
  1. ./test

  2. 顯示:Hello world!
    複製程式碼
複製程式碼 2、增加靜態庫(.a) 
Android.mk檔案 
Java程式碼
  1. LOCAL_PATH :=$(call my-dir)

  2. include $(CLEAR_VARS)

  3. LOCAL_SRC_FILES := \

  4. hello.c

  5. LOCAL_MODULE :=test

  6. include $(BUILD_STATIC_LIBRARY)
    複製程式碼
複製程式碼 編譯: 
mydroid#. build/envsetup.sh 
test#mm 
生成的結果在out/target/product/generic/obj/STATIC_LIBRARY 
目標資料夾{XXX}_static_intermediates下,XXX為你定義的模組名稱test 

假如這個靜態庫是由hello.c生成的,但是生成的靜態庫是不能直接使用的,而是由動態庫呼叫它 

3、增加動態庫(.so) 
編譯動態庫其實可以用NDK的,那樣生成非常方便,但是有時候還是需要掌握其他的方法的 
Android.mk 
Java程式碼
  1. LOCAL_PATH :=$(call my-dir)

  2. include $(CLEAR_VARS)

  3. LOCAL_SRC_FILES := \

  4. hello.c

  5. LOCAL_MODULE :=test

  6. include $(BUILD_SHARED_LIBRARY)
    複製程式碼
複製程式碼 編譯的放法都差不多,只不過Android.mk不同的是最後一句,如果比較一下就會發現那句話決定了生成的是什麼 

不過要想生成動態庫,絕非是這麼簡單的,有時候只需要Android.mk和原始檔即可,但是有時候還需要Application.mk檔案。Application.mk檔案的具體語法很快會在部落格中更新 




下面是使用 NDK 來生成 .so 檔案的,環境是在 ubuntu11.04 下面 
1、 下載 Android-NDK-r6 ,將其解壓到 ~/android/android-ndk-r6 目錄下 
2、 配置 .bash_profile 檔案,加入 
NDK=~/android/android-ndk-r6 
export NDK 
3、 cd $NDK 後,進入 ndk 的目錄,我以它自帶的專案為例,進入 samples/hello-jni 
在終端輸入 $NDK/ndk-build 
系統會自動編譯這個檔案,並將生成的 libhello-jni.so 檔案存放在當前目錄的 libs/armeabi 目錄下 
4、 我們可以將這個生成的 libhello-jni.so 放在 Android 原始碼的適當的位置即可使用了 
下面是相應的檔案 
hello-jni.c 
Java程式碼
  1. #include <string.h>

  2. #include <jni.h>

  3. jstring

  4. Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,

  5. jobject thiz )

  6. {

  7. return (*env)->NewStringUTF(env, "Hello from JNI !");

  8. }
    複製程式碼
複製程式碼 Android.mk 檔案 
Java程式碼
  1. LOCAL_PATH := $(call my-dir)

  2. include $(CLEAR_VARS)

  3. LOCAL_MODULE := hello-jni

  4. LOCAL_SRC_FILES := hello-jni.c

  5. include $(BUILD_SHARED_LIBRARY)
    複製程式碼
複製程式碼 由於這裡只是使用了一個簡單的 C 檔案,所以沒用用到 Application.mk 檔案 
然後將

相關推薦

Android原始碼增加模組

Android build system就是編譯系統的意思  在我們需要向自己編譯的原始碼中增加模組的時候,需要一些規則,當然這個規則都是類似的。 Android.mk檔案解析  讓我們來看一個 Android.mk 檔案的樣子  Java程式碼 LOCAL_PATH := $(call my-dir)i

如何單獨編譯Android原始碼模組

      第一次下載好Android原始碼工程後,我們通常是在Android原始碼工程目錄下執行make命令,經過漫長的等待之後,就可以得到Android系統映象system.img了。以後如果我們修改了Android原始碼中的某個模組或者在Android原始碼工程新增一個

單獨編譯Android原始碼模組

第一次下載好Android原始碼工程後,我們通常是在Android原始碼工程目錄下執行make命令,經過漫長的等待之後,就可以得到Android系統映象system.img了。以後如果我們修改了Android原始碼中的某個模組或者在Android原始碼工程新增一個自己的模組

單獨編譯Android原始碼的某個模組

       眾所周知,編譯一個韌體要花很久時間。有時只改系統的某個模組的某個功能,如修改系統Setting原始碼的一些地方,這時就沒有必要再整個系統編譯一遍,這時就需要用到模組編譯(前提是系統已經編譯過一遍)。       下面以編譯A20平臺原始碼中的一個apk為例。

unity3d開發的android應用增加AD系統的詳細步驟

查看 發的 b- sset @override 大小 代碼 nac cal unity3d開發的android應用中增加AD系統的詳細步驟 博客分類: Unity3d unity3d Unity3d已經支持android,怎樣在程序裏增加admob?

Android原始碼引用@hide類出現引用異常的問題error: cannot find symbol

    自己開發的APP在Android中使用一些系統隱藏的類         編譯的時候報錯,出現如下異常 error: cannot find symbol import android.net.EthernetM

android原始碼採用Unix Domain Socket跨程序通訊

      今天看android原始碼Zygote程序啟動流程,無意間發現使用了一種檔案描述符作為跨程序通訊的地址,於是仔細研究了一下:  從字面來理解是傳統的Socket使用,但個人覺得不應該是,特地找資料學習了一下,下面的介紹比較詳細到位。又進一步瞭解一下,使用的其實是

Android 原始碼 寫後臺應用

在Android 開機啟動的時候會有一些後臺程序跑起來,當然我麼也可以定製 在vendor 的目錄中放置 一個Android.mk檔案還有一個server.cpp,標頭檔案配置 makefile配置 # LOCAL_PATH變數。它用於在開發樹中查詢原始檔 my

Android 原始碼的設計模式

面向物件的六大原則 單一職責原則   所謂職責是指類變化的原因。如果一個類有多於一個的動機被改變,那麼這個類就具有多於一個的職責。而單一職責原則就是指一個類或者模組應該有且只有一個改變的原因。通俗的說,即一個類只負責一項職責,將一組相關性很高的函式、資料封裝到一個類中。

android原始碼的設計模式

建造者模式 建造者模式最明顯的標誌就是Build類,而在Android中最常用的就是Dialog的構建,Notification的構建也是標準的建造者模式。 建造者模式很好理解,如果一個類的構造需要很多引數,而且這些引數並不都是必須的,那麼這種情況下就比較適合Builder。 比如構建一

android 原始碼預置帶.so檔案的APK

有原始碼有.so預置apk: LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files

android開發Fingerprint模組淺析

一、Fingerprint上層總體架構 Fingerprint模組架構圖如下,這裡分為application,framework,fingerprintd和FingerprintHal這幾個部分,不涉及指紋的IC庫和驅動這部分,這部分邏輯由指紋廠商來實現,目

Android原始碼的靜態工廠方法

我們知道工廠模式有三兄弟,通常我們說的工廠模式指的是工廠方法模式,它的應用頻率最高。本篇部落格分享的簡單工廠模式是工廠方法模式的“小弟”,確切的來講它不屬於設計模式,而是一種方法。此外,工廠方法模式還有一位“大哥”——抽象工廠模式。 今天我們來分享一下簡單工廠

Android原始碼的巧妙的位運算

                                                           與或非是啥? 常用的位運算子: “&”   “|”    “~”(與   或  非)。 1,“&”運算子的運算規則:兩個運算位同時為1時結

Android原始碼關機充電UI的修改

  對於Android原始碼來講,不管是Android4.X系統還是Android5.X系統,關機充電的流程是一樣的。想從網上找關於修改關機充電UI的知識,發現基本沒有,今天有時間就總結一下關於如何修改關機充電的UI介面。   首先,需要了解一下關機充電的流程:如下圖  

Android原始碼如何吧so庫打包編譯進入apk, 整合第三方庫(jar和so庫)

整合第三方so和jar包 include $(CLEAR_VARS) #jar包編譯            LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=securitysdk:libs/hello.jar #64和32系統選擇不同的庫 if

Eclipse與Android原始碼ProGuard工具的使用

由於工作需要,這兩天和同事在研究android下面的ProGuard工具的使用,通過檢視android官網對該工具的介紹以及網路上其它相關資料,再加上自己的親手實踐,算是有了一個基本瞭解。下面將自己的理解和認識簡要的做個筆記,有異議或者不解的,可以直接留言。 什麼是ProGuard工具? ProGua

Android原始碼編譯aidl

為什麼要這麼做? 1、因為專案中一些功能需要呼叫系統原始碼中的一些介面,上層無法訪問。所以想一些需要呼叫系統介面的方法用原始碼編譯,然後使用aidl暴露出介面,供上層呼叫。 準備工作: 1、應用端

【轉】Android ROM研究---Android build system增加模組

Android build system就是編譯系統的意思 在我們需要向自己編譯的原始碼中增加模組的時候,需要一些規則,當然這個規則都是類似的。 Android.mk檔案解析 讓我們來看一個 Android.mk 檔案的樣子 Java程式碼   L

[開源]Android逆向So模組自動化修復工具+實戰一發

前言 Android加固方案經過這麼長時間的發展,從開始的整體dex加密壓縮方案逐步開始往native層發展,市面上知名的幾款商業級加固方案中很容易發現這種方案的身影。這樣看來,在今後相當長的一段時