您的位置:首页 > 编程语言 > Java开发

Hardware-javaaplication.

2015-08-06 09:40 225 查看
eg:hello

一:Hardware

//作用,向系统申请设备号,设备节点实体化file_operations,cdv

struct cdev{

dev_t dev;

};



static struct file_operations hello_ops={

.owner = THIS_MODULE,

.ioctl = hello_ioctl,

.read = hello_read,

.write = hello_write,

.open = hello_open,

......

};



static __init xxx_init() 模块加载函数

{

}

static __exit xxx_exit() 模块卸载函数

{

}

module_init(hello_init);

module_exit(hello_exit);

二:HAL

/*

Android硬件抽象层规范的要求,

分别定义模块ID、模块结构体以及硬件接口结构体。

在硬件接口结构体中,fd表示设备文件描述符,对应我们将要处理的设备文件"/dev/hello",

set_val和get_val为该HAL对上提供的函数接口。

__BEGIN_DECLS

*/

/*定义模块ID*/

#define HELLO_HARDWARE_MODULE_ID "hello"

/*硬件模块结构体*/

struct hello_module_t {

struct hw_module_t common;

};

/*硬件接口结构体*/

struct hello_device_t {

struct hw_device_t common;

int fd;

int (*set_val)(struct hello_device_t* dev, int val);

int (*get_val)(struct hello_device_t* dev, int* val);

};

/*设备打开和关闭接口*/

static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);

static int hello_device_close(struct hw_device_t* device);



/*设备访问接口*/

static int hello_set_val(struct hello_device_t* dev, int val);

static int hello_get_val(struct hello_device_t* dev, int* val);



/*模块方法表*/

static struct hw_module_methods_t hello_module_methods = {

open: hello_device_open

};



/*模块实例变量*/

struct hello_module_t HAL_MODULE_INFO_SYM = {

common: {

tag: HARDWARE_MODULE_TAG,

version_major: 1,

version_minor: 0,

id: HELLO_HARDWARE_MODULE_ID,

name: MODULE_NAME,

author: MODULE_AUTHOR,

methods: &hello_module_methods,

}

};

//这里,实例变量名必须为HAL_MODULE_INFO_SYM,tag也必须为HARDWARE_MODULE_TAG,这是Android硬件抽象层规范规定的



//定义hello_device_open函数:

static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {

struct hello_device_t* dev;

dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));



if(!dev) {

LOGE("Hello Stub: failed to alloc space");

return -EFAULT;

}



memset(dev, 0, sizeof(struct hello_device_t));

dev->common.tag = HARDWARE_DEVICE_TAG;

dev->common.version = 0;

dev->common.module = (hw_module_t*)module;

dev->common.close = hello_device_close;

dev->set_val = hello_set_val;

dev->get_val = hello_get_val;



if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {

LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));free(dev);

return -EFAULT;

}



*device = &(dev->common);

LOGI("Hello Stub: open /dev/hello successfully.");



return 0;

}

//DEVICE_NAME定义为"/dev/hello"。由于设备文件是在内核驱动里面通过device_create创建的,

//而device_create创建的设备文件默认只有root用户可读写,而hello_device_open一般是由上层APP来调用的,

//这些APP一般不具有root权限,这时候就导致打开设备文件失败

//解决办法是类似于Linux的udev规则,打开Android源代码工程目录下,进入到system/core/rootdir目录,

//里面有一个名为ueventd.rc文件,往里面添加一行:

/dev/hello 0666 root root

//定义hello_device_close、hello_set_val和hello_get_val这三个函数:

static int hello_device_close(struct hw_device_t* device) {

struct hello_device_t* hello_device = (struct hello_device_t*)device;



if(hello_device) {

close(hello_device->fd);

free(hello_device);

}



return 0;

}



static int hello_set_val(struct hello_device_t* dev, int val) {

LOGI("Hello Stub: set value %d to device.", val);



write(dev->fd, &val, sizeof(val));



return 0;

}



static int hello_get_val(struct hello_device_t* dev, int* val) {

if(!val) {

LOGE("Hello Stub: error val pointer");

return -EFAULT;

}



read(dev->fd, val, sizeof(*val));



LOGI("Hello Stub: get value %d from device", *val);



return 0;

}

三:JNI

/*

Android的Application Frameworks层提供硬件服务

Java应用程序通过JNI来调用硬件抽象层接口

准备好硬件抽象层模块,确保Android系统镜像文件system.img已经包含hello.default模块。

二. 进入到frameworks/base/services/jni目录,新建com_android_server_HelloService.cpp文件:

在com_android_server_HelloService.cpp文件中,实现JNI方法。注意文件的命令方法,com_android_server前缀表示的是包名,表示硬件服务HelloService是放在frameworks/base/services/java目录下的com/android/server目录的,即存在一个命令为com.android.server.HelloService的类。这里,我们暂时略去HelloService类的描述,在下一篇文章中,我们将回到HelloService类来。简单地说,HelloService是一个提供Java接口的硬件访问服务类。

接着定义hello_init、hello_getVal和hello_setVal三个JNI方法:

*/

namespace android

{

/*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h>*/

struct hello_device_t* hello_device = NULL;

/*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/

static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {

int val = value;

LOGI("Hello JNI: set value %d to device.", val);

if(!hello_device) {

LOGI("Hello JNI: device is not open.");

return;

}



hello_device->set_val(hello_device, val);

}

/*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/

static jint hello_getVal(JNIEnv* env, jobject clazz) {

int val = 0;

if(!hello_device) {

LOGI("Hello JNI: device is not open.");

return val;

}

hello_device->get_val(hello_device, &val);



LOGI("Hello JNI: get value %d from device.", val);



return val;

}

/*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/

static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) {

return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);

}

/*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/

static jboolean hello_init(JNIEnv* env, jclass clazz) {

hello_module_t* module;



LOGI("Hello JNI: initializing......");

if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {

LOGI("Hello JNI: hello Stub found.");

if(hello_device_open(&(module->common), &hello_device) == 0) {

LOGI("Hello JNI: hello device is open.");

return 0;

}

LOGE("Hello JNI: failed to open hello device.");

return -1;

}

LOGE("Hello JNI: failed to get hello stub module.");

return -1;

}

/*JNI方法表*/

static const JNINativeMethod method_table[] = {

{"init_native", "()Z", (void*)hello_init},

{"setVal_native", "(I)V", (void*)hello_setVal},

{"getVal_native", "()I", (void*)hello_getVal},

};

/*注册JNI方法*/

int register_android_server_HelloService(JNIEnv *env) {

return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));

}

};

注意,在hello_init函数中,通过Android硬件抽象层提供的hw_get_module方法来加载模块ID为HELLO_HARDWARE_MODULE_ID的硬件抽象层模块,其中,HELLO_HARDWARE_MODULE_ID是在<hardware/hello.h>中定义的。Android硬件抽象层会根据HELLO_HARDWARE_MODULE_ID的值在Android系统的/system/lib/hw目录中找到相应的模块,然后加载起来,并且返回hw_module_t接口给调用者使用。在jniRegisterNativeMethods函数中,第二个参数的值必须对应HelloService所在的包的路径,即com.android.server.HelloService。



三. 修改同目录下的onload.cpp文件,首先在namespace android增加register_android_server_HelloService函数声明:



namespace android {



..............................................................................................



int register_android_server_HelloService(JNIEnv *env);



};



在JNI_onLoad增加register_android_server_HelloService函数调用:

extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved)

{

.................................................................................................

register_android_server_HelloService(env);

.................................................................................................

}

这样,在Android系统初始化时,就会自动加载该JNI方法调用表。

四. 修改同目录下的Android.mk文件,在LOCAL_SRC_FILES变量中增加一行:

LOCAL_SRC_FILES:= \

com_android_server_AlarmManagerService.cpp \

com_android_server_BatteryService.cpp \

com_android_server_InputManager.cpp \

com_android_server_LightsService.cpp \

com_android_server_PowerManagerService.cpp \

com_android_server_SystemServer.cpp \

com_android_server_UsbService.cpp \

com_android_server_VibratorService.cpp \

com_android_server_location_GpsLocationProvider.cpp \

com_android_server_HelloService.cpp /

onload.cpp

五. 编译和重新找亿system.img:

USER-NAME@MACHINE-NAME:~/Android$ mmm frameworks/base/services/jni

USER-NAME@MACHINE-NAME:~/Android$ make snod

这样,重新打包的system.img镜像文件就包含我们刚才编写的JNI方法了,也就是我们可以通过Android系统的Application Frameworks层提供的硬件服务HelloService来调用这些JNI方法,进而调用低层的硬件抽象层接口去访问硬件了。前面提到,在这篇文章中,我们暂时忽略了HelloService类的实现,在下一篇文章中,我们将描述如何实现硬件服务HelloService,敬请关注。

四:java Frameworks

/*

一:

我们要先定义好通信接口。进入到frameworks/base/core/java/android/os目录

新增IHelloService.aidl接口定义文件:

IHelloService接口主要提供了设备和获取硬件寄存器val的值的功能,分别通过setVal和getVal两个函数来实现。

eg

*/

package android.os;

interface IHelloService {

void setVal(int val);

int getVal();

}



/*



返回到frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IHelloService.aidl源文件:

eg

*/

core/java/android/os/IHelloService.aidl /

/*



编译IHelloService.aidl接口:

USER-NAME@MACHINE-NAME:~/Android$ mmm frameworks/base

这样,就会根据IHelloService.aidl生成相应的IHelloService.Stub接口。

*/

/*



.进入到frameworks/base/services/java/com/android/server目录,新增HelloService.java文件:

HelloService主要是通过调用JNI方法init_native、setVal_native和getVal_native

(见在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口一文)来提供硬件服务。

*/

package com.android.server;

import android.content.Context;

import android.os.IHelloService;

import android.util.Slog;

public class HelloService extends IHelloService.Stub {

private static final String TAG = "HelloService";

HelloService() {

init_native();

}

public void setVal(int val) {

setVal_native(val);

}

public int getVal() {

return getVal_native();

}



private static native boolean init_native();

private static native void setVal_native(int val);

private static native int getVal_native();

};

/*

五. 修改同目录的SystemServer.java文件,在ServerThread::run函数中增加加载HelloService的代码:

*/

try {



Slog.i(TAG, "Hello Service");



ServiceManager.addService("hello", new HelloService());



} catch (Throwable e) {



Slog.e(TAG, "Failure starting Hello Service", e);



}

/*

七. 编译HelloService和重新打包system.img:



USER-NAME@MACHINE-NAME:~/Android$ mmm frameworks/base/services/java



USER-NAME@MACHINE-NAME:~/Android$ make snod



这样,重新打包后的system.img系统镜像文件就在Application Frameworks层中包含了我们自定义的硬件服务HelloService了,并且会在系统启动的时候,自动加载HelloService。这时,应用程序就可以通过Java接口来访问Hello硬件服务了。我们将在下一篇文章中描述如何编写一个Java应用程序来调用这个HelloService接口来访问硬件,敬请期待。





*/

五:Application

/*

我们将在Android系统的应用层增加一个内置的应用程序,

这个内置的应用程序通过ServiceManager接口获取指定的服务,然后通过这个服务来获得硬件服务。

*/

package shy.luo.hello;



import shy.luo.hello.R;

import android.app.Activity;

import android.os.ServiceManager;

import android.os.Bundle;

import android.os.IHelloService;

import android.os.RemoteException;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;



public class Hello extends Activity implements OnClickListener {

private final static String LOG_TAG = "shy.luo.renju.Hello";



private IHelloService helloService = null;



private EditText valueText = null;

private Button readButton = null;

private Button writeButton = null;

private Button clearButton = null;



/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);



helloService = IHelloService.Stub.asInterface(

ServiceManager.getService("hello"));



valueText = (EditText)findViewById(R.id.edit_value);

readButton = (Button)findViewById(R.id.button_read);

writeButton = (Button)findViewById(R.id.button_write);

clearButton = (Button)findViewById(R.id.button_clear);



readButton.setOnClickListener(this);

writeButton.setOnClickListener(this);

clearButton.setOnClickListener(this);



Log.i(LOG_TAG, "Hello Activity Created");

}



@Override

public void onClick(View v) {

if(v.equals(readButton)) {

try {

int val = helloService.getVal();

String text = String.valueOf(val);

valueText.setText(text);

} catch (RemoteException e) {

Log.e(LOG_TAG, "Remote Exception while reading value from device.");

}

}

else if(v.equals(writeButton)) {

try {

String text = valueText.getText().toString();

int val = Integer.parseInt(text);

helloService.setVal(val);

} catch (RemoteException e) {

Log.e(LOG_TAG, "Remote Exception while writing value to device.");

}

}

else if(v.equals(clearButton)) {

String text = "";

valueText.setText(text);

}

}

}

/*

程序通过ServiceManager.getService("hello")来获得HelloService,

接着通过IHelloService.Stub.asInterface函数转换为IHelloService接口。

其中,服务名字“hello”是系统启动时加载HelloService时指定的,

而IHelloService接口定义在android.os.IHelloService中,

具体可以参考在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务一文。

这个程序提供了简单的读定自定义硬件有寄存器val的值的功能,

通过IHelloService.getVal和IHelloService.setVal两个接口实现。

*/

ServiceManager.addService("hello", new HelloService());

ServiceManager.getService("hello")

public class HelloService extends IHelloService.Stub {}



helloService = IHelloService.Stub.asInterface(

ServiceManager.getService("hello"));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: