Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android系統JNI的實現方式

Android系統JNI的實現方式

編輯:關於Android編程



Android系統JNI的實現方式

All rights reserved

JNI(Java Native Interface)定義了一種Java代碼調用C或者C++代碼等其他代碼的方式。

在Android系統中,JNI通過JNINativeMethod結構體進行描述,該結構體定義於jni.h,如下所示:

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;

第一個參數name:是Java代碼中的函數名。

第二個參數signature:用於描述函數的參數和返回值。

第三個參數fnPtr:C代碼中函數的指針。

其中,第二個參數為一個描述函數參數和返回值的字符串,字符串的格式如下:

(XX..)X

X的取值和定義如下所示:

字符

Java類型

C類型

V

void

void

Z

jboolean

unsigned char

B

jbyte

signed char

C

jchar

unsigned short

S

jshort

short

I

jint

int

J

jlong

long

F

jfloat

float

D

jdouble

double

另外,從jni.h中對於變量類型的定義中也可以看到這些字符的意義,如下所示:

typedef unsigned char   jboolean;       /* unsigned 8 bits */
typedef signed char     jbyte;          /* signed 8 bits */
typedef unsigned short  jchar;          /* unsigned 16 bits */
typedef short           jshort;         /* signed 16 bits */
typedef int             jint;           /* signed 32 bits */
typedef long long       jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */

typedef union jvalue {
    jboolean    z;
    jbyte       b;
    jchar       c;
    jshort      s;
    jint        i;
    jlong       j;
    jfloat      f;
    jdouble     d;
    jobject     l;
} jvalue;

例如,為一個驅動添加HAL層,並創建JNI層。僅就JNI層而言,創建frameworks/base/services/jni/com_android_server_DemoService.cpp文件,該文件中用於描述JNI接口的代碼如下所示:

static const JNINativeMethod method_table[] = {
                {"init_native", "()I", (void*)demo_init},
                {"setVal_native", "(II)V", (void*)demo_setVal},
                {"getVal_native", "(I)I", (void*)demo_getVal},
        };

其中“(II)V”,表示函數的有兩個整形參數,返回值為void。

注意:由參數二指定的函數參數和返回值類型一定要和C函數的參數和返回值保持一致,否則雖然編譯能夠通過,但在Android系統加載過程中,會報如下所示的錯誤,導致Android系統無法正常運行。

E/dalvikvm( 1737): ERROR: couldn't find native method
E/dalvikvm( 1737): Requested: Lcom/android/server/DemoService;.init_native:()Z
E/dalvikvm( 1737): Candidate: Lcom/android/server/DemoService;.init_native:()I
E/JNIHelp ( 1737): RegisterNatives failed for 'com/android/server/DemoService', aborting
F/libc    ( 1737): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 1737 (system_server)

以上錯誤通發生在frameworks/base/services/jni/onload.cpp文件中的JNI_OnLoad()函數中,如下所示:

extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("GetEnv failed!");
        return result;
    }
    ALOG_ASSERT(env, "Could not retrieve the env!");
    ……   
    register_android_server_DemoService(env);
    ……
    return JNI_VERSION_1_4;
}

另外,ProGuard對程序的優化也可能導致上述運行錯誤的發生。此時,可以在makefile文件中添加“LOCAL_PROGUARD_ENABLED:=disabled”宏來關閉ProGuard的優化。

關於ProGuard,可以參考其官方網站:http://proguard.sourceforge.net/

ProGuard是一個免費的Java類文件壓縮器、優化器、混淆器和預校驗器。它會檢測並刪除沒有用到的類、域、方法以及屬性。它最大限度的優化字節碼並且刪除無用的指令。它用很短的沒有意義的名字對剩余的類、域和方法進行重命名。最後,它對處理過的代碼進行預校驗。

ProGuard的一些用途如下:

A.為了更小的代碼檔案、更快的網絡傳輸、更快的加載速度和更小的內存占用創建更緊湊的代碼;

B.使程序和庫難於進行反向工程;

C.列出死代碼,這樣就能將其刪除;

D.為Java 6或更高的版本對存在的類文件進行重定位和預校驗,以充分利用其快速加載類的性能。




















  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved