做者:劉昊昱 java
博客:http://blog.csdn.net/liuhaoyutzandroid
Android版本:2.3.7_r1數據結構
Linux內核版本:android-goldfish-2.6.29架構
在上一篇博客《Android架構分析之硬件抽象層(HAL)》中,咱們瞭解了硬件抽象層的基本數據結構和模塊編寫規則,如今,咱們就來看怎樣編寫一個自定義的硬件抽象層模塊並加入到Android系統中,同時,咱們還要介紹應用程序怎樣使用咱們自定義的硬件抽象層模塊。app
硬件抽象層的做用是給上層應用程序提供一個訪問硬件設備的接口,在本文中,咱們要操做的硬件設備是在前面博客文章中建立的/dev/example,該設備的內核驅動的實現能夠參考《Android架構分析之Android驅動程序開發》一文。ide
首先,咱們來建立自定義的硬件抽象層模塊,同硬件設備名同樣,將其命名爲example,進入hardware/libhardware/include/hardware目錄,建立example.h文件,內容以下:函數
1#ifndef ANDROID_EXAMPLE_INTERFACE_H 2#define ANDROID_EXAMPLE_INTERFACE_H 3 4#include <hardware/hardware.h> 5 6__BEGIN_DECLS 7 8/** 9 * The id of this module 10 */ 11#define EXAMPLE_HARDWARE_MODULE_ID "example" 12 13/** 14 * The id of this device 15 */ 16#define EXAMPLE_HARDWARE_DEVICE_ID "example 17 18struct example_module_t { 19 struct hw_module_t common; 20}; 21 22struct example_device_t { 23 struct hw_device_t common; 24 int fd; 25 int (*set_val)(struct example_device_t* dev, int val); 26 int (*get_val)(struct example_device_t* dev, int* val); 27}; 28 29__END_DECLS 30 31#endif
18-20行,咱們自定義的硬件抽象層模塊類型是example_module_t。按照Android的規定,硬件抽象層模塊結構體的第一個成員必須是hw_module_t類型。佈局
22-27行,硬件抽象層模塊example訪問的設備類型是example_device_t。按照Android的規定,設備結構體的第一個成員必須是hw_device_t類型。fd用來保存打開的設備描述符。set_val函數用來向設備寄存器寫數據,get_val函數用來讀取設備寄存器。this
接下來,進入hardware/libhardware/modules目錄,建立一個example目錄,再在example目錄下建立Android.mk和example.cpp兩個文件。atom
Android.mk文件內容以下:
1LOCAL_PATH := $(call my-dir) 2include $(CLEAR_VARS) 3LOCAL_MODULE_TAGS := optional 4LOCAL_PRELINK_MODULE := false 5LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw 6LOCAL_SHARED_LIBRARIES := liblog 7LOCAL_SRC_FILES := example.cpp 8LOCAL_MODULE := example.default 9include $(BUILD_SHARED_LIBRARY)
第9行,BUILD_SHARED_LIBRARY參數表示將該硬件抽象層模塊編譯爲動態連接庫文件。
第8行,表示編譯生成的動態連接庫名爲example.default.so。
第5行,表示生成的動態連接庫文件存放在$(TARGET_OUT_SHARED_LIBRARIES)/hw目錄下。
example.cpp文件內容以下:
1#define LOG_TAG "ExampleHALStub" 2 3#include <hardware/hardware.h> 4#include <hardware/example.h> 5 6#include <fcntl.h> 7#include <errno.h> 8 9#include <cutils/log.h> 10#include <cutils/atomic.h> 11 12#define DEVICE_NAME "/dev/example" 13#define MODULE_NAME "Example" 14#define MODULE_AUTHOR "haoyu" 15 16static int example_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device); 17static int example_device_close(struct hw_device_t* device); 18static int example_set_val(struct example_device_t* dev, int val); 19static int example_get_val(struct example_device_t* dev, int* val); 20 21static struct hw_module_methods_t example_module_methods = { 22 open: example_device_open 23}; 24 25struct example_module_t HAL_MODULE_INFO_SYM = { 26 common: { 27 tag: HARDWARE_MODULE_TAG, 28 version_major: 1, 29 version_minor: 0, 30 id: EXAMPLE_HARDWARE_MODULE_ID, 31 name: MODULE_NAME, 32 author: MODULE_AUTHOR, 33 methods: &example_module_methods, 34 } 35}; 36 37static int example_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device) { 38 if(!strcmp(id, EXAMPLE_HARDWARE_DEVICE_ID)) { 39 struct example_device_t* dev; 40 41 dev = (struct example_device_t*)malloc(sizeof(struct example_device_t)); 42 if(!dev) { 43 LOGE("Failed to alloc space for example_device_t."); 44 return -EFAULT; 45 } 46 47 memset(dev, 0, sizeof(struct example_device_t)); 48 49 dev->common.tag = HARDWARE_DEVICE_TAG; 50 dev->common.version = 0; 51 dev->common.module = (hw_module_t*)module; 52 dev->common.close = example_device_close; 53 dev->set_val = example_set_val; 54 dev->get_val = example_get_val; 55 56 if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) { 57 LOGE("Failed to open device file /dev/example -- %s.", strerror(errno)); 58 free(dev); 59 return -EFAULT; 60 } 61 62 *device = &(dev->common); 63 64 LOGI("Open device file /dev/example successfully."); 65 66 return 0; 67 } 68 69 return -EFAULT; 70} 71 72static int example_device_close(struct hw_device_t* device) { 73 struct example_device_t* example_device = (struct example_device_t*)device; 74 if(example_device) { 75 close(example_device->fd); 76 free(example_device); 77 } 78 79 return 0; 80} 81 82static int example_set_val(struct example_device_t* dev, int val) { 83 if(!dev) { 84 LOGE("Null dev pointer."); 85 return -EFAULT; 86 } 87 88 LOGI("Set value %d to device file /dev/example.", val); 89 write(dev->fd, &val, sizeof(val)); 90 91 return 0; 92} 93 94static int example_get_val(struct example_device_t* dev, int* val) { 95 if(!dev) { 96 LOGE("Null dev pointer."); 97 return -EFAULT; 98 } 99 100 if(!val) { 101 LOGE("Null val pointer."); 102 return -EFAULT; 103 } 104 105 read(dev->fd, val, sizeof(*val)); 106 107 LOGI("Get value %d from device file /dev/example.", *val); 108 109 return 0; 110}
21-23行,定義了hw_module_methods_t類型變量example_module_methods,hw_module_methods_t類型只有一個成員變量,即open函數,用來打開指定ID的設備,這裏指定open成員爲example_device_open函數。
25-35行,按照Android的規定,每一個硬件抽象層模塊都必須定義一個命名爲HAL_MODULE_INFO_SYM的自定義結構體類型的變量。這裏對其hw_module_t類型的第一個成員變量進行了初始化。
37-70行,定義了example_device_open函數,該函數用來打開第二個參數id指定的設備,初始化對應該設備的hw_device_t變量,並經過第三個參數device返回。第56行,調用open函數打開指定設備,並將設備描述符保存在dev->fd中。
72-100行,有了設備描述符,後面的代碼example_device_close、example_set_val、example_get_val三個函數就是經過該文件描述符,分別調用close,write,read函數執行關閉,寫和讀操做。
執行以下命令編譯example HAL模塊:
# mmm hardware/libhardware/modules/example
# make snod
這樣system.img中就包含咱們定義的硬件抽象層模塊example.default.so了。
爲了讓Android應用程序可以經過硬件抽象層模塊對底層硬件進行操做,咱們須要使用AIDL語言建立一個硬件訪問服務接口。在Android系統中,硬件訪問服務接口一般定義在frameworks/base/core/java/android/os目錄中,因此咱們在這個目錄下建立一個IExampleService.aidl文件,其內容以下:
1package android.os; 2 3interface IExampleService { 4 void setVal(int val); 5 int getVal(); 6}
這個文件定義了接口IExampleService,該接口提供了兩個函數setVal和getVal,後面咱們能夠看到,應用程序就是經過調用IExampleService接口的setVal和getVal函數,執行對硬件設備的寫和讀操做。
因爲硬件訪問服務接口IExampleService是使用AIDL語言描述的,所以,咱們須要將其添加到編譯腳本文件中,這樣編譯系統才能將其轉換爲JAVA文件,而後再對它進行編譯。進入frameworks/base目錄中,打開裏面的Android.mk文件,修改LOCAL_SRC_FILES變量的值:
… 192 voip/java/android/net/sip/ISipSessionListener.aidl \ 193 voip/java/android/net/sip/ISipService.aidl \ 194 core/java/android/os/IExampleService.aidl …
下面咱們就能夠執行以下命令對硬件訪問服務接口IExampleService進行編譯了:
# mmm frameworks/base/
編譯後獲得的framework.jar文件就包含有IExampleService接口,其實現文件是out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/IExampleService.java
打開這個文件,能夠看到IExampleService繼承了android.os.IInterface接口。在IExampleService接口內部,定義了一個Binder本地對象類Stub,它實現了IExampleService接口,而且繼承了android.os.Binder類。另外,在IExampleService.Stub類內部,還定義了一個Binder代理對象類Proxy,它一樣也實現了IExampleService接口。
前面咱們實現了硬件訪問服務接口,下面咱們來實現硬件訪問服務。在Android系統中,一般把硬件訪問服務實如今frameworks/base/services/java/com/android/server目錄中,進入這個目錄,建立ExampleService.java文件,其內容以下:
1package com.android.server; 2 3import android.content.Context; 4import android.os.IExampleService; 5import android.util.Slog; 6 7public class ExampleService extends IExampleService.Stub { 8 private static final String TAG = "ExampleService"; 9 10 private int mPtr = 0; 11 12 ExampleService() { 13 mPtr = init_native(); 14 15 if(mPtr == 0) { 16 Slog.e(TAG, "Failed to initialize example service."); 17 } 18 } 19 20 public void setVal(int val) { 21 if(mPtr == 0) { 22 Slog.e(TAG, "Example service is not initialized."); 23 return; 24 } 25 26 setVal_native(mPtr, val); 27 } 28 29 public int getVal() { 30 if(mPtr == 0) { 31 Slog.e(TAG, "Example service is not initialized."); 32 return 0; 33 } 34 35 return getVal_native(mPtr); 36 } 37 38 private static native int init_native(); 39 private static native void setVal_native(int ptr, int val); 40 private static native int getVal_native(int ptr); 41};
硬件訪問服務ExampleService繼承了IExampleService.Stub類,而且實現了IExampleService接口的成員函數setVal和getVal。其中,成員函數setVal經過調用JNI方法setVal_native來寫虛擬硬件設備example的寄存器val,而成員函數getVal調用JNI方法getVal_native來讀虛擬硬件設備example的寄存器val。
注意,硬件訪問服務ExampleService在啓動時,其構造函數的執行,會經過調用JNI方法init_native來打開虛擬硬件設備example,而且得到它的一個句柄值,保存在成員變量mPtr中。若是硬件訪問服務ExampleService打開虛擬硬件設備example失敗,那麼它的成員變量mPtr的值就等於0;不然,就獲得一個大於0的句柄值。這個句柄值其實是指向虛擬硬件設備example在硬件抽象層中的example_device_t對象,硬件訪問服務ExampleService的成員函數 setVal和getVal在訪問虛擬硬件設備example時,必需要指定這個句柄值,以便硬件訪問服務ExampleService的JNI實現能夠知道它所要訪問的是哪個硬件設備。
硬件訪問服務ExampleService編寫完成以後,就能夠執行mmm命令來從新編譯Android系統的services模塊了:
# mmm ./frameworks/base/services/java
編譯後獲得的services.jar文件就包含有ExampleService類。
硬件訪問服務是使用JAVA語言實現的,爲了訪問硬件,必須經過使用硬件抽象層(HAL)提供的接口,而硬件抽象層模塊是使用C++語言實現的,因此咱們必須實現硬件訪問服務ExampleService的JNI方法。
在Android系統中,一般把硬件訪問服務的JNI方法實如今frameworks/base/services/jni目錄下,進入這個目錄,建立com_android_server_ExampleService.cpp文件,內容以下:
1#define LOG_TAG "ExampleServiceJNI" 2 3#include "jni.h" 4#include "JNIHelp.h" 5#include "android_runtime/AndroidRuntime.h" 6 7#include <utils/misc.h> 8#include <utils/Log.h> 9#include <hardware/hardware.h> 10#include <hardware/example.h> 11 12#include <stdio.h> 13 14namespace android 15{ 16 static void example_setVal(JNIEnv* env, jobject clazz, jint ptr, jint value) { 17 example_device_t* device = (example_device_t*)ptr; 18 if(!device) { 19 LOGE("Device example is not open."); 20 return; 21 } 22 23 int val = value; 24 25 LOGI("Set value %d to device example.", val); 26 27 device->set_val(device, val); 28 } 29 30 static jint example_getVal(JNIEnv* env, jobject clazz, jint ptr) { 31 example_device_t* device = (example_device_t*)ptr; 32 if(!device) { 33 LOGE("Device example is not open."); 34 return 0; 35 } 36 37 int val = 0; 38 39 device->get_val(device, &val); 40 41 LOGI("Get value %d from device example.", val); 42 43 return val; 44 } 45 46 static inline int example_device_open(const hw_module_t* module, struct example_device_t** device) { 47 return module->methods->open(module, EXAMPLE_HARDWARE_DEVICE_ID, (struct hw_device_t**)device); 48 } 49 50 static jint example_init(JNIEnv* env, jclass clazz) { 51 example_module_t* module; 52 example_device_t* device; 53 54 LOGI("Initializing HAL stub example......"); 55 56 if(hw_get_module(EXAMPLE_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) { 57 LOGI("Device example found."); 58 if(example_device_open(&(module->common), &device) == 0) { 59 LOGI("Device example is open."); 60 return (jint)device; 61 } 62 63 LOGE("Failed to open device example."); 64 return 0; 65 } 66 67 LOGE("Failed to get HAL stub example."); 68 69 return 0; 70 } 71 72 static const JNINativeMethod method_table[] = { 73 {"init_native", "()I", (void*)example_init}, 74 {"setVal_native", "(II)V", (void*)example_setVal}, 75 {"getVal_native", "(I)I", (void*)example_getVal}, 76 }; 77 78 int register_android_server_ExampleService(JNIEnv *env) { 79 return jniRegisterNativeMethods(env, "com/android/server/ExampleService", method_table, NELEM(method_table)); 80 } 81};
在函數example_init中,首先經過Android硬件抽象層提供的hw_get_module函數來加載模塊ID爲EXAMPLE_HARDWARE_MODULE_ID的硬件抽象層模塊。函數hw_get_module最終返回一個hw_module_t接口給example_init函數,這個hw_module_t接口實際指向的是自定義的一個硬件抽象層模塊對象,即一個example_module_t對象。
函數example_init接着調用函數example_device_open來打開設備ID爲EXAMPLE_HARDWARE_DEVICE_ID的硬件設備,而example_device_open函數又是經過調用前面得到的hw_module_t接口的操做方法列表中的open函數來打開指定的硬件設備的。
函數example_init最後把得到的example_device_t接口轉換成一個整型句柄,返回給調用者。
函數example_setVal和example_getVal都是首先把參數ptr轉換爲一個example_device_t接口,而後分別調用它的成員函數set_val和get_val來訪問虛擬硬件設備example的寄存器val的值。
文件接着定義了一個JNI方法表method_table,分別將函數example_init、example_setVal和example_getVal的JNI方法註冊爲init_native、setVal_native和getVal_native。最後調用了jniRegisterNativeMethods函數把JNI方法表method_table註冊到Java虛擬機中,以便提供給硬件訪問服務ExampleService類使用。
硬件訪問服務ExampleService的JNI方法編寫完成以後,咱們還須要修改frameworks/base/services/jni目錄下的onload.cpp文件,在裏面增長register_android_server_ExampleService函數的聲明和調用,修改方法以下:
…… namespace android { …… int register_android_server_ExampleService(JNIEnv* env); }; …… extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { …… register_android_server_ExampleService(env); …… }
onload.cpp文件實如今libandroid_servers模塊中。當系統加載libandroid_servers模塊時,就會調用實如今onload.cpp文件中的JNI_OnLoad函數。這樣,就能夠將前面定義的三個JNI方法init_native、setVal_native和getVal_native註冊到Java虛擬機中。
最後,進入到frameworks/base/services/jni目錄中,打開裏面的Android.mk文件,修改變量LOCAL_SRC_FILES的值,以下:
…… LOCAL_SRC_FILES:= \ …… com_android_server_ExampleService.cpp \ onload.cpp ……
下面,咱們就能夠用mmm命令來從新編譯libandroid_servers模塊了。
# mmm frameworks/base/services/jni
編譯後獲得的libandroid_servers.so文件就包含有init_native、setVal_native和getVal_native這三個JNI方法了。
至此,硬件訪問服務ExampleService的實現就介紹完了。下面咱們繼續介紹如何在系統進程System中啓動它。
Android系統的硬件訪問服務一般是在系統進程System中啓動的,而系統進程System是由應用程序孵化器進程Zygote負責啓動的。因爲應用程序孵化器進程Zygote是在系統啓動時啓動的,所以,把硬件訪問服務運行在系統進程System中,就實現了開機時自動啓動。
爲了把硬件訪問服務ExampleService加入到系統進程System中,進入frameworks/base/services/java/com/android/server目錄,修改SystemServer.java文件,在ServerThread類的成員函數run中,添加以下內容:
…… 447 try { 448 Slog.i(TAG, "Example Service"); 449 ServiceManager.addService("example", new ExampleService()); 450 } catch (Throwable e) { 451 Slog.e(TAG, "Failure starting Example Service", e); 452 } ……
系統進程System在啓動時,會建立一個ServerThread線程來啓動系統中的關鍵服務,其中就包括一些硬件訪問服務。在ServerThread類的成員函數run中,首先建立一個ExampleService實例,而後把它註冊到Service Manager中。Service Manager是Android系統的Binder進程間通訊機制的一個重要角色,它負責管理系統中的服務對象。註冊到Service Manager中的服務對象都有一個對應的名稱,使用這些服務的Client進程就是經過這些名稱來向Service Manager請求它們的Binder代理對象接口的,以即可以訪問它們所提供的服務。硬件訪問服務ExampleService註冊到Service Manager以後,它的啓動過程就完成了。
最後,咱們須要執行mmm命令來從新編譯services模塊。
# mmm frameworks/base/services/java
編譯後獲得的services.jar文件就包含有硬件訪問服務ExampleService,而且在系統啓動時,將它運行在系統進程System中。
至此,硬件訪問服務ExampleService就徹底實現好了。咱們能夠執行make snod命令來從新打包Android系統鏡像文件system.img。
# make snod
下面,咱們來編寫一個應用程序,利用咱們提供的硬件訪問服務,經過硬件抽象層模塊,對底層硬件執行讀寫操做。這裏咱們只給出java源碼文件Example.java和佈局文件main.xml。
佈局文件main.xml的內容以下:
1<?xml version="1.0" encoding="utf-8"?> 2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent" 6 > 7 <LinearLayout 8 android:layout_width="fill_parent" 9 android:layout_height="wrap_content" 10 android:orientation="vertical" 11 android:gravity="center"> 12 <TextView 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:text="@string/value"> 16 </TextView> 17 <EditText 18 android:layout_width="fill_parent" 19 android:layout_height="wrap_content" 20 android:id="@+id/edit_value" 21 android:hint="@string/hint"> 22 </EditText> 23 </LinearLayout> 24 <LinearLayout 25 android:layout_width="fill_parent" 26 android:layout_height="wrap_content" 27 android:orientation="horizontal" 28 android:gravity="center"> 29 <Button 30 android:id="@+id/button_read" 31 android:layout_width="wrap_content" 32 android:layout_height="wrap_content" 33 android:text="@string/read"> 34 </Button> 35 <Button 36 android:id="@+id/button_write" 37 android:layout_width="wrap_content" 38 android:layout_height="wrap_content" 39 android:text="@string/write"> 40 </Button> 41 <Button 42 android:id="@+id/button_clear" 43 android:layout_width="wrap_content" 44 android:layout_height="wrap_content" 45 android:text="@string/clear"> 46 </Button> 47 </LinearLayout> 48</LinearLayout>
應用程序源碼文件Example.java的內容以下:
1package haoyu.hal.example; 2 3import android.app.Activity; 4import android.os.ServiceManager; 5import android.os.Bundle; 6import android.os.IExampleService; 7import android.os.RemoteException; 8import android.util.Log; 9import android.view.View; 10import android.view.View.OnClickListener; 11import android.widget.Button; 12import android.widget.EditText; 13 14public class Example extends Activity implements OnClickListener { 15 private final static String LOG_TAG = "haoyu.hal.example.ExampleActivity"; 16 17 private IExampleService exampleService = null; 18 19 private EditText valueText = null; 20 private Button readButton = null; 21 private Button writeButton = null; 22 private Button clearButton = null; 23 24 /** Called when the activity is first created. */ 25 @Override 26 public void onCreate(Bundle savedInstanceState) { 27 super.onCreate(savedInstanceState); 28 setContentView(R.layout.main); 29 30 exampleService = IExampleService.Stub.asInterface( 31 ServiceManager.getService("example")); 32 33 valueText = (EditText)findViewById(R.id.edit_value); 34 readButton = (Button)findViewById(R.id.button_read); 35 writeButton = (Button)findViewById(R.id.button_write); 36 clearButton = (Button)findViewById(R.id.button_clear); 37 38 readButton.setOnClickListener(this); 39 writeButton.setOnClickListener(this); 40 clearButton.setOnClickListener(this); 41 42 Log.i(LOG_TAG, "Example Activity Created"); 43 } 44 45 @Override 46 public void onClick(View v) { 47 if(v.equals(readButton)) { 48 try { 49 int val = exampleService.getVal(); 50 String text = String.valueOf(val); 51 valueText.setText(text); 52 } catch (RemoteException e) { 53 Log.e(LOG_TAG, "Remote Exception while reading value from example service."); 54 } 55 } 56 else if(v.equals(writeButton)) { 57 try { 58 String text = valueText.getText().toString(); 59 int val = Integer.parseInt(text); 60 exampleService.setVal(val); 61 } catch (RemoteException e) { 62 Log.e(LOG_TAG, "Remote Exception while writing value to example service."); 63 } 64 } 65 else if(v.equals(clearButton)) { 66 String text = ""; 67 valueText.setText(text); 68 } 69 } 70}
第17行,定義了IExampleService服務接口類型變量exampleService。
30-31行,取得example服務接口,賦值給exampleService。
49行,調用IExampleService服務接口提供的getVal函數,對底層硬件執行讀操做。
60行,調用IExampleService服務接口提供的setVal函數,對底層硬件執行寫操做。
這裏須要說明的是,我在執行應用程序對設備進行讀寫操做時,出現/dev/example設備不存在的錯誤提示,而實際上/dev/example設備是正常存在的。這是由於應用程序沒有訪問/dev/example的權限,爲此,咱們須要進行以下修改:
打開system/core/rootdir/ueventd.rc文件,在其中添加以下一行內容:
75/dev/example 0666 root root
這樣,咱們的應用程序就能夠找到/dev/example設備,並對其進行讀寫操做了。
最後,咱們從上到下,把執行流程進行一下梳理。
1、應用程序經過IExampleService服務接口提供的getVal/setVal函數來讀寫設備。
2、咱們經過AIDL語言定義了IExampleService服務接口。
3、有了IExampleService服務接口,咱們又在frameworks/base/services/java/com/android/server/ExampleService.java文件中實現了ExampleService服務。該服務經過調用JNI函數getVal_native和setVal_native實現了IExampleService服務接口提供的getVal/setVal函數。另外,ExampleService服務會在系統啓動時自動啓動,在服務的構造函數中,調用了JNI函數init_native進行初始化。
4、ExampleService服務是經過硬件抽象層模塊來訪問底層硬件的,可是ExampleService服務是用JAVA實現的,硬件抽象層模塊是用C++實現的,因此在二者之間,必須有JNI代碼。咱們在frameworks/base/services/jni/com_android_server_ExampleService.cpp文件中實現了JNI代碼,它起到了關聯ExampleService服務的JAVA代碼和硬件抽象層C++代碼的做用,在該文件中,定義了JNI函數init_native、setVal_native、getVal_native。這三個函數其實都是經過調用硬件抽象層模塊的相關函數來實現的。其中,init_native函數完成初始化工做,它負責找到硬件抽象層模塊example,並打開對應的設備。
5、再向下就是按照Android硬件抽象層的規則,編寫硬件抽象層模塊。在硬件抽象層模塊中,經過使用系統調用open、read、write等,完成對底層硬件的打開和讀寫操做。
6、在Linux內核驅動程序中,實現了對底層硬件的打開、讀寫等操做。