通常情况下,开发好硬件抽象层模块后,通常需要在应用程序宽假层中实现一个硬件访问服务!
硬件访问服务通过硬件抽象层模块来为应用程序提供硬件读写操作。
由于硬件抽象层模块式使用C/C++语言来开发,应用程序框架层中的硬件访问服务是使用java语言来开发,
因此,硬件访问服务需要通过java接口(JNI)来调用硬件抽象层模块!
(1):定义硬件访问接口 (以下内容涉及aidl,有兴趣的读者可以看一下android应用的远程service相关的内容)
在Android系统中,通常把硬件访问服务接口定义在frameworks/base/core/java/android/os目录中,所有在这里,我们把服务接口 --zhx_print_service.aidl也保存到这里!内容:
frameworks/base/core/java/android/os/zhx_print_service.aidl
package android.os;
interface zhx_print_service
{
void setVal(int val);
int getVal();
}
然后再frameworks/base/目录中,打开里面的Android.mk文件修改LOCAL_SRC_FILES变量。
interface zhx_print_service
{
void setVal(int val);
int getVal();
}
LOCAL_SRC_FILES += \
...
voip/java/android/net/sip/ISipService.aidl \
core/java/android/os/zhx_print_service.aidl
...
voip/java/android/net/sip/ISipService.aidl \
core/java/android/os/zhx_print_service.aidl
接在在当前目录下编译该硬件访问服务接口,操作如下:
ics/frameworks/base$ mm
通过上面操作后,编译后得到的framework.jar文件就会包括zhx_print_service接口了!!!
(2):实现硬件访问服务 (就相当于定义一些可以给java调用的函数!)
frameworks/base/service/java/com/android/server/zhx_Print_Service.java
package com.android.server;
import android.content.Context;
import android.util.Slog;
import android.os.zhx_print_service;
public class zhx_Print_Service extends zhx_print_service.Stub
{
private static final String TAG ="zhx Service : ";
private int mPtr = 0;
zhx_Print_Service()
{
/*zhx_print_init 为jni层函数,该函数通过调用HAL层函数实现对驱动的调用*/
mPtr = zhx_print_init();
if(mPtr != 0)
{
Slog.e(TAG,"Failed to initialize freg service.");
}
}
public void setVal(int val)
{
if(zhx_print_set_val(val)== 0)
{
Slog.i(TAG,"done with the setting");
}
else
{
Slog.e(TAG,"setting val error");
}
}
public int getVal()
{
int val = 0;
Slog.i(TAG,"before to get,the val is "+val);
val = zhx_print_get_val();
Slog.i(TAG,"get the val by the \"zhx_print_get_val val\" = "+val);
return val;
}
//声明以下函数时JNI层中定义
public native int zhx_print_get_val();
public native int zhx_print_set_val(int val);
public native int zhx_print_init();
}
import android.content.Context;
import android.util.Slog;
import android.os.zhx_print_service;
public class zhx_Print_Service extends zhx_print_service.Stub
{
private static final String TAG ="zhx Service : ";
private int mPtr = 0;
zhx_Print_Service()
{
/*zhx_print_init 为jni层函数,该函数通过调用HAL层函数实现对驱动的调用*/
mPtr = zhx_print_init();
if(mPtr != 0)
{
Slog.e(TAG,"Failed to initialize freg service.");
}
}
public void setVal(int val)
{
if(zhx_print_set_val(val)== 0)
{
Slog.i(TAG,"done with the setting");
}
else
{
Slog.e(TAG,"setting val error");
}
}
public int getVal()
{
int val = 0;
Slog.i(TAG,"before to get,the val is "+val);
val = zhx_print_get_val();
Slog.i(TAG,"get the val by the \"zhx_print_get_val val\" = "+val);
return val;
}
//声明以下函数时JNI层中定义
public native int zhx_print_get_val();
public native int zhx_print_set_val(int val);
public native int zhx_print_init();
}
硬件访问服务zhx_Print_Service继承了zhx_print_service.Stub类,
并且实现了该zhx_print_service.aidl接口定义的函数setVal和getVal!
编写好源码后,我们需要执行以下命令:
ics/frameworks/base/services/java$ mm
编译好后,在services.jar文件中就包含有zhx_Print_Service类了!!!
(3):实现硬件访问服务的JNI方法
Android系统源码中,通常把硬件访问服务的JNI方法放到frameworks/base/service/jni目录中,
所有,在这里,我们把实现硬件访问服务zhx_Print_Service.java的JNI方法
com_android_service_zhx_print_service.cpp也保存到这个目录中,内容如下:
frameworks/base/services/jni/com_android_server_zhx_print_server.cpp(jni也可以用c语言来编写)
#define LOG_TAG"zhx_jni :"
/*jni使用头*/
#include <jni.h>
#include <JNIHelp.h>
/*HAL层使用头*/
#include <hardware/hardware.h>
#include <hardware/zhx_print.h>
/*log打印信息头 同时宏定义LOG_TAG也是属于log.h打印信息中的定义,
* LOG_TAG必须在log.h前定义*/
#include <utils/Log.h>
#include <stdio.h>
/*函数声明*/
int print_get_val(JNIEnv *env,jobject obj);
int print_set_val(JNIEnv *env,jobject obj,jint val);
int print_init(JNIEnv *env,jobject obj);
/*定义全局变量*/
struct print_device_t *device_dev = NULL;
struct print_module_t *module_dev = NULL;
namespace android {
/*读取数值*/
int print_get_val(JNIEnv *env,jobject obj)
{
int ret = -1;
int val = 0;
ret = device_dev->get_val(device_dev,&val);
if(ret == 0)
{
LOGI("get val sucessfully");
return val;
}
else
{
LOGE("fail to get val");
return ret;
}
return val;
}
/*设置数值 sucess = 0 fail < 0*/
int print_set_val(JNIEnv *env,jobject obj,jint val)
{
int ret = -1;
ret = device_dev->set_val(device_dev,val);
if(ret == 0)
{
LOGI("set val sucessfully.");
}
else
{
LOGE("error to set val");
}
return ret;
}
int zhx_print_open(struct hw_module_t*dev)
{
int ret = -1;
/*调用HAl打开函数*/
ret = dev->methods->open(dev,"zhx_print",
(struct hw_device_t**)&device_dev);
if(ret == 0)
{
LOGI("Found device sucessfully!");
}
else
{
LOGE("ERROR : not Found device");
}
return ret;
}
/**/
int print_init(JNIEnv *env,jobject obj)
{
int ret = -1;
if(!hw_get_module("zhx_print",(conststruct hw_module_t **)&module_dev))
{
LOGI("Found the HAL module");
ret = zhx_print_open(&(module_dev->common));
return ret;
}
return ret;
}
/*jni映射方法*/
static const JNINativeMethod method_table[] =
{
{"zhx_print_get_val","()I",(void*)print_get_val},
{"zhx_print_set_val","(I)I",(void*)print_set_val},
{"zhx_print_init","()I",(void*)print_init},
};
int register_android_server_zhx_Print_Service(JNIEnv*env)
{
return jniRegisterNativeMethods(env,
"com/android/server/zhx_Print_Service",
method_table,
NELEM(method_table));
}
};
/*jni使用头*/
#include <jni.h>
#include <JNIHelp.h>
/*HAL层使用头*/
#include <hardware/hardware.h>
#include <hardware/zhx_print.h>
/*log打印信息头 同时宏定义LOG_TAG也是属于log.h打印信息中的定义,
* LOG_TAG必须在log.h前定义*/
#include <utils/Log.h>
#include <stdio.h>
/*函数声明*/
int print_get_val(JNIEnv *env,jobject obj);
int print_set_val(JNIEnv *env,jobject obj,jint val);
int print_init(JNIEnv *env,jobject obj);
/*定义全局变量*/
struct print_device_t *device_dev = NULL;
struct print_module_t *module_dev = NULL;
namespace android {
/*读取数值*/
int print_get_val(JNIEnv *env,jobject obj)
{
int ret = -1;
int val = 0;
ret = device_dev->get_val(device_dev,&val);
if(ret == 0)
{
LOGI("get val sucessfully");
return val;
}
else
{
LOGE("fail to get val");
return ret;
}
return val;
}
/*设置数值 sucess = 0 fail < 0*/
int print_set_val(JNIEnv *env,jobject obj,jint val)
{
int ret = -1;
ret = device_dev->set_val(device_dev,val);
if(ret == 0)
{
LOGI("set val sucessfully.");
}
else
{
LOGE("error to set val");
}
return ret;
}
int zhx_print_open(struct hw_module_t*dev)
{
int ret = -1;
/*调用HAl打开函数*/
ret = dev->methods->open(dev,"zhx_print",
(struct hw_device_t**)&device_dev);
if(ret == 0)
{
LOGI("Found device sucessfully!");
}
else
{
LOGE("ERROR : not Found device");
}
return ret;
}
/**/
int print_init(JNIEnv *env,jobject obj)
{
int ret = -1;
if(!hw_get_module("zhx_print",(conststruct hw_module_t **)&module_dev))
{
LOGI("Found the HAL module");
ret = zhx_print_open(&(module_dev->common));
return ret;
}
return ret;
}
/*jni映射方法*/
static const JNINativeMethod method_table[] =
{
{"zhx_print_get_val","()I",(void*)print_get_val},
{"zhx_print_set_val","(I)I",(void*)print_set_val},
{"zhx_print_init","()I",(void*)print_init},
};
int register_android_server_zhx_Print_Service(JNIEnv*env)
{
return jniRegisterNativeMethods(env,
"com/android/server/zhx_Print_Service",
method_table,
NELEM(method_table));
}
};
编写好jni文件后,我们还需要修改frameworks/hase/services/jni目录下的onload.cpp文件,在里面添加register_android_server_zhx_print_service函数声明和调用。添加内容如下:
frameworks/base/services/jni/onload.cpp
namespace android
{
。。。
int register_android_server_zhx_print_service(JNIEnv* env);
}
。。。
extern "C" jint JNI_OnLoad(JavaVM *vm,void*reserved)
{
。。。
register_android_server_zhx_print_service(env);
return JNI_VERSION_1_4;
}
{
。。。
int register_android_server_zhx_print_service(JNIEnv* env);
}
。。。
extern "C" jint JNI_OnLoad(JavaVM *vm,void*reserved)
{
。。。
register_android_server_zhx_print_service(env);
return JNI_VERSION_1_4;
}
然后,进入到frameworks/base/service/jni目录中,打开里面的Android.mk文件,修改变量LOCALSRC_FILES的值。
LOCAL_SRC_FILE += \
。。。
com_android_server_zhx_print_service.cpp \
onload.cpp
。。。
com_android_server_zhx_print_service.cpp \
onload.cpp
修改好后,我们在执行如下命令:
ics/frameworks/base/services/jni$ mm
编译好后,得到的libandroid_servers.so文件包中就包含,print_get_val,print_set_val,prnt_init这三个JNI方法了!
到这里,硬件访问服务zhx_print_service就实现了,下面我们来介绍如何在系统进程system中启动它。
(4)启动硬件访问服务
在这里,我们把硬件访问服务运行在系统进程System中,就实现开机自动启动!!
首先,进入frameworks/base/services/java/com/android/server目录中,打开里面的SystemServer.java文件,修改
ServerThread类的成员函数run的实现,如下所示。
class ServerThread extends Thread {
。。。。
@Override
public void run() {
。。。。
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
...
try
{
Slog.i(TAG,"zhx_print_service");
//在系统开机启动的时候就创建zhx_Print_service
ServiceManager.addService("zhx_print",new zhx_Print_Service());
}catch(Throwable e)
{
Slog.e(TAG,"Failure starting zhx_print_Service");
}
}
。。。。
@Override
public void run() {
。。。。
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
...
try
{
Slog.i(TAG,"zhx_print_service");
//在系统开机启动的时候就创建zhx_Print_service
ServiceManager.addService("zhx_print",new zhx_Print_Service());
}catch(Throwable e)
{
Slog.e(TAG,"Failure starting zhx_print_Service");
}
}
最后,我们需要执行如下命令来重新编译services模块:
ics/frameworks/base/services/java$ mm
并以好后,得到services.jar 文件就包含有硬件访问服务zhx_print_service,并在系统启动时,将他运行在系统进程System中。
到这里,我们在重新打包Android系统镜像文件system.img.
/ics$ make snod
到这里,整个系统的硬件访问服务就编译完成了!!!
接下来我们在编译一个系统的应用程序来使用这个硬件访问服务!
(5)Android应用程序来实现硬件访问服务
由于这个应用程序是实验性质,所有我们将他放在packages/experimental目录中!!!对应的文件夹名字为
Zhx_Print,
在这里,我提供一个该应用程序的压缩包,
读者只需要直接把压缩包解压到packages/experimental目录中即可!
当在packages/experimental创建了工程Zhx_Print后,我们还需要执行以下命令:
ics/packages/experimental/Zhx_Print$ mm
android/ics$ make snod
android/ics$ make snod
打包好后,在Android系统镜像文件system.img中就包含有应用程序zhx_print了!
(6) 运行Android模拟器:
USER-NAME@MACHINE-NAME:~/Android$ emulator-kernel kernel/common/arch/arm/boot/zImage&
在Home Screen中就可以看到zhx_print应用程序了!!!!!!!