• Android架构分析之使用自定义硬件抽象层(HAL)模块


    作者:刘昊昱 

    博客:http://blog.csdn.net/liuhaoyutz

    Android版本:2.3.7_r1

    Linux内核版本:android-goldfish-2.6.29

     

    在上一篇博客《Android架构分析之硬件抽象层(HAL)》中,我们了解了硬件抽象层的基本数据结构和模块编写规则,现在,我们就来看怎样编写一个自定义的硬件抽象层模块并加入到Android系统中,同时,我们还要介绍应用程序怎样使用我们自定义的硬件抽象层模块。

    硬件抽象层的作用是给上层应用程序提供一个访问硬件设备的接口,在本文中,我们要操作的硬件设备是在前面博客文章中创建的/dev/example,该设备的内核驱动的实现可以参考《Android架构分析之Android驱动程序开发》一文。

    首先,我们来创建自定义的硬件抽象层模块,同硬件设备名一样,将其命名为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函数用来读取设备寄存器。

     

    接下来,进入hardware/libhardware/modules目录,创建一个example目录,再在example目录下创建Android.mk和example.cpp两个文件。

    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设备,并对其进行读写操作了。

     

    最后,我们从上到下,把执行流程进行一下梳理。

    一、应用程序通过IExampleService服务接口提供的getVal/setVal函数来读写设备。

     

    二、我们通过AIDL语言定义了IExampleService服务接口。

     

    三、有了IExampleService服务接口,我们又在frameworks/base/services/java/com/android/server/ExampleService.java文件中实现了ExampleService服务。该服务通过调用JNI函数getVal_native和setVal_native实现了IExampleService服务接口提供的getVal/setVal函数。另外,ExampleService服务会在系统启动时自动启动,在服务的构造函数中,调用了JNI函数init_native进行初始化。

     

    四、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,并打开对应的设备。

     

    五、再向下就是按照Android硬件抽象层的规则,编写硬件抽象层模块。在硬件抽象层模块中,通过使用系统调用open、read、write等,完成对底层硬件的打开和读写操作。

     

    六、在Linux内核驱动程序中,实现了对底层硬件的打开、读写等操作。

  • 相关阅读:
    Cocos Creator 脚本模板
    Cocos Creator学习四:按钮响应事件
    cocos2dx AudioEngine在Android7上播放音效卡顿问题处理
    WebStorm Error : program path not specified
    异常上报工具:腾讯Bugly
    Lua报错:invalid key to 'next'
    cocos2dx 如何获得节点的类型
    不要在Lua中使用os.clock()函数
    Windows下使用创建多层文件夹 SHCreateDirectoryEx 函数需要注意的问题
    Eclipse Jee环境配置
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3149628.html
Copyright © 2020-2023  润新知