安卓硬件访问服务

安卓硬件访问服务

硬件访问服务通过硬件抽象层模块来为应用程序提供硬件读写操作。 由于硬件抽象层模块是使用C++语言开发的, 而应用程序框架层中的硬件访问服务是使用Java语言开发的, 因此, 硬件访问服务必须通过Java本地接口(Java Native InterfaceJNI) 来调用硬件抽象层模块的接口。

image-20200716105744277

Android系统的硬件访问服务通常运行在系统进程System中, 而使用这些硬件访问服务的应用程序运行在另外的进程中, 即应用程序需要通过进程间通信机制来访问这些硬件访问服务。

Android系统提供了一种高效的进程间通信机制——Binder进程间通信机制, 应用程序就是通过它来访问运行在系统进程System中的硬件访问服务的。 Binder进程间通信机制要求提供服务的一方必须实现一个具有跨进程访问能力的服务接口, 以便使用服务的一方可以通过这个服务接口来访问它。 因此, 在实现硬件访问服务之前, 我们首先要定义它的服务接口。

定义硬件访问服务接口

Android系统提供了一种描述语言来定义具有跨进程访问能力的服务接口, 这种描述语言称为Android接口描述语言(Android Interface Definition LanguageAIDL) 。 以AIDL定义的服务接口文件是以aidl为后缀名的, 在编译时, 编译系统会将它们转换成Java文件, 然后再对它们进行编译。

硬件访问服务接口定义 :

// frameworks\base\core\java\android\os\IFregService.aidlpackage android.os;interface IFregService 
{// 往虚拟硬件设备freg的寄存器val中写入一个整数void setVal(int val);// 从虚拟硬件设备freg的寄存器val中读出一个整数int getVal();
}

由于服务接口IFregService是使用AIDL语言描述的, 所以 需要将其添加到编译脚本文件中, 这样编译系统才能将其转换为Java文件, 然后再对它进行编译

编译脚本文件 :

# frameworks/base/Android.mk## READ ME: ########################################################
##
## When updating this list of aidl files, consider if that aidl is
## part of the SDK API.  If it is, also add it to the list below that
## is preprocessed and distributed with the SDK.  This list should
## not contain any aidl files for parcelables, but the one below should
## if you intend for 3rd parties to be able to send those objects
## across process boundaries.
##
## READ ME: ########################################################
LOCAL_SRC_FILES += \core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \#...core/java/android/net/IThrottleManager.aidl \core/java/android/nfc/IP2pTarget.aidl \core/java/android/os/IVibratorService.aidl \# 将需要的添加到编译脚本文件中core/java/android/os/IFregService.aidl \core/java/android/service/urlrenderer/IUrlRendererService.aidl \#...voip/java/android/net/sip/ISipService.aidl
#

编译 :

# 对硬件访问服务接口IFregService进行编译
mmm ./frameworks/base/

编译后得到的framework.jar文件就包含有IFregService接口, 它继承了android.os.IInterface接口。

IFregService接口内部, 定义了一个Binder本地对象类Stub,它实现了IFregService接口, 并且继承了android.os.Binder类。 此外, 在IFregService.Stub类内部, 还定义了一个Binder代理对象类Proxy, 它同样也实现了IFregService接口。

AIDL定义的服务接口是用来进行进程间通信的, 其中, 提供服务的进程称为Server进程, 而使用服务的进程称为Client进程。

Server进程中, 每一个服务都对应有一个Binder本地对象, 它通过一个桩(Stub) 来等待Client进程发送进程间通信请求。

Client进程在访问运行Server进程中的服务之前, 首先要获得它的一个Binder代理对象接口(Proxy) , 然后通过这个Binder代理对象接口向它发送进程间通信请求。

image-20200716110435819

实现硬件访问服务

硬件访问服务实现 :

// frameworks\base\services\java\com\android\server\FregService.javapackage com.android.server;import android.content.Context;
import android.os.IFregService;
import android.util.Slog;// 硬件访问服务 FregService 继承了 IFregService.Stub 类
public class FregService extends IFregService.Stub 
{private static final String TAG = "FregService";private int mPtr = 0;FregService() {// 调用 JNI 方法 init_native 来打开虚拟硬件设备 freg ,// 并且获得它的一个句柄值, 保存在成员变量 mPtr 中// 这个句柄值实际上是指向虚拟硬件设备freg在硬件抽象层中的一个设备对象mPtr = init_native();if(mPtr == 0) {Slog.e(TAG, "Failed to initialize freg service.");}}public void setVal(int val) {if(mPtr == 0) {Slog.e(TAG, "Freg service is not initialized.");return;}// 调用 JNI 方法 setVal_native 来写虚拟硬件设备 freg 的寄存器 valsetVal_native(mPtr, val);}    public int getVal() {if(mPtr == 0) {Slog.e(TAG, "Freg service is not initialized.");return 0;}//调用 JNI 方法 getVal_native 来读虚拟硬件设备 freg 的寄存器 valreturn getVal_native(mPtr);}private static native int init_native();private static native void setVal_native(int ptr, int val);private static native int getVal_native(int ptr);
};
# 重新编译 Android 系统的 services 模块
mmm ./frameworks/base/services/java/

编译后得到的services.jar文件就包含有FregService

实现硬件访问服务的JNI方法

实现了硬件访问服务FregServiceJNI方法:

// frameworks\base\services\jni\com_android_server_FregService.cpp#define LOG_TAG "FregServiceJNI"#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/freg.h>#include <stdio.h>namespace android
{//设置虚拟硬件设备 freg 的寄存器的值static void freg_setVal(JNIEnv* env, jobject clazz, jint ptr, jint value) {int val = value;//将参数 ptr 转换为 freg_device_t 结构体变量freg_device_t* device = (freg_device_t*)ptr;if(!device){LOGE("Device freg is not open.");return;}LOGI("Set value %d to device freg.", val);device->set_val(device, val);}//读取虚拟硬件设备freg的寄存器的值static jint freg_getVal(JNIEnv* env, jobject clazz, jint ptr){int val = 0;//将传输ptr转换为 freg_device_t 结构体变量freg_device_t* device = (freg_device_t*)ptr;if(!device) {LOGE("Device freg is not open.");return 0;}device->get_val(device, &val);LOGI("Get value %d from device freg.", val);return val;}//打开虚拟硬件设备fregstatic inline int freg_device_open(const hw_module_t* module, struct freg_device_t** device) {return module->methods->open(module, FREG_HARDWARE_DEVICE_ID, (struct hw_device_t**)device);}//初始化虚拟硬件设备fregstatic jint freg_init(JNIEnv* env, jclass clazz){freg_module_t* module;freg_device_t* device;LOGI("Initializing HAL stub freg......");//加载硬件抽象层模块freg// 根据 FREG_HARDWARE_MODULE_ID 来加载 Android 硬件抽象层模块 fregif(hw_get_module(FREG_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {LOGI("Device freg found.");//打开虚拟硬件设freg , 打开设备ID为 FREG_HARDWARE_DEVICE_ID 的硬件设备if(freg_device_open(&(module->common), &device) == 0) {LOGI("Device freg is open.");//将freg_device_t 接口转换为整型句柄值值返回return (jint)device;}LOGE("Failed to open device freg.");return 0;}LOGE("Failed to get HAL stub freg.");return 0;}//java本地接口方法表// 把JNI方法表method_table注册到Java虚拟机// 将函数freg_init、 freg_setVal和 freg_getVal的JNI方法注册//为init_native、 setVal_native和 getVal_nativestatic const JNINativeMethod method_table[] = {{"init_native", "()I", (void*)freg_init},{"setVal_native", "(II)V", (void*)freg_setVal},{"getVal_native", "(I)I", (void*)freg_getVal},};//注册java本地接口方法int register_android_server_FregService(JNIEnv *env) {return jniRegisterNativeMethods(env, "com/android/server/FregService", method_table, NELEM(method_table));}};

增加 register_android_server_FregService函数的声明调用 :

onload.cpp文件实现在libandroid_servers模块中。 当系统加载libandroid_servers模块时, 就会调用实现在onload.cpp文件中的JNI_OnLoad函数。 这样, 就可以将前面定义的三个JNI方法init_nativesetVal_nativegetVal_native注册到Java虚拟机中

image-20200716121659492

// frameworks/base/services/jni/onload.cpp#include "JNIHelp.h"
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"namespace android 
{
// ...
int register_android_server_location_GpsLocationProvider(JNIEnv* env);// 声明
int register_android_server_FregService(JNIEnv* env);
};using namespace android;extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{JNIEnv* env = NULL;jint result = -1;if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {LOGE("GetEnv failed!");return result;}LOG_ASSERT(env, "Could not retrieve the env!");//...register_android_server_location_GpsLocationProvider(env);//调用register_android_server_FregService(env);return JNI_VERSION_1_4;
}

进入到frameworks/base/services/jni目录中, 打开里面的Android.mk文件, 修改变量LOCAL_SRC_FILES的值

# frameworks/base/services/jni/Android.mkLOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)# 修改变量LOCAL_SRC_FILES的值
LOCAL_SRC_FILES:= \#...com_android_server_location_GpsLocationProvider.cpp \com_android_server_FregService.cpp \onload.cppLOCAL_C_INCLUDES += \$(JNI_H_INCLUDE)LOCAL_SHARED_LIBRARIES := \libandroid_runtime \libcutils \libhardware \libhardware_legacy \libnativehelper \libsystem_server \libutils \libui \libsurfaceflinger_clientifeq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS),linux)
ifeq ($(TARGET_ARCH),x86)
LOCAL_LDLIBS += -lpthread -ldl -lrt
endif
endif
endififeq ($(WITH_MALLOC_LEAK_CHECK),true)LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
endifLOCAL_MODULE:= libandroid_serversinclude $(BUILD_SHARED_LIBRARY)
# 重新编译libandroid_servers模块 , 得到的libandroid_servers.so文件
mmm ./frameworks/base/services/jni/

编译后得到的libandroid_servers.so文件就包含有init_nativesetVal_nativegetVal_native这三个JNI方法

启动硬件访问服务

Android系统的硬件访问服务通常是在系统进程System中启动的, 而系统进程System是由应用程序孵化器进程Zygote负责启动的。 由于应用程序孵化器进程Zygote是在系统启动时启动的, 所以要把硬件访问服务运行在系统进程System中, 就实现了开机时自动启动

image-20200716102646715

打开里面的SystemServer.java文件, 修改ServerThread类的成员函数run的实现

// frameworks/base/services/java/com/android/server/SystemServer.java
//...
class ServerThread extends Thread 
{//...// 修改 ServerThread 类的成员函数run的实现@Overridepublic void run() {//...if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {//...try {Slog.i(TAG, "DiskStats Service");ServiceManager.addService("diskstats", new DiskStatsService(context));} catch (Throwable e) {Slog.e(TAG, "Failure starting DiskStats Service", e);}try {Slog.i(TAG, "Freg Service");ServiceManager.addService("freg", new FregService());} catch (Throwable e) {Slog.e(TAG, "Failure starting Freg Service", e);}}//...}
}//...

系统进程System在启动时, 会创建一个ServerThread线程来启动系统中的关键服务,其中就包括一些硬件访问服务。

ServerThread类的成员函数run中, 首先创建一个FregService实例, 然后把它注册到Service Manager中。 Service ManagerAndroid系统的Binder进程间通信机制的一个重要角色, 它负责管理系统中的服务对象

注册到Service Manager中的服务对象都有一个对应的名称, 使用这些服务的Client进程就是通过这些名称来向Service Manager请求它们的Binder代理对象接口的, 以便可以访问它们所提供的服务。 硬件访问服务FregService注册到Service Manager之后, 它的启动过程就完成了

image-20200716103437599

# 重新编译services模块
mmm ./frameworks/base/services/java/

编译后得到的services.jar文件就包含有硬件访问服务FregService, 并且在系统启动时, 将它运行在系统进程System

# 重新打包Android系统镜像文件system.img
make snod

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/831707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vector的使用

1.构造函数 void test_vector1() {vector<int> v; //无参的构造函数vector<int> v2(10, 0);//n个value构造&#xff0c;初始化为10个0vector<int> v3(v2.begin(), v2.end());//迭代器区间初始化,可以用其他容器的区间初始化vector<int> v4(v3); //拷贝…

Java项目:基于SSM框架实现的学院党员管理系统高校党员管理系统(ssm+B/S架构+源码+数据库+毕业论文+开题)

一、项目简介 本项目是一套基于SSM框架实现的学院党员管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能齐…

ConstraintLayout 特殊用法详解

1.使用百分比设置间距 app:layout_constraintHorizontal_bias"0.4" 水平偏移&#xff08;0-1&#xff09; app:layout_constraintVertical_bias"0.4" 垂直偏移 &#xff08;0-1&#xff09; <?xml version"1.0" encoding"u…

第18章 基于经验的测试技术

一、错误猜想法 &#xff08;一&#xff09;概念 错误推算法基于测试人员对以往测试项目中一些经验测试程序中的错误测试程序时&#xff0c;人们可根据经验或直觉推测程序中可能存在的各种错误&#xff0c;然后有针对性地编写检查这些错误的测试用例的方法 &#xff08;二&a…

使用MATLAB/Simulink点亮STM32开发板LED灯

使用MATLAB/Simulink点亮STM32开发板LED灯-笔记 一、STM32CubeMX新建工程二、Simulink 新建工程三、MDK导入生成的代码 一、STM32CubeMX新建工程 1. 打开 STM32CubeMX 软件&#xff0c;点击“新建工程”&#xff0c;选择中对应的型号 2. RCC 设置&#xff0c;选择 HSE(外部高…

LeetCode 69—— x 的平方根

阅读目录 1. 题目2. 解题思路一3. 代码实现一4. 解题思路二5. 代码实现二 1. 题目 2. 解题思路一 二分查找法&#xff0c;对于整数 i ∈ [ 0 , x ] i \in [0,x] i∈[0,x]&#xff0c;我们判断 i 2 i^2 i2 和 x x x 的关系&#xff0c;然后找到最后一个平方小于等于 x x x …

【 书生·浦语大模型实战营】作业(六):Lagent AgentLego 智能体应用搭建

【 书生浦语大模型实战营】作业&#xff08;六&#xff09;&#xff1a;Lagent & AgentLego 智能体应用搭建 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方…

35.Docker-数据卷,目录挂载

注意&#xff1a;在容器内修改文件是不推荐的。 1.修改不方便&#xff0c;比如vi命令都无法使用。 2.容器内修改&#xff0c;没有日志记录的。 问题&#xff1a;那应该如何修改容器中的文件呢&#xff1f; 数据卷 volume是一个虚拟目录&#xff0c;指向宿主机文件系统中的…

如何把学浪的视频保存到手机

你是不是还在为无法将学浪的视频保存到手机而烦恼&#xff1f;别担心&#xff0c;接下来我将为大家分享一个非常实用的方法&#xff0c;让你轻松实现这一目标&#xff01; 下载学浪的工具我已经打包好了&#xff0c;有需要的自己下载一下 学浪下载工具打包链接&#xff1a;百…

一加12/11/10/Ace2/Ace3手机上锁回锁BL无限重启黑屏9008模式救砖

一加12/11/10/Ace2/Ace3手机官方都支持解锁BL&#xff0c;搞机的用户也比较多&#xff0c;相对于其他品牌来说&#xff0c;并没有做出限制&#xff0c;这也可能是搞机党最后的救命稻草。而厌倦了root搞机的用户&#xff0c;就习惯性回锁BL&#xff0c;希望彻底变回官方原来的样…

研究论文的蓝图:精通论文大纲的编写技巧

研究论文大纲是一个补充文件&#xff0c;描述了按计划顺序纳入论文的所有主题&#xff0c;通常按段落分割。正常的研究论文大纲包括额外的细节&#xff0c;例如子主题和证据来源&#xff0c;以帮助作者保持结构。本文讨论了研究论文大纲的内容以及如何撰写。 研究论文大纲的含…

C#语言入门

一、基础知识 1. 程序语言是什么 用于人和计算机进行交流&#xff0c;通过程序语言让计算机能够响应我们发出的指令 2. 开发环境 IDE&#xff0c;集成开发环境。它就是一类用于程序开发的软件&#xff0c;这一类软件一般包括了代码编辑、编译器、调试器、图形用户界面等等工…

STM32独立看门狗,实现单片机自动重启

今天学习了一下独立看门狗&#xff0c;看门狗的主要作用就是防止程序中有死循环或是不知道的bug&#xff0c;而造成在while循环中没有及时喂狗&#xff0c;程序就会控制单片机重启复位&#xff0c;从而不至于影响程序一直不能正常工作。 其实看门狗的应用也不是很复杂&#xf…

1020. 【USACO题库】2.1.1 The Castle城堡

题目描述 以一个几乎超乎想像的运气,农民约翰在他的生日收到了一张爱尔兰博彩的奖券。 这一张奖券成为了唯一中奖的奖券。 农民约翰嬴得爱尔兰的乡下地方的一个传说中的城堡。 吹牛在他们威斯康辛州不算什么,农民约翰想告诉他的牛所有有关城堡的事。 他想知道城堡有多少房间…

光伏光热一体化技术PVT

1、PVT集热器简介 太阳能光伏光热一体化组件主要由光伏与光热两个部分组成。光伏部分采用技术成熟的太阳能光伏面板&#xff0c;通过控制系统为建筑提供所需电能&#xff0c;主要包括光伏电池、蓄电池、逆变器和控制器等构件。光热部分主要为集热器&#xff0c;将太阳能转换为热…

力扣例题(接雨水)

链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 思路&#xff1a; 判断一块地方是否可以接到雨水&#xff0c;只需要判断他是否有左右边界使他可以接到水 左右边界分别为此处左侧的最高点和右侧的最高点 同时此处可接雨水的高度为左右两…

基于Pytorch深度学习——GPU安装/使用

本文章来源于对李沐动手深度学习代码以及原理的理解&#xff0c;并且由于李沐老师的代码能力很强&#xff0c;以及视频中讲解代码的部分较少&#xff0c;所以这里将代码进行尽量逐行详细解释 并且由于pytorch的语法有些小伙伴可能并不熟悉&#xff0c;所以我们会采用逐行解释小…

《QT实用小工具·四十九》QT开发的轮播图

1、概述 源码放在文章末尾 该项目实现了界面轮播图的效果&#xff0c;包含如下特点&#xff1a; 左右轮播 鼠标悬浮切换&#xff0c;无需点击 自动定时轮播 自动裁剪和缩放不同尺寸图片 任意添加、插入、删除 单击事件&#xff0c;支持索引和自定义文本 界面美观&#xff0c;圆…

开源免费的网盘项目Cloudreve,基于Go云存储个人网盘系统源码(七牛、阿里云 OSS、腾讯云 COS、又拍云、OneDrive)

项目简介&#xff1a; 在现今的网盘服务中&#xff0c;用户经常遭遇限速和价格上涨的问题&#xff0c;这无疑增加了使用上的困扰。 为此&#xff0c;我今天要介绍一款开源且免费的网盘项目——Cloudreve。 这个项目是基于Go语言开发的云存储个人网盘系统&#xff0c;支持多种…

[笔试训练](十二)

目录 034:删除公共字符串 035:两个链表的第一个公共节点 036:mari和shiny 034:删除公共字符串 删除公共字符_牛客题霸_牛客网 (nowcoder.com) 题解: 用哈希记录好第二个字符串中的字符&#xff0c;再遍历一遍第一个字符串&#xff0c;只将没有记录的字符加在结果字符串上。…