安卓驅動、HAL、JNI與java

very_on發表於2018-05-20

最近看了安卓驅動層到應用層的實現,總結一下所學,新手學習,不足之處請指正(以LED為例):

網址:http://blog.csdn.net/liruicom/article/details/8517948

由驅動層到應用層的流程Linux驅動->HAL->JNI->APK

首先是驅動層:

    1)建立cdev與實現file_operations 。

    2)module_init與module_exit的實現:在module_init中實現cdev_init()、register_chrdev_region()或alloc_chrdev_region()與cdev_add(),同時實現class_create()、device_class()。在module_exit中實現device_destroy()、class_destroy()與unregister_chrdev_region()。

    3)open與release函式的實現,open函式中實現gpio_request()、s3c_gpio_cfgpin()、gpio_direction_output()函式。release函式中實現gpio_free()。

    4)ioctl函式實現

    5)MODULE_LICENSE("GPL")

    6)對Makefile與Kconfig函式修改。

其次HAL層實現:

    HAL層的入口函式為HAL_MODULE_INFO_SYM,呼叫過程為HAL_MODULE_INFO_SYM-> hw_module_methods_t->open,在open中對包含hw_device_t的結構體進行一系列初始化,並開啟LED驅動裝置。具體實現過程如下:

    1)定義結構體和巨集

        hw_module_t,hw_device_t及IO,HAL規定不可直接使用hw_module_t結構體,因此,需要在hw_module_t外再套一層結構體。hw_module_t及hw_device_t自定義結構體內的第一個成員變數資料結構必須為hw_module_t與hw_device_t。在hw_device_t自定義的結構體內可定義函式指標,函式指標的數量與引數可自己定義,但必須與上層呼叫形式儲存一致。

    2)編寫HAL模組的open函式

        (1)初始化hw_device_t子結構體、必要操作、硬體操作函式指標。

        (2)開啟裝置檔案。

        (3)初始化暫存器

    3)定義hw_module_methods_t結構體變數

    4)定義HAL_MODULE_INFO_SYM變數,一般為hw_module_t或子結構體,並對其初始化。

    5)編寫HAL模組close函式

    6)編寫控制函式

    7)編寫Android.mk

再次編寫JNI函式

    1)編寫JNI_Onload函式,系統在成功裝載JNI共享庫後自動呼叫,一般用於初始化JNI,函式如下:主要實現功能:告訴JavaVm使用虛擬機器那一個版本:初值設定獲取JavaVm介面

/*沒有理解JNI_OnLoad函式與register_android_server_LedService函式,若您理解了之後可以留言教我一下嗎*/

    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_android_server_LedService( env );//將JNI程式庫與Java類繫結
        return JNI_VERSION_1_4;
    }

int register_android_server_LedService(JNIEnv *env)
{
    static const char* const kClassName = " android /server/LedService"; /*kclassname‍ 指定了需要呼叫該Jni庫的Java APP類*/
    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, method_table,
    sizeof(method_table) / sizeof(method_table[0])) != JNI_OK)
    {
       LOGE("Failed registering methods for %s/n", kClassName);
       return -1;
    }

    /* fill out the rest of the ID cache */
    return 0;
}

/*JNI與JAVA對應對映表,格式:要註冊到java類中的方法名;方法引數與返回值的型別;要註冊到JNI的指標函式*/

 static JNINativeMethod method_table[] = {
{ "led_init", "()Z", (void*)Java_com_embedsky_led_LedActivity_ledInit },
{ "led_setOn", "(I)Z", (void*)Java_com_embedsky_led_LedActivity_ledSetOn },
{ "led_setOff", "(I)Z", (void*)Java_com_embedsky_led_LedActivity_ledSetOff },
{ "led_close", "()Z", (void*)Java_com_embedsky_led_LedActivity_ledClose },

     2)實現method_table[] 中JNI的指標函式,在init中呼叫hw_get_module函式,實現通過呼叫hw_get_module函式找到HAL中定義標頭檔案的ID來查詢HAL模組,並獲得hw_module_t的子結構,來呼叫hw_module_methods_t中的open函式來初始化hw_device_t的子結構體。

最後實現JAVA函式

    1)package xxx/*宣告原始檔中的類屬於哪個具體包,包的名字是有層次的,各層之間以點分割,必須與檔案系統結構相同*/

    2)import xxx /*將其他包中的類引入當前名字空間中*/

     3)public class LedActivity extends Activity {
            static {
            System.loadLibrary("led");??
作用是什麼,不太理解?
             }
             /*在C++中實現native函式,需要特定格式,可以用javah來幫助宣告用javac編譯我們的java類,獲得class檔案,然後javah xxx.class 生成.h檔案JNI格式按.h檔案書寫*/

            public static native boolean ledInit();/*要將JNI呼叫的方法做本地宣告,關鍵詞native*/
            public static native boolean ledClose();
            private static native boolean ledSetOn(int number);
            private static native boolean ledSetOff(int number);

            CheckBox[] cb = new CheckBox[8];
            CheckBox cbAll;// 全選
            Button btnQuit;// 退出按鈕
            @Override
/*重寫父類,加 @Override系統可以幫你檢查方法的正確性*/
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);

                setContentView(R.layout.main);
                // 獲取 xml 中對應的控制元件
                cb[0] = (CheckBox) findViewById(R.id.cbLed1);
                cb[1] = (CheckBox) findViewById(R.id.cbLed2);
                cb[2] = (CheckBox) findViewById(R.id.cbLed3);
                cb[3] = (CheckBox) findViewById(R.id.cbLed4);
                cb[4] = (CheckBox) findViewById(R.id.cbLed5);
                cb[5] = (CheckBox) findViewById(R.id.cbLed6);
                cb[6] = (CheckBox) findViewById(R.id.cbLed7);
                cb[7] = (CheckBox) findViewById(R.id.cbLed8);
                cbAll = (CheckBox) findViewById(R.id.cbLedAll);
                btnQuit = (Button) findViewById(R.id.btnQuit);
                // 初始化點選事件物件

               // 初始化點選事件物件
               MyClickListener myClickListern = new MyClickListener();
              // LED1-LED8 選中 / 取消事件
              for (int i = 0; i < 8; i++) {
                   cb[i].setOnClickListener(myClickListern);
              }
             // 全選選中 / 取消事件
             cbAll.setOnClickListener(myClickListern);
             // 退出按鈕點選事件處理
            btnQuit.setOnClickListener(new OnClickListener() {
           @Override
           public void onClick(View v) {
           finish();
         }
     }
      // led 初始化
     if (!ledInit()) {
         new AlertDialog.Builder(this).setTitle("init led fail").show();
         //led 初始化失敗,則使控制元件不可點選

         for (int i = 0; i < 8; i++)
         cb[i].setEnabled(false);
        cbAll.setEnabled(false);
       }
}

      // 自定義的事件監聽器類,用來處理 CheckBox 選中和取消事件
      public class MyClickListener implements OnClickListener {

     @Override
      public void onClick(View v) {
      // 遍歷陣列,判斷是哪個 led 控制元件被選中
      for (int i = 0; i < 8; i++) {
     if (v == cb[i]) {
     // 根據選中 / 取消狀態來控制 led 燈的亮 / 滅
      controlLed(i + 1, cb[i].isChecked());
    return;
      }
}
// 全選按鈕,遍歷陣列,對所有 led 燈做控制
    if (v == cbAll) {
    for (int i = 0; i < 8; i++) {
    controlLed(i + 1, cbAll.isChecked());
   cb[i].setChecked(cbAll.isChecked());
   }
  }
  }

/*******************************************/
// 功能: LED 亮 / 滅處理
// 引數:
// number : 燈編號
// on :true ,亮 ;fase, 滅
/*******************************************/
private void controlLed(int number, boolean on) {
if (on) {
ledSetOn(number);
} else {
ledSetOff(number);
}
}
}

相關文章