安卓硬件访问服务

news2024/11/17 7:53:31

安卓硬件访问服务

硬件访问服务通过硬件抽象层模块来为应用程序提供硬件读写操作。 由于硬件抽象层模块是使用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.aidl

package 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.java

package 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 的寄存器 val
        setVal_native(mPtr, val);
    }    

    public int getVal() 
    {
        if(mPtr == 0) 
        {
            Slog.e(TAG, "Freg service is not initialized.");
            return 0;
        }

        //调用 JNI 方法 getVal_native 来读虚拟硬件设备 freg 的寄存器 val
        return 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;
    }

    //打开虚拟硬件设备freg
    static 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);
    }

    //初始化虚拟硬件设备freg
    static 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 硬件抽象层模块 freg
        if(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_native
    static 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.mk

LOCAL_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.cpp

LOCAL_C_INCLUDES += \
    $(JNI_H_INCLUDE)

LOCAL_SHARED_LIBRARIES := \
    libandroid_runtime \
    libcutils \
    libhardware \
    libhardware_legacy \
    libnativehelper \
    libsystem_server \
    libutils \
    libui \
    libsurfaceflinger_client

ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS),linux)
ifeq ($(TARGET_ARCH),x86)
LOCAL_LDLIBS += -lpthread -ldl -lrt
endif
endif
endif

ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
    LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
endif

LOCAL_MODULE:= libandroid_servers

include $(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的实现
    @Override
    public 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.coloradmin.cn/o/1642985.html

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

相关文章

EPAI手绘建模APP演示板、材质编辑器、样式编辑器

(11) 更多 图 74 更多工具栏 ① 演示板&#xff1a;打开关闭演示板。演示板用来显示从设备导入的模型图纸图片或者打开模型建模教程网页&#xff0c;是建模过程中一个辅助功能。有些设备有小窗口功能有些没有&#xff0c;对于没有小窗口功能的设备&#xff0c;通过演示板能够在…

A Bug‘s Life (并查集)

//新生训练 #include <iostream> #include <algorithm> using namespace std; const int N 5000; int p[N], sz[N]; int n, m; int find(int x) {if (p[x] ! x)p[x] find(p[x]);return p[x]; } int main() {int T;scanf("%d", &T);for (int k 1; …

车载电子电器架构 —— 通信安全E2E Rollng counter

车载电子电器架构 —— 通信安全E2E Rollng counter 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要…

17_Scala面向对象高阶功能

文章目录 1.继承1.1 构造对象时,父类对象优于子类对象1.2父类主构造有参数,子类必须要显示地调用父类主构造器并传值 2.封装3.抽象3.1抽象定义3.2子类继承抽象类3.3抽象属性 4.伴生对象4.1创建类和伴生对象4.2调用 1.继承 –和Java一样,权限protected , public.父类定义子类用…

[嵌入式系统-67]:RT-Thread-组件:虚拟-设备文件系统DFS,以目录结构和文件的方式存储和管理各种各样的数据

目录 虚拟文件系统 1. DFS 简介 DFS 架构 POSIX 接口层 虚拟文件系统层 设备抽象层 2. 挂载管理&#xff1a;构建统一的文件系统目录 初始化 DFS 组件 注册文件系统 将存储设备注册为块设备 格式化文件系统 挂载文件系统 卸载文件系统 3. 文件管理 打开和关闭文…

分布式与一致性协议之一致哈希算法(三)

一致哈希算法 如何使用一致哈希算法实现哈希寻址 我们一起来看一个例子&#xff0c;对于1000万个key的3节点KV存储&#xff0c;如果我们使用一致哈希算法增加1个节点&#xff0c;即3节点集群变为4节点集群&#xff0c;则只需要迁移24.3%的数据,如代码所示 package mainimpor…

时间日志格式的统一和定制

返回当前格式的时间没有错误&#xff0c;但是不符合中国人的阅读习惯 解决&#xff1a; 方案一&#xff1a;JsonFormat 解决后端 传到 前端格式问题 依赖&#xff1a; <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jack…

brpc profiler

cpu profiler cpu profiler | bRPC MacOS的额外配置 在MacOS下&#xff0c;gperftools中的perl pprof脚本无法将函数地址转变成函数名&#xff0c;解决办法是&#xff1a; 安装standalone pprof&#xff0c;并把下载的pprof二进制文件路径写入环境变量GOOGLE_PPROF_BINARY_PA…

Spring Boot与JSP的浪漫邂逅:轻松构建动态Web应用的秘诀

本文介绍 Spring Boot 集成 JSP。 1、pom.xml 增加对 JSP 的支持 Spring Boot 的默认视图支持是 Thymeleaf 模板引擎&#xff0c;如果想要使用 JSP 页面&#xff0c;需要配置 servlet 依赖和 tomcat 的支持。 在 pom.xml 文件中增加如下代码&#xff1a; <!-- servlet依赖 -…

Sarcasm detection论文解析 |使用基于多头注意力的双向 LSTM 进行讽刺检测

论文地址 论文地址&#xff1a;https://ieeexplore.ieee.org/document/8949523 论文首页 笔记框架 使用基于多头注意力的双向 LSTM 进行讽刺检测 &#x1f4c5;出版年份:2020 &#x1f4d6;出版期刊:IEEE Access &#x1f4c8;影响因子:3.9 &#x1f9d1;文章作者:Kumar Avinas…

使用docker-compose编排lnmp(dockerfile)完成wordpress

文章目录 使用docker-compose编排lnmp&#xff08;dockerfile&#xff09;完成wordpress1、服务器环境2、Docker、Docker-Compose环境安装2.1 安装Docker环境2.2 安装Docker-Compose 3、nginx3.1 新建目录&#xff0c;上传安装包3.2 编辑Dockerfile脚本3.3 准备nginx.conf配置文…

WebAssembly 入门教程 c++、python编译wasm

WebAssembly 入门 了解 wasm 使用场景&#xff0c;复杂对象传递和经验法则。 简介 WebAssembly 是一种新的编码方式&#xff0c;可以在现代的网络浏览器中运行。它是一种低级的类汇编语言&#xff0c;具有紧凑的二进制格式&#xff0c;可以接近原生的性能运行&#xff0c;并…

【C++】学习笔记——vector_2

文章目录 七、vector2. vecotr的使用3. vector的模拟实现 未完待续 七、vector 2. vecotr的使用 上节我们以二维数组结束&#xff0c;这一节我们以二维数组开始。 // 二维数组 vector<vector<int>> vv;二维数组在底层是连续的一维数组。vv[i][j] 是怎样访问的&a…

FBA头程海运发货流程是怎样的?

FBA头程发货作为整个FBA流程的关键一环&#xff0c;更是直接影响到商品从起点到终点的流通效率和成本。其中&#xff0c;海运作为一种经济、稳定的运输方式&#xff0c;在FBA头程发货中扮演着举足轻重的角色。那么&#xff0c;FBA头程海运发货流程究竟是怎样的呢? 1、装箱与发…

轻松应对数据恢复挑战:雷神笔记本,不同情况不同策略

在数字化时代&#xff0c;数据无疑是我们生活中不可或缺的一部分。无论是重要的工作文件、珍贵的家庭照片&#xff0c;还是回忆满满的视频&#xff0c;一旦丢失&#xff0c;都可能给我们的生活带来诸多不便。雷神笔记本作为市场上备受欢迎的电脑品牌&#xff0c;用户在使用过程…

Kotlin: Expecting a ‘>‘

数组值为任意类型&#xff0c;声明报错: Kotlin: Expecting a > var anyArr1: Array<Any?> arrayOf("a", "b", "c", true, 34)原因是&#xff1a; // var anyArr1: Array<Any?> arrayOf("a", "b", "c…

小苹果

题目描述 小的桌子上放着几个苹果从左到右排成一列&#xff0c;编号为从1 到 。小苞是小的好朋友&#xff0c;每天她都会从中拿走一些苹果。每天在拿的时候&#xff0c;小苞都是从左侧第1个苹果开始、每隔2个苹果拿走1个苹果。随后小苞会将剩下的苹果按原先的顺序重新排成一列…

gige工业相机突破(一,准备资源)

gige相机能不能绕开相机生产商提供的sdk&#xff0c;而直接取到像&#xff1f; 两种办法&#xff0c;第一&#xff0c;gige vision2.0说明书&#xff0c;第二&#xff0c;genicam 首先你会去干什么事&#xff1f; 好几年&#xff0c;我都没有突破&#xff0c;老虎吃天&#x…

Vue3-element-plus表格

一、element-plus 1.用组件属性实现跳转路由 <el-menu active-text-color"#ffd04b" background-color"#232323" :default-active"$route.path" //高亮 text-color"#fff"router><el-menu-item index"/article/channe…

基于yolov2深度学习网络模型的鱼眼镜头中人员检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 load yolov2.mat% 加载训练好的目标检测器 img_size [448,448]; imgPath test/; % 图像…