Android中linux内核模块--开发设备驱动程序 && 上层接口实施 (二)

二、整合到android系统中


【前情摘要1】   Android的框架


                    



【前情摘要2】   Android的HAL层分析(hal归根结底仍然是以so文件的形式呈现给上层.....)


1、Android的HAL是为了一些硬件提供商提出的“保护proprietary”的驱动程序而产生的东东,简而言之,就是为了避开Linuxkernal的GPL license的束缚。Android把控制硬件的动作都放到了user space中,而在kernel driver里面只有最简单的读写寄存器的操作,而完全去掉了各种功能性的操作(比如控制逻辑等),这些能够体现硬件特性的操作都放到了Android的HAL层,而Android是基于Aparch的license,因此硬件厂商可以只提供二进制代码,所以说Android知识一个开放的平台,并不是一个开源的平台。



2、  Android的HAL的实现需要通过JNI(Java Native Intereface),JNI简单说就是java程序可以调用C/C++写的动态链接库,这样的话,HAL可以使用C/C++语言编写,效率更高。

        而Android的app(JNI)可以直接调用.so;也可以通过app->app_manager->service(java)->service(jni)->HAL来调用。第二种方法看上去很复杂,但是更加符合android的架构结构。

         Android的HAL的实现需要通过JNI(Java Native Interface),JNI简单来说就是java程序可以调用C/C++写的动态链接库,这样的话,HAL可以使用C/C++语言编写,效率更高。在Android下访问HAL大致有以下两种方式:

(1)Android的app可以直接通过service调用.so格式的jni:

(2)经过Manager调用service

        上面两种方法应该说是各有优缺点,第一种方法简单高效,但不正规。第二种方法实现起来比较复杂,但更符合目前的Android框架。第二种方法中,LegManager和LedService(java)在两个进程中,需要通过进程通讯的方式来通讯。

    mokoid工程中实现了上述两种方法。下面将详细介绍这两种方法的实现原理。

mokoid工程的结构分析

  |-- Android.mk  

  |-- apps      //两种应用测试方法

  |   |-- Android.mk

  |   |-- LedClient    //直接调用service来调用jni

  |   |   |-- AndroidManifest.xml

  |   |   |-- Android.mk

  |   |   `-- src

  |   |       `-- com

  |   |           `-- mokoid

  |   |               `-- LedClient

  |   |                   `-- LedClient.java  //第1种方式应用程序实现代码

  |   `-- LedTest        //通过manager来调用jni

  |       |-- AndroidManifest.xml

  |       |-- Android.mk

  |       `-- src

  |           `-- com

  |               `-- mokoid

  |                   `-- LedTest

  |                       |-- LedSystemServer.java  //开启了一个后台service,下文会有解释

  |                       `-- LedTest.java    //第2种方式应用程序实现代码

  |-- dma6410xp   //这个目录可以不要

  |   |-- AndroidBoard.mk

  |   |-- AndroidProducts.mk

  |   |-- BoardConfig.mk

  |   |-- dma6410xp.mk

  |   |-- init.dma6410xp.rc

  |   |-- init.goldfish.sh

  |   `-- init.rc

  |-- frameworks     //框架代码

  |   |-- Android.mk

  |   `-- base

  |       |-- Android.mk

  |       |-- core

  |       |   `-- java

  |       |       `-- mokoid

  |       |           `-- hardware

  |       |               |-- ILedService.aidl

  |       |               `-- LedManager.java     //实现了Manager,给第2种方法用

  |       `-- service  

  |           |-- Android.mk

  |           |-- com.mokoid.server.xml

  |           |-- java

  |           |   `-- com

  |           |       `-- mokoid

  |           |           `-- server

  |           |               `-- LedService.java    //Framework service代码

  |           `-- jni

  |               |-- Android.mk

  |               `-- com_mokoid_server_LedService.cpp  //jni代码

  |-- hardware

  |   |-- Android.mk

  |   |-- libled

  |   |   |-- Android.mk

  |   |   `-- libled.c

  |   `-- modules

  |       |-- Android.mk

  |       |-- include

  |       |   `-- mokoid

  |       |       `-- led.h

  |       `-- led

  |           |-- Android.mk

  |           `-- led.c       //led stub 硬件控制代码

  `-- README.txt


3、

1)Kernel Driver

       这里的kernel driver相对于linux真正的driver形式上是一样的,也提供open,read,write,ioctl,mmap等接口,就可以只作成往寄存器写操作,至于如何写,为什么写,这些工作都会在HAL层进行的,而一般用户是看不到这些代码的。这也是linux mainstream把android的kernel踢出去的原因,因为这些driver根本无法用在其他的linux平台上。


2)这一层就位于kernel之上的user space了,一般来说这里需要涉及的是两个结构体:hw_module_t和hw_device_t,第一个结构体是当这个hardware stub被load的时候(hw_get_module())提供的初始化操作,比如提供stub的open(module->methods->open())操作,而第二个结构体是提供该硬件stub具有的操作硬件的接口,,在jollen的mokoid工程里,主要提供打开和关闭led的操作,文件就是led.h和文件led.c,这两个文件最后会被编译成动态链接库,不如libled.so被放到/system/libs/hw/,当service调用hw_get_module(hardware/libhardware/hardware.c)时,会在/system/libs/hw/里面寻找对应的动态链接库,然后提供给service对应的操作接口。




HAL的实现实例1】()--Android的app可以直接通过service调用.so格式的jni:


第一种方法:直接调用service方法的实现过程

      下面分析第一种方法中,各层的关键代码。

1HAL

      一般来说HAL moudle需要涉及的是三个关键结构体:

  struct hw_module_t;

  struct hw_module_methods_t;

  struct hw_device_t;

      下面结合代码说明这3个结构的用法。部分代码经过修改,后面的章节会给出修改的原因。

  文件:mokoid-read-only/hardware/modules/include/mokoid/led.h 

  



struct led_module_t {  
struct hw_module_t common;  
};  
//HAL 规定不能直接使用hw_module_t结构,因此需要做这么一个继承。
struct led_control_device_t {    
//自定义的一个针对Led控制的结构,包含hw_device_t和支持的API操作
struct hw_device_t common;  
/* attributes */
int fd;  //可用于具体的设备描述符
/* supporting control APIs go here */
int (*set_on)(struct led_control_device_t *dev, int32_t led);  
int (*set_off)(struct led_control_device_t *dev, int32_t led);  
};
#define LED_HARDWARE_MODULE_ID "led"  
//定义一个MODULE_ID,HAL层可以根据这个ID找到我们这个HAL stub

  文件:mokoid-read-only/hardware/modules/led/led.c

  

#define LOG_TAG "MokoidLedStub"
#include <hardware/hardware.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
//#include <mokoid/led.h>
#include "../include/mokoid/led.h"
/*****************************************************************************/
int fd;             //硬件led的设备描述符 。你也可以用led_control_device_t结构中定义的fd
#define GPG3DAT2_ON 0x4800                 //ioctl控制命令
#define GPG3DAT2_OFF 0x4801
int led_device_close(struct hw_device_t* device)  
{  
struct led_control_device_t* ctx = (struct led_control_device_t*)device;  
if (ctx) {  
        free(ctx);  
    }  
    close(fd);  
return 0;  
}  
int led_on(struct led_control_device_t *dev, int32_t led)  
{  
    LOGI("LED Stub: set %d on.", led);  
    ioctl(fd,GPG3DAT2_ON,NULL);           //控制Led亮灭,和硬件相关
return 0;  
}  
int led_off(struct led_control_device_t *dev, int32_t led)  
{  
    LOGI("LED Stub: set %d off.", led);  
return 0;  
}  
staticint led_device_open(conststruct hw_module_t* module, constchar* name,  
struct hw_device_t** device)   
{  
struct led_control_device_t *dev;  
    dev = (struct led_control_device_t *)malloc(sizeof(*dev));  
    memset(dev, 0, sizeof(*dev));  
    dev->common.tag =  HARDWARE_DEVICE_TAG;  
    dev->common.version = 0;  
    dev->common.module = module;  
    dev->common.close = led_device_close;  
    dev->set_on = led_on;        //实例化支持的操作
    dev->set_off = led_off;  
    *device = &dev->common;     //将实例化后的led_control_device_t地址返回给jni层
//这样jni层就可以直接调用led_on、led_off、led_device_close方法了。
if((fd=open("/dev/led",O_RDWR))==-1)      //打开硬件设备
    {  
        LOGE("LED open error");  
    }  
else
        LOGI("open ok");  
success:  
return 0;  
}  
staticstruct hw_module_methods_t led_module_methods = {  
    open: led_device_open  
};  
conststruct led_module_t HAL_MODULE_INFO_SYM = {  
//定义这个对象等于向系统注册了一个ID为LED_HARDWARE_MODULE_ID的stub。注意这里HAL_MODULE_INFO_SYM的名称不能改。
    common: {  
        tag: HARDWARE_MODULE_TAG,  
        version_major: 1,  
        version_minor: 0,  
        id: LED_HARDWARE_MODULE_ID,  
        name: "Sample LED Stub",  
        author: "The Mokoid Open Source Project",  
        methods: &led_module_methods,  //实现了一个open的方法供jni层调用,
//从而实例化led_control_device_t
    }  
/* supporting APIs go here */
};  

2JNI

  文件:mokoid-read-only/frameworks/base/service/jni/com_mokoid_server_LedService.cpp

  

struct led_control_device_t *sLedDevice = NULL;  

static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led)   
{  
    LOGI("LedService JNI: mokoid_setOn() is invoked.");  

if (sLedDevice == NULL) {  
        LOGI("LedService JNI: sLedDevice was not fetched correctly.");  
return -1;  
    } else {  
return sLedDevice->set_on(sLedDevice, led);//调用hal层的注册的方法
    }  
}  

static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led)   
{  
    LOGI("LedService JNI: mokoid_setOff() is invoked.");  


if (sLedDevice == NULL) {  
        LOGI("LedService JNI: sLedDevice was not fetched correctly.");  
return -1;  
    } else {  
return sLedDevice->set_off(sLedDevice, led); //调用hal层的注册的方法
    }  
}  

/** helper APIs */
static inline int led_control_open(conststruct hw_module_t* module,  
struct led_control_device_t** device) {  
return module->methods->open(module,  
            LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);  
//这个过程非常重要,jni通过LED_HARDWARE_MODULE_ID找到对应的stub
}  

static jboolean mokoid_init(JNIEnv *env, jclass clazz)  
{  
    led_module_t* module;  
     LOGI("jni init-----------------------.");  
if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {  
//根据LED_HARDWARE_MODULE_ID找到hw_module_t,参考hal层的实现
        LOGI("LedService JNI: LED Stub found.");  
if (led_control_open(&module->common, &sLedDevice) == 0) {    
//通过hw_module_t找到led_control_device_t
            LOGI("LedService JNI: Got Stub operations.");  
return 0;  
        }  
    }  

    LOGE("LedService JNI: Get Stub operations failed.");  
return -1;  
}  

/*
 * Array of methods.
* Each entry has three fields: the name of the method, the method
 * signature, and a pointer to the native implementation.
 */
staticconst JNINativeMethod gMethods[] = {  
    { "_init",      "()Z",  (void *)mokoid_init },//Framework层调用_init时促发
    { "_set_on",        "(I)Z", (void *)mokoid_setOn },  
    { "_set_off",       "(I)Z", (void *)mokoid_setOff },  
};  
/*
*JNINativeMethod是jni层注册的方法,Framework层可以使用这些方法
*_init 、_set_on、_set_off是在Framework中调用的方法名称,函数的类型及返回值如下:
*()Z   无参数    返回值为bool型
* (I)Z   整型参数  返回值为bool型
*/
staticint registerMethods(JNIEnv* env) {  
staticconstcharconst kClassName =  
"com/mokoid/server/LedService";//注意:必须和你Framework层的service类名相同
        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;  
}   
jint JNI_OnLoad(JavaVM* vm, void* reserved) {//Framework层加载jni库时调用 
        JNIEnv* env = NULL;  
        jint result = -1;  
        LOGI("JNI_OnLoad LED");  
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
            LOGE("ERROR: GetEnv failed/n");  
goto fail;  
        }  
            assert(env != NULL);  
if (registerMethods(env) != 0) { //注册你的JNINativeMethod
            LOGE("ERROR: PlatformLibrary native registration failed/n");  
goto fail;  
        }  
/* success -- return valid version number */
        result = JNI_VERSION_1_4;  
fail:  
return result;  
}  

  3service  属于Framework

  文件:frameworks/base/service/java/com/mokoid/server/LedService.java

  

package com.mokoid.server;  
import Android.util.Config;  
import android.util.Log;  
import ntent.Context;  
import android.os.Binder;  
import android.os.Bundle;  
import android.os.RemoteException;  
import android.os.IBinder;  
import mokoid.hardware.ILedService;  
public final class LedService extends ILedService.Stub {  
//对于这种直接模式不需要进程通讯,所以可以不加extends ILedService.Stub,此处加上主要是为了后面的第二种模式.
static {  
        System.load("/system/lib/libmokoid_runtime.so");//加载jni的动态库
    }  
public LedService() {  
        Log.i("LedService", "Go to get LED Stub...");  
    _init();  
    }  
/*
     * Mokoid LED native methods.
     */
public boolean setOn(int led) {  
        Log.i("MokoidPlatform", "LED On");  
return _set_on(led);  
    }  
public boolean setOff(int led) {  
        Log.i("MokoidPlatform", "LED Off");  
return _set_off(led);  
    }  
private static native boolean _init();          //声明jni库可以提供的方法
private static native boolean _set_on(int led);  
private static native boolean _set_off(int led);  


4APP 测试程序 (属于APP

  文件:apps/LedClient/src/com/mokoid/LedClient/LedClient.java


package com.mokoid.LedClient;  
import com.mokoid.server.LedService;// 导入Framework层的LedService
import android.app.Activity;  
import android.os.Bundle;  
import android.widget.TextView;  

publicclass LedClient extends Activity {  
    @Override  
publicvoid onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
// Call an API on the library.
    LedService ls = new LedService();  //实例化LedService
    ls.setOn(1);                       //通过LedService提供的方法,控制底层硬件
    ls.setOff(2);  

        TextView tv = new TextView(this);  
        tv.setText("LED 1 is on. LED 2 is off.");  
        setContentView(tv);  
    }  
}  








HAL的实现实例2】()--经过Manager调用service

第二种方法:经过Manager调用service

      HAL、JNI两层和第一种方法一样,所以后面只分析其他的层次。

1)Manager 属于Framework

      APP通过这个Manager和service通讯。

  文件:mokoid-read-only /frameworks/base/core/java/mokoid/hardware/LedManager.java 

  



package mokoid.hardware;  
import ntent.Context;  
import android.os.Binder;  
import android.os.Bundle;  
import android.os.Parcelable;  
import android.os.ParcelFileDescriptor;  
import android.os.Process;  
import android.os.RemoteException;  
import android.os.Handler;  
import android.os.Message;  
import android.os.ServiceManager;  
import android.util.Log;  
import mokoid.hardware.ILedService;  

/*
 * Class that lets you access the Mokoid LedService.
 */
publicclass LedManager  
{  
privatestatic final String TAG = "LedManager";  
private ILedService mLedService;  
public LedManager() {  
        mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));  
/*
*这一步是关键,利用ServiceManager获取到LedService,从而调用它提供的方法。这要求LedService必
*须已经添加到了ServiceManager中,这个过程将在App中的一个service进程中完成。
*/
if (mLedService != null) {  
            Log.i(TAG, "The LedManager object is ready.");  
    }  
    }  
public boolean LedOn(int n) {  
        boolean result = false;  
try {  
            result = mLedService.setOn(n);  
        } catch (RemoteException e) {  
            Log.e(TAG, "RemoteException in LedManager.LedOn:", e);  
        }  
return result;  
    }  
public boolean LedOff(int n) {  
        boolean result = false;  
try {  
            result = mLedService.setOff(n);  
        } catch (RemoteException e) {  
            Log.e(TAG, "RemoteException in LedManager.LedOff:", e);  
        }  
return result;  
    }  
}  

  因为LedService和LedManager在不同的进程,所以要考虑到进程通讯的问题。Manager通过增加一个aidl文件来描述通讯接口。

  

  文件:mokoid-read-only/frameworks/base/core/java/mokoid/hardware/ILedService.aidl

  

package mokoid.hardware;  
interface ILedService  
{  
    boolean setOn(int led);  
    boolean setOff(int led);  
}  
//系统的aidl工具会将ILedService.aidl文件ILedService.java文件,实现了ILedService

2)SystemServer (属于APP层)

  文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedSystemServer.java

  

package com.mokoid.LedTest;  
import com.mokoid.server.LedService;  
import android.os.IBinder;  
import android.os.ServiceManager;  
import android.util.Log;  
import android.app.Service;  
import ntent.Context;  
import ntent.Intent;  

publicclass LedSystemServer extends Service {  
//注意这里的Service是APP中的概念,代表一个后台进程。注意区别和Framework中的service的概念。
    @Override  
public IBinder onBind(Intent intent) {  
returnnull;  
publicvoid onStart(Intent intent, int startId) {  
        Log.i("LedSystemServer", "Start LedService...");  

/* Please also see SystemServer.java for your interests. */
    LedService ls = new LedService();  
try {  
            ServiceManager.addService("led", ls);  //将LedService添加到ServiceManager中
        } catch (RuntimeException e) {  
            Log.e("LedSystemServer", "Start LedService failed.");  
        }  
    }  
}  

3)APP 测试程序(属于APP层)

  文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java

  

package com.mokoid.LedTest;  
import mokoid.hardware.LedManager;  
import com.mokoid.server.LedService;  
import android.app.Activity;  
import android.os.Bundle;  
import android.util.Log;  
import android.widget.TextView;  
import android.widget.Button;  
import ntent.Intent;  
import android.view.View;  

publicclass LedTest extends Activity implements View.OnClickListener {  
private LedManager mLedManager = null;  
    @Override  
publicvoid onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
// Start LedService in a seperated process.
        startService(new Intent("com.mokoid.systemserver"));//开启后台进程
        Button btn = new Button(this);  
        btn.setText("Click to turn LED 1 On");  
     btn.setOnClickListener(this);  
        setContentView(btn);  
    }  
publicvoid onClick(View v) {  
// Get LedManager.
if (mLedManager == null) {  
        Log.i("LedTest", "Creat a new LedManager object.");  
        mLedManager = new LedManager();  //实例化Framework层中的Manager
        }      
if (mLedManager != null) {  
        Log.i("LedTest", "Got LedManager object.");  
     }  
/** Call methods in LedService via proxy object 
         * which is provided by LedManager. 
         */
        mLedManager.LedOn(1);  
        TextView tv = new TextView(this);  
        tv.setText("LED 1 is On.");  
        setContentView(tv);  
    }  
}  




辅助:实例分析(--经过Manager调用service

老罗的Android之旅http://blog.csdn.net/lxl584685501/article/details/45972991

1.在Ubuntu上为Android系统编写Linux内核驱动程序 :

          驱动程序的功能主要是向上层提供访问设备的寄存器的值,包括读和写。

          这里,提供了三种访问设备寄存器的方法,一是通过proc文件系统来访问,二是通过传统的设备文件的方法来访问,三是通过devfs文件系统来访问。

         完成这个内核驱动程序后,便可以在Android系统中得到三个文件,分别是/dev/hello、/sys/class/hello/hello/val和/proc/hello


                            (测试程序:在Android系统中增加C可执行程序来访问硬件驱动程序。)


2.在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序



3.为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口


4.在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务


5.为Android系统内置Java应用程序测试Application Frameworks层的硬件服务




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值