android分層學習筆記(二)

來源:互聯網
上載者:User

android 是的jni是java與c之間的中介。java通過jni訪問c/c++的函數功能。
jni的編寫,比較簡單,而且有一個模板可以套用。就像寫八股文一樣,並且不用像寫八股文那樣要把內容填入很漂亮,而是完成功能即可,沒有華麗的外表。

在hal目錄下建立framework,並在framework下建立service/jni目錄,即
cd hal
mkdir -p  framework/jni

在jni目錄下建立com_ask_gpio.cpp檔案。

標頭檔:
#include "utils/Log.h"            //用於在logcat中可以看到log資訊                  

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

#include <jni.h>               //jni相關的函數
#include <gpio.h>              //gpio操作的函數及變數(id號),這個標頭檔其實就是module/gpio/目錄下的gpio.h檔案

實現gpio置1
static jboolean ask_gpio_set(JNIEnv* env, jobject thiz, jint gpio)
{
    LOGI("GPIOService JNI: ask_gpioSet()");
    
//    apc

    if (g_gpioDev == NULL)
    {
        LOGI("GPIOService JNI: not gpio device.");
        return -1;
    }
    else
    {
        return g_gpioDev->SetGPIO(g_gpioDev, gpio);
    }
}

實現gpio清0
static jboolean ask_gpio_clr(JNIEnv* env, jobject thiz, jint gpio)
{
    LOGI("GPIOService JNI: ask_gpioClr()");

    if (g_gpioDev == NULL)
    {
        LOGI("GPIOService JNI: not gpio device.");
        return -1;
    }
    else
    {
        return g_gpioDev->ClrGPIO(g_gpioDev, gpio);
    }
}
jni層開啟gpio裝置,其實就是調用了module/gpio/gpio.c中的gpio_device_open函數
static inline int ask_gpio_open(const struct hw_module_t* module, struct gpio_device_t** device)
{
    return module->methods->open(module,  GPIO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}

給java層調用的介面函數
static const JNINativeMethod gMethods[] = {
    { "_gpio_init",          "()Z",    (void *)ask_gpio_init },
    { "_gpio_set",        "(I)Z", (void *)ask_gpio_set },
    { "_gpio_clr",       "(I)Z", (void *)ask_gpio_clr },
};
註:關於這個結構體的填寫,涉及到c類型到java類型的轉換,android定義了橋接變數,如()z之類的,具體的映射如下
JNINativeMethod的結構體變數成員分別為
const char* name;       //Java中函數的名字
const char* signature;  //signature,用字串是描述了函數的參數和傳回值
void* fnPtr;            //fnPtr是函數指標,指向C函數。

對於signature,內容必須與fnPtr是函數指標的格式一致,即
(1)如果函數fnPtr的指向的函數為void fun(void),那麼signature的內容必須為“()”
(2)如果函數fnPtr的指向的函數為int func(int i, int j),那麼signature的內容必須為“(II)I”

具體的每一個字元的對應關係如下
字元 Java類型 C類型
V:      void     <-->       void
Z:       jboolean  <-->   boolean
I:        jint     <-->     int
J:      jlong            long
D:     jdouble   <-->  double
F:      jfloat   <-->     float
B:      jbyte    <-->     byte
C:      jchar    <-->    char
S:      jshort   <-->   short
數組則以"["開始,用兩個字元表示
[I:       jintArray  <-->    int[]
[F:     jfloatArray <-->   float[]
[B:     jbyteArray <-->   byte[]
[C:    jcharArray  <-->  char[]
[S:    jshortArray <-->  short[]
[D:    jdoubleArray <--> double[]
[J:     jlongArray  <-->   long[]
[Z:    jbooleanArray <--> boolean[]
以上為基本類型,如果Java函數的參數是class,則以"L"開頭,以";"結尾中間用"/" 隔開的包及類名。而其對應的C函數名的參數則為jobject。 一個例外是String類,其對應的類為jstring
Ljava/lang/String; : String <--> jstring
Ljava/net/Socket; : Socket <--> jobject
如果JAVA函數位於一個嵌入類,則用$作為類名間的分隔字元。
例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

註冊存取方法
int register_askhals_server_GpioService(JNIEnv* env) {
    static const char* const kClassName = "com/ask/server/GpioService";  
    jclass clazz;

    /* look up the class */
    clazz = env->FindClass(kClassName);
    if (clazz == NULL)
    {
        LOGE("Can't find class %s/n", kClassName);
        return -1;
    }

    /* register all the methods */
    if (env->RegisterNatives(clazz, gMethods,
            sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
    {
        LOGE("Failed registering methods for %s/n", kClassName);
        return -1;
    }

    /* fill out the rest of the ID cache */
    return 0;
}
其中kClassName必須與編寫java代碼的service的時涉及到.xml中的name項一致,否則將找不到類名,這個將在下節說明。

載入c模組,調用register_askhals_server_GpioService函數
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

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

    register_ctophals_server_GpioService(env);
     return JNI_VERSION_1_4;
}
java相關中System.load函數時,就是調用此函數了。

寫完cpp檔案
那麼剩下就是Android.mk檔案了。
如下:
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
ASK_MODULE_H_DIR := /home/gium/android_src/vendor/ask/modules/gpio/
LOCAL_SRC_FILES:= /
    com_ask_gpio.cpp
     
LOCAL_C_INCLUDES += /
    $(JNI_H_INCLUDE) /
    $(ASK_MODULE_H_DIR)
LOCAL_SHARED_LIBRARIES := /
    libcutils /
    libhardware /
    libhardware_legacy /
    libnativehelper /
    libsystem_server /
    libutils /
    libui
ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS),linux)
ifeq ($(TARGET_ARCH),x86)
LOCAL_LDLIBS += -lpthread -ldl -lrt
endif
endif
endif

ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
    LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
endif

LOCAL_MODULE:= libaskgpio

LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)

註:ASK_MODULE_H_DIR這個是自己定義的,就是gpio模組所在目錄,要根據自己的實際情況而改,目前我的目錄為/home/gium/android_src/vendor/ctop/modules/gpio/
這樣在文中的包含標頭檔可以寫成include <gpio.h>

下節說明java調用這個jni的內容。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.