Android Framework 소스의 JNI 메소드 등록 프로세스

12096 단어
Android Zygote 프로세스 시작 (1) 글에서 Android Runtime에 언급되었습니다.cpp에서 언급한 안드로이드 런타임:::start () 함수는 주로 세 가지를 합니다: 1.자바 가상 머신 시작, 2.등록 방법zygote의main 방법을 호출합니다.오늘 안드로이드 프레임워크에서 JNI 방법을 어떻게 등록했는지 알아보겠습니다.
/*
 * Register android native functions with the VM.
 */
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
    /*
     * This hook causes all future threads created in this process to be
     * attached to the JavaVM.  (This needs to go away in favor of JNI
     * Attach calls.)
     */
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---
"); /* * Every "register" function calls one or more things that return * a local reference (e.g. FindClass). Because we haven't really * started the VM yet, they're all getting stored in the base frame * and never released. Use Push/Pop to manage the storage. */ env->PushLocalFrame(200); if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); //createJavaThread("fubar", quickTest, (void*) "hello"); return 0; }

방법 중 먼저 라인 생성 방법을javaCreateThreadEtc로 설정한 다음register를 통해jni_procs에서 jni 방법을 등록했습니다.
register_jni_procs 함수 매개변수 RegJNIRec은 미리 정의된 매크로입니다.
#ifdef NDEBUG
    #define REG_JNI(name)      { name }
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
    };
#else
    #define REG_JNI(name)      { name, #name }
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
        const char* mName;
    };
#endif

코드에서 볼 수 있듯이 RegJNIRec는 구조체로 mProc 수신 파라미터가 JNIEnv 포인터로 되돌아오는 값이 int인 함수 포인터를 포함하고 있다.
static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    ····
}

register_jni_procs 함수는 jni 메서드의 등록을 위해 RegJNIRec 배열에서 mProc 메서드를 반복적으로 호출합니다.
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
            ALOGD("----------!!! %s failed to load
", array[i].mName); #endif return -1; } } return 0; }

여기는registerandroid_content_AssetManager 메서드의 등록은 등록 프로세스를 분석합니다.우선registerandroid_content_AssetManager 메서드의 설명은 다음과 같은 네임스페이스android 아래에 있습니다.
namespace android {

/*
 * JNI-based registration functions.  Note these are properly contained in
 * namespace android.
 */
extern int register_android_app_admin_SecurityLog(JNIEnv* env);
extern int register_android_content_AssetManager(JNIEnv* env);


그에 상응하는 실현 조작은androidutil_AssetManager.cpp 파일
int register_android_content_AssetManager(JNIEnv* env)
{
       ......
       return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
                                NELEM(gAssetManagerMethods));
}

gAssetManagerMethods는 현재 등록해야 하는 jni의 방법 목록입니다.
static const JNINativeMethod gAssetManagerMethods[] = {
    /* name, signature, funcPtr */

    // Basic asset stuff.
    { "openAsset",      "(Ljava/lang/String;I)J",
        (void*) android_content_AssetManager_openAsset },
    { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
        (void*) android_content_AssetManager_openAssetFd },
    { "openNonAssetNative", "(ILjava/lang/String;I)J",
        (void*) android_content_AssetManager_openNonAssetNative },
    { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
        (void*) android_content_AssetManager_openNonAssetFdNative },
    { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
        (void*) android_content_AssetManager_list },
    { "destroyAsset",   "(J)V",
        (void*) android_content_AssetManager_destroyAsset },
    { "readAssetChar",  "(J)I",
        (void*) android_content_AssetManager_readAssetChar },
    { "readAsset",      "(J[BII)I",
        (void*) android_content_AssetManager_readAsset },
    { "seekAsset",      "(JJI)J",
        (void*) android_content_AssetManager_seekAsset },
    { "getAssetLength", "!(J)J",
        (void*) android_content_AssetManager_getAssetLength },
    { "getAssetRemainingLength", "!(J)J",
        (void*) android_content_AssetManager_getAssetRemainingLength },
    { "addAssetPathNative", "(Ljava/lang/String;Z)I",
        (void*) android_content_AssetManager_addAssetPath },
    { "addOverlayPathNative",   "(Ljava/lang/String;)I",
        (void*) android_content_AssetManager_addOverlayPath },
    { "isUpToDate",     "()Z",
        (void*) android_content_AssetManager_isUpToDate },

    // Resources.
    { "getLocales",      "()[Ljava/lang/String;",
        (void*) android_content_AssetManager_getLocales },
    { "getNonSystemLocales", "()[Ljava/lang/String;",
        (void*) android_content_AssetManager_getNonSystemLocales },
    { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
        (void*) android_content_AssetManager_getSizeConfigurations },
    { "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
        (void*) android_content_AssetManager_setConfiguration },
    { "getResourceIdentifier","!(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
        (void*) android_content_AssetManager_getResourceIdentifier },
    { "getResourceName","!(I)Ljava/lang/String;",
        (void*) android_content_AssetManager_getResourceName },
    { "getResourcePackageName","!(I)Ljava/lang/String;",
        (void*) android_content_AssetManager_getResourcePackageName },
    { "getResourceTypeName","!(I)Ljava/lang/String;",
        (void*) android_content_AssetManager_getResourceTypeName },
    { "getResourceEntryName","!(I)Ljava/lang/String;",
        (void*) android_content_AssetManager_getResourceEntryName },
    { "loadResourceValue","!(ISLandroid/util/TypedValue;Z)I",
        (void*) android_content_AssetManager_loadResourceValue },
    { "loadResourceBagValue","!(IILandroid/util/TypedValue;Z)I",
        (void*) android_content_AssetManager_loadResourceBagValue },
    { "getStringBlockCount","!()I",
        (void*) android_content_AssetManager_getStringBlockCount },
    { "getNativeStringBlock","!(I)J",
        (void*) android_content_AssetManager_getNativeStringBlock },
    { "getCookieName","(I)Ljava/lang/String;",
        (void*) android_content_AssetManager_getCookieName },
    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },

    // Themes.
    { "newTheme", "()J",
        (void*) android_content_AssetManager_newTheme },
    { "deleteTheme", "(J)V",
        (void*) android_content_AssetManager_deleteTheme },
    { "applyThemeStyle", "(JIZ)V",
        (void*) android_content_AssetManager_applyThemeStyle },
    { "copyTheme", "(JJ)V",
        (void*) android_content_AssetManager_copyTheme },
    { "clearTheme", "(J)V",
        (void*) android_content_AssetManager_clearTheme },
    { "loadThemeAttributeValue", "!(JILandroid/util/TypedValue;Z)I",
        (void*) android_content_AssetManager_loadThemeAttributeValue },
    { "getThemeChangingConfigurations", "!(J)I",
        (void*) android_content_AssetManager_getThemeChangingConfigurations },
    { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
        (void*) android_content_AssetManager_dumpTheme },
    { "applyStyle","!(JIIJ[I[I[I)Z",
        (void*) android_content_AssetManager_applyStyle },
    { "resolveAttrs","!(JII[I[I[I[I)Z",
        (void*) android_content_AssetManager_resolveAttrs },
    { "retrieveAttributes","!(J[I[I[I)Z",
        (void*) android_content_AssetManager_retrieveAttributes },
    { "getArraySize","!(I)I",
        (void*) android_content_AssetManager_getArraySize },
    { "retrieveArray","!(I[I)I",
        (void*) android_content_AssetManager_retrieveArray },

    // XML files.
    { "openXmlAssetNative", "(ILjava/lang/String;)J",
        (void*) android_content_AssetManager_openXmlAssetNative },

    // Arrays.
    { "getArrayStringResource","(I)[Ljava/lang/String;",
        (void*) android_content_AssetManager_getArrayStringResource },
    { "getArrayStringInfo","!(I)[I",
        (void*) android_content_AssetManager_getArrayStringInfo },
    { "getArrayIntResource","!(I)[I",
        (void*) android_content_AssetManager_getArrayIntResource },
    { "getStyleAttributes","!(I)[I",
        (void*) android_content_AssetManager_getStyleAttributes },

    // Bookkeeping.
    { "init",           "(Z)V",
        (void*) android_content_AssetManager_init },
    { "destroy",        "()V",
        (void*) android_content_AssetManager_destroy },
    { "getGlobalAssetCount", "()I",
        (void*) android_content_AssetManager_getGlobalAssetCount },
    { "getAssetAllocations", "()Ljava/lang/String;",
        (void*) android_content_AssetManager_getAssetAllocations },
    { "getGlobalAssetManagerCount", "()I",
        (void*) android_content_AssetManager_getGlobalAssetManagerCount },
};

여기서 Andoird에서는 서로 다른 기존 JNI 방식을 사용하여 native의 함수를 정의합니다.여기서 중요한 차이점은 Andorid가 자바와 C 함수의 매핑 테이블 배열을 사용하고 함수의 매개 변수와 반환 값을 설명하는 것이다.이 배열의 유형은 JNINativeMethod이고 jni에 정의되어 있습니다.h의 헤더 파일은 다음과 같습니다.
typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;


첫 번째 변수 name은 Java의 함수 이름입니다.두 번째 변수signature, 함수의 매개 변수와 반환 값을 문자열로 설명하는 세 번째 변수 fnPtr는 함수 바늘로 C 함수를 가리킨다.그 중에서 이해하기 어려운 것은 두 번째 매개 변수이다. 예를 들어'()V'(II)V'(Ljava/lang/string, Ljava/lang/string,)V "실제로 이 문자들은 함수의 매개 변수 유형과 일일이 대응한다."() "의 문자는 매개 변수를 나타내고, 뒤에 있는 문자는 되돌아오는 값을 나타냅니다. 예를 들어"() V "는void Func () 를 나타냅니다.(II) V "void Func(int, int)를 나타냅니다. 구체적인 각 문자의 대응 관계는 다음과 같습니다. Java 유형 C 유형 V void Z jboolean boolean I jint Jjlong 롱 D jdouble double F jfloat float B jbyte byte C jchar S jshort 배열은"["[I jint Array int [] [F jfloat Array float By] [jby Array Arteby] [] [jby][C jcharararray char[][S jshort Array short[] [D jdouble Array double[][J jlong Array long[] [Z jboolean Array boolean[] 위에 있는 것은 모두 기본 유형입니다.Java 함수의 매개 변수가 class이면 "L"로 시작하고 ";"끝 중간에 "/"로 구분된 가방과 클래스 이름입니다.그에 대응하는 C함수 이름의 매개 변수는jobject이다.하나의 예외는String클래스인데 그에 대응하는 클래스는 jstring Ljava/lang/String이다.String jstring Ljava/net/Socket; Socket jobject JAVA 함수가 포함된 클래스에 있으면 $를 클래스 이름 사이의 구분자로 사용합니다.
RegisterMethodsOrDie 메서드의 구현:
static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
                                       const JNINativeMethod* gMethods, int numMethods) {
    int res = AndroidRuntime::registerNativeMethods(env, className, gMethods, numMethods);
    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
    return res;
}

최종적으로 모든 jni의native를 등록하는 것을 알 수 있다.이로써 Android Framework의 JNI 등록 메소드 프로세스가 완전히 완료되었습니다.

좋은 웹페이지 즐겨찾기