(安卓/android)应用层绕过HAL调用驱动
应用层绕过HAL调用驱动(以Radio为例)
为什么要绕过Hal层调用驱动
-
硬件抽象层是位于操作系统 内核与硬件电路之间的接口层,其目的在于将硬件抽象化。它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,可在多种平台上进行移植。在Android内核源码(不是linux内核源码)中添加HAL层、JNI层、开启系统服务,这是一个比较复杂的过程,很多标准的设备都采用这种方式设计,比如说wifi、gps、sensor等,这种调用过程看起来比较标准,但是如果作为第三方开发就会很麻烦,HAL层、JNI层,系统服务层,每层都需要编译Android内核源码,这样就会延长了产品的开发周期,所以编写本文意在简化应用层与驱动的交互逻辑,虽增加耦合,但在平台有限的开发环境中能大大提高开发效率,可从应用层调试驱动减少系统编译和排错的成本。
-
简化前后结构概览
一. 创建访问驱动的新方式
1.编写Jni代码访问驱动节点
相关文件地址:
AndroidM_3561_after/vendor/xxx/packages/apps/Radio/app/src/main/jni/RadioDriveJni.cpp
可参照FaRadioService.cpp,实现节点的open/close/read/write
extern "C"JNIEXPORT jint JNICALLJava_com_xxx_radio_radiodrive_RadioDriveJni_init(JNIEnv *env, jobject instance) { fd = open(DEVICE_NAME, O_RDWR); if(fd < 0) { LOGE("Fail to open device file /dev/FlyRadio --%s.",DEVICE_NAME); return -1; } return 0;}extern "C"JNIEXPORT jint JNICALLJava_com_xxx_radio_radiodrive_RadioDriveJni_setMute(JNIEnv *env, jobject instance, jboolean muted) { unsigned char buf[5] = {0xa0,0x66,0x01,0x00}; buf[3] = muted; mMute = muted; if(write(fd, buf,sizeof(buf))) { return 0; } return -1;}extern "C"JNIEXPORT jboolean JNICALLJava_com_xxx_radio_radiodrive_RadioDriveJni_destroy(JNIEnv *env, jobject instance) { if(fd != -1){ if(!close(fd)){ return 0; } } return -1;}
2.新建Android.mk文件跟随系统一起编译到system/lib目录,module命名为’ libfaradio_drive_jni ’
相关文件地址:
AndroidM_3561_after/vendor/xxx/packages/apps/Radio/app/src/main/jni/Android.mk
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ RadioDriveJni.cpp \ LOCAL_SHARED_LIBRARIES := libutils libcutils LOCAL_C_INCLUDES += $(LOCAL_PATH)/include ifneq ($(XXX_LIB_OUT_PATH),)LOCAL_MODULE_PATH := $(XXX_LIB_OUT_PATH)endif LOCAL_MODULE:= libfaradio_drive_jni include $(BUILD_SHARED_LIBRARY)
3.Radio根目录下的Android.mk文件里引入上述创建的mk文件
相关文件地址:
AndroidM_3561_after/vendor/xxx/packages/apps/RadioAndroid.mk
include $(LOCAL_PATH)/app/src/main/jni/Android.mk
4.将libfaradio_drive_jni module 添加到device.mk白名单
相关文件地址:
AndroidM_3561_after/system/core/rootdir/device.mk
PRODUCT_PACKAGES += libfaradio_drive_jni
5.赋予应用读写驱动节点的权限
相关文件地址:
AndroidM_3561_after/system/core/rootdir/ueventd.rc
AndroidM_3561_after/external/sepolicy/system_app.te
在ueventd.rc中添加,
/dev/FlyRadio 0666 system system
在system_app.te中添加,’ fly_radio_device ’ 为/dev/FlyRadio节点在file_contexts文件中的定义
allow system_app fly_radio_device:chr_file rw_file_perms;
二. 移除访问驱动的旧方式
根据结构图一步一步定位再移除
1.移除Hal层
相关文件地址:
AndroidM_3561_after/hardware/libhardware/modules/xxx/FlyRadioHal.c
AndroidM_3561_after/hardware/libhardware/modules/xxx/Android.mk
直接删除即可
2.移除Service
相关文件地址:
AndroidM_3561_after/vendor/xxx/frameworks/native/faradio/service/FaRadioService.h
AndroidM_3561_after/vendor/xxx/frameworks/native/faradio/service/FaRadioService.cpp
AndroidM_3561_after/vendor/xxx/frameworks/native/faradio/service/IaRadioService.h
AndroidM_3561_after/vendor/xxx/frameworks/native/faradio/service/IaRadioService.cpp
直接删除即可
由于这里没有Android.mk文件,所有应该被父目录相应的Android.mk文件引入,在AndroidM_3561_after/vendor/xxx/frameworks/native/faradio/中查看Android.mk,果然有对service文件夹的引入,删除即可
LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/service \
3.移除Service启动的入口
相关文件地址:
AndroidM_3561_after/vendor/xxx/frameworks/native/launcher/ServicesLauncher.cpp
注释掉FaRadioService启动的代码即可
extern "C" void instantiateServices(int tag){ if(tag == 1){ int status = launchService("/system/lib/libfaradioservice.so"); if(status == -1) ALOGE("ServicesLauncher load library Error."); }}
4.移除调用FaradioService的Jni封装
相关文件地址:
AndroidM_3561_after/vendor/xxx/frameworks/base/jni/com_xxx_radio_Radio.cpp
直接删除即可,和2一样移除相关Andorid.mk对此文件的依赖
###5.移除device.mk对已移除module的依赖
相关文件地址:
AndroidM_3561_after/vendor/xxx/device/device.mk
# PRODUCT_PACKAGES += \#libfaradioservice \# add xxx radio# PRODUCT_PACKAGES += radio.default
三. 编译系统
更多相关文章
- Android(安卓)Odex 文件使用
- [Android]如何做一个崩溃率少于千分之三噶应用app(17)-组件化SDK
- Android自定义适配器---实现简单文件管理器
- 上传音乐到Android模拟器的SD卡,并在Android模拟器上播放
- android屏幕适配计算方式及适配values文件生成
- Android中的软件安全和逆向分析[一]—apk反编译破解以及java汇编
- 自动化代码检查优化Lint
- 两个Android工程之间的调用
- 长聚微嵌 DMA-210U Android(安卓)入门第一天------烧写uboot、ke