Android架構分析之使用自定義硬件抽象層(HAL)模塊

做者:劉昊昱  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內核驅動程序中,實現了對底層硬件的打開、讀寫等操做。

相關文章
相關標籤/搜索