Android版本:2.3.7_r1
Linux核心版本:android-goldfish-2.6.29
在我們開始分析Android硬體抽象層HAL之前,我們先來通過一個簡單的例子看一下JAVA是怎樣通過Java Native Interface(JNI)與C/C++代碼進行互動的。
首先我們來編寫NativeTest.java,其代碼如下:
[cpp] 1public class NativeTest {
2 public native static double max(double a, double b);
3
4 static {
5 System.loadLibrary("max");
6 }
7
8 public static void main(String[] args) {
9 System.out.println(max(1, 2));
10 }
11}
1public class NativeTest {
2 public native static double max(double a, double b);
3
4 static {
5 System.loadLibrary("max");
6 }
7
8 public static void main(String[] args) {
9 System.out.println(max(1, 2));
10 }
11}第2行,聲明max函數是一個native函數,後面由C語言實現。
第5行,匯入系統庫max,在Linux下,其名稱為libmax.so。
第9行,調用max函數,該函數的實現在max庫中。
接下來,我們要做的是編譯JAVA源碼,並且使用javah工具產生一個C標頭檔。
# javac NativeTest.java
# javah -jni NativeTest
以上兩個命令執行完後,目前的目錄下會產生NativeTest.class和NativeTest.h兩個檔案。
開啟NativeTest.h,其內容如下:
[cpp] 1/* DO NOT EDIT THIS FILE - it is machine generated */
2#include <jni.h>
3/* Header for class NativeTest */
4
5#ifndef _Included_NativeTest
6#define _Included_NativeTest
7#ifdef __cplusplus
8extern "C" {
9#endif
10/*
11 * Class: NativeTest
12 * Method: max
13 * Signature: (DD)D
14 */
15JNIEXPORT jdouble JNICALL Java_NativeTest_max
16 (JNIEnv *, jclass, jdouble, jdouble);
17
18#ifdef __cplusplus
19}
20#endif
21#endif
1/* DO NOT EDIT THIS FILE - it is machine generated */
2#include <jni.h>
3/* Header for class NativeTest */
4
5#ifndef _Included_NativeTest
6#define _Included_NativeTest
7#ifdef __cplusplus
8extern "C" {
9#endif
10/*
11 * Class: NativeTest
12 * Method: max
13 * Signature: (DD)D
14 */
15JNIEXPORT jdouble JNICALL Java_NativeTest_max
16 (JNIEnv *, jclass, jdouble, jdouble);
17
18#ifdef __cplusplus
19}
20#endif
21#endif第15-16行,可以看到,該標頭檔中聲明了一個函數Java_NativeTest_max,這就是需要我們在C程式中實現的函數,它對應JAVA代碼中調用的max函數。
編寫C程式max.c,實現Java_NativeTest_max函數,其代碼如下:
[cpp] 1#include "NativeTest.h"
2JNIEXPORT jdouble JNICALL Java_NativeTest_max
3(JNIEnv * jni_env, jclass class, jdouble a, jdouble b)
4{
5 return a > b? a: b;
6}
1#include "NativeTest.h"
2JNIEXPORT jdouble JNICALL Java_NativeTest_max
3(JNIEnv * jni_env, jclass class, jdouble a, jdouble b)
4{
5 return a > b? a: b;
6}Java_NativeTest_max函數的作用是返回兩個參數較大的那個。
下面我們需要編譯產生動態連結程式庫libmax.so,在編譯之前,先配置環境變數:
# export C_INCLUDE_PATH=$C_INCLUDE_PATH:$JAVA_HOME/include
# export C_INCLUDE_PATH=$C_INCLUDE_PATH:$JAVA_HOME/include/linux
# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
編譯動態連結程式庫:
# gcc max.c -fPIC -shared -o libmax.so
在目前的目錄下會產生動態連結程式庫檔案libmax.so,執行JAVA程式:
# java NativeTest
2.0
上面的過程就是使用JNI串連JAVA代碼與C代碼的過程。