在学习了硬件访问服务框架之后,以led为例,总结了Android app通过服务访问硬件的框架
实现:
1. JNI和HAL
//用来注册JNI本地方法(jniRegisterNativeMethods)
实现com_android_server_LedService.cpp
//实现HAL本地方法调用c函数:open、close、ioctl 具体实现参考文章最后
hal_led.c
hal_led.h
2. 修改onload.cpp
register_android_server_LedService(env); 调用各个硬件JNI中的注册本地方法的接口函数 进行本地方法的注册
最终编译生成libandroid_servers.so
3. 修改SystemServer.java 创建一个LedService对象并add这个service
System.loadLibrary(“android_servers”); //加载库,执行jniOnLoad方法
LedService led = new LedService();
ServiceManager.addService(“led”, led);
4. 创建LedService.java 去调用JNI提供的native方法
这个LedService类要继承ILedService接口,实现接口中的方法。至此,一个LedService服务就创建成功了,但是最终要通过步骤3将这个服务添加到系统中通过service_manager这个进程来进行管理所有的服务。
5. 创建ILedService.java接口,供app使用
这个接口通过编写一个对应的ILedService.aidl文件然后mmm编译在out目录下生成对应的ILedService.java接口, 参考IVibratorService.aidl文件。
编写HAL代码:
JNI 向上提供本地函数,向下加载HAL文件并调用 HAL的函数
HAL 负责访问驱动程序执行硬件操作
JNI加载HAL的实质是JNI如何使用dlopen来加载HAL的动态库
1. JNI如何使用HAL
a. 使用hw_get_module获得hw_module_t结构体
b. 调用module->methods->open(module, name, &device); // name – 设备的名字,一个so可能包含多个device
调用moudle的open函数获取一个hw_device_t结构体(设备结构体)。
(light_device_t*)device; //并且将设备结构体转换为自定义的结构体
2. HAL怎么写
a. 要实现一个名字为HMI的hw_module_t结构体
b. 要实现一个open函数,根据传入的name返回一个设备自定义结构体,这个结构体的第一成员是hw_device_t结构体。
对修改或者新加的文件处理:
led_hal.c
hardware/libhardware/modules/led
mk文件可以cp ../vibratory/Android.mk进行修改
led_hal.h
hardware/libhardware/include/hardware
com_android_service.led.cpp
frameworks/base/services/core/jni
ILedLService.aidl
frameworks/base/core/java/android/os/ILedService.aidl
frameworks/base$ vi Android.mk进行修改
生成.java需在当前目录下执行mmm命令
SystemServer.java
frameworks/base/services/java/com/android/server
LedService.java
frameworks/base/services/core/java/com/android/server
修改frameworks/base/services/core/Android.mk
onload.cpp
frameworks/base/services/core/jni
修改frameworks/base/services/core/jni/Android.mk
mmm frameworks/base/services
mmm hardware/libhardware/modules/led
make snod
./gen-img.sh
从新烧写system.img
最后app如何使用:
1. as工程要包含什么?
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar
2. 怎么包含
a. Creating a module library and adding it to module dependencies
file->project structure->+ ->import .jar ->classer.jar
file->project structure->app->dependencies ->+ module depends -> classer
b. 编译报错:java.lang.OutOfMemoryError: GC overhead limit exceeded
修改build.gradle,添加
dexOptions {
javaMaxHeapSize "4g"
}
c. 编译报错: Too many field references Building Apps with Over 65K Methods
修改build.gradle
android {
defaultConfig {
multiDexEnabled true
dependencies {
compile 'com.android.support:multidex:1.0.1'
修改AndroidManifest
<application
android:name="android.support.multidex.MultiDexApplication"
关于他们之间的关系:
最后附上相关代码:
LedService.java
/*************************************************************************
> File Name: LedService.java
> Author: hanp
> Mail: [email protected]
> Created Time: 2017年07月26日 星期三 16时23分18秒
************************************************************************/
package com.android.server;
import android.os.ILedService;
import android.util.Slog;
/* 调用本地native方法,操作硬件 */
public class LedService extends ILedService.Stub
{
private static final String TAG = "LedService";
public LedService()
{
Slog.i(TAG, "public LedService()");
native_ledOpen();
}
public void ledCtrl(int which, int status) throws android.os.RemoteException
{
Slog.i(TAG, "ledCtrl(int which = "+which+", int status = "+status+")");
native_ledCtrl(which, status);
}
public static native void native_ledOpen();
public static native void native_ledCtrl(int which, int status);
public static native void native_ledClose();
}
SystemService.java
/* 向servicemanger添加一个service */
Slog.i(TAG, "Led Service");
LedService led = new LedService();
ServiceManager.addService("led", led);
com_android_service_LedService
/*************************************************************************
> File Name: com_android_server_LedService.cpp
> Author: hanp
> Mail: [email protected]
> Created Time: 2017年07月26日 星期三 16时53分51秒
************************************************************************/
#include
#include "jni.h"
#include "JNIHelp.h"
#include
#include
#include "android_runtime/AndroidRuntime.h"
#include
#include
#include
#define LOG_TAG "LedService"
namespace android
{
static led_device_t * led_dev;
JNIEXPORT void JNICALL ledOpen(JNIEnv * env, jclass cls)
{
jint err;
hw_device_t * device;
hw_module_t * module;
ALOGI("JNI native method led_open ...");
/* 1. get modules hw_get_module */
/* 2. call module->methods->open method get a hw_device_t structure */
/* 3. call led_open */
err = hw_get_module("led", (hw_module_t const**)&module);
if (err == 0) {
err = module->methods->open(module, NULL, &device);
if (err == 0) {
led_dev = (led_device_t*)device;
led_dev->led_open(led_dev);
}
else {
ALOGI("JNI native get module err ...");
}
}
return;
}
JNIEXPORT void JNICALL ledClose(JNIEnv * env, jclass cls)
{
ALOGI("JNI native method led_close ...");
}
/* status 0 -- off 1 -- on */
JNIEXPORT void JNICALL ledCtrl(JNIEnv * env, jclass cls, jint which, jint status)
{
ALOGI("JNI native method led_ctrl ...");
led_dev->led_ctrl(led_dev, which, status);
return;
}
const JNINativeMethod methods[] = {
{"native_ledOpen", "()V", (void *)ledOpen},
{"native_ledClose", "()V", (void *)ledClose},
{"native_ledCtrl", "(II)V", (void *)ledCtrl},
};
int register_android_server_LedService(JNIEnv *env)
{
ALOGI("JNI native method register_android_server_LedService ...");
/* 将本地method注册到LEDService这个服务中*/
return jniRegisterNativeMethods(env, "com/android/server/LedService", methods, NELEM(methods));
}
};
hal_led.c
/*************************************************************************
> File Name: led_hal.c
> Author: hanp
> Mail: [email protected]
> Created Time: 2017年07月31日 星期一 15时00分30秒
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "led.h"
#define LOG_TAG "LedHal"
/* 1. 定义一个名字为HMI的hw_device_t类型的结构体 */
/* 2. 实现一个open函数,并根据传入的name返回一个自定义的设备结构体 (led_device_t) */
/* 3. 根据传入name的定义一个自定义的设备结构体 -- led_device_t, 这个结构体的第一个成员是hw_device_t结构体 */
static int fd;
static void led_open(led_device_t * dev)
{
fd = open("/dev/led", O_RDWR);
ALOGI("hal method led_open ...");
if (fd < 0)
{
ALOGI("hal method led_open open /dev/led err ...");
return ;
}
}
static int led_close(struct hw_device_t * dev)
{
ALOGI("hal method led_close ...");
close(fd);
return 0;
}
static void led_ctrl(led_device_t * dev, int which, int status)
{
ALOGI("hal method led_ctrl ...");
switch (status)
{
case 1:
ioctl(fd, LED_ON, which);
break;
case 0:
ioctl(fd, LED_OFF, which);
break;
default:
ALOGI("hal method led_ctrl invaled argument ...");
break;
}
}
static led_device_t led_device = {
.common = {
.tag = HARDWARE_DEVICE_TAG,
.close = led_close,
},
.led_open = led_open,
.led_ctrl = led_ctrl,
};
static int led_device_open(const hw_module_t* module, const char* id, hw_device_t** device)
{
*device = &led_device; //通过参数,传回led_device_t结构体
return 0;
}
static struct hw_module_methods_t led_module_methods = {
.open = led_device_open,
};
struct hw_module_t HAL_MODULE_INFO_SYM = { //#define HAL_MODULE_INFO_SYM HMI
.tag = HARDWARE_MODULE_TAG,
.id = "led",
.methods = &led_module_methods,
};