android硬件访问服务程序框架和简单实例分析

2024-09-05 22:18

本文主要是介绍android硬件访问服务程序框架和简单实例分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

android硬件访问服务程序框架

  • loadLibrary 进行加载C库
  • JNI_OnLoad 注册本地方法
    – 分别调用各个硬件的函数来注册本地方法
  • SystemServer 使用本地方法(在java代码中,例如InputManagerService),对每一个硬件构造service,将其添加到系统中
  • APP 使用:获得服务 getService ;使用服务。执行service

SystemServer提供众多的服务service.
前三者属于系统进程
第四个属于用户进程
不同进程之间进行通信。所借助的是系统的binder服务。


以下属于针对上述分析

涉及的代码

\android5.0.2\frameworks\base\services\java\com\android\server\SystemServer.java
\frameworks\base\core\java\android\hardware\input\InputManager.java
\frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
\frameworks\base\core\java\android\content\Context.java
\frameworks\base\core\java\android\app\ContextImpl.java
\frameworks\base\core\java\android\hardware\input\IInputManager.aidl

实例

    //LoadLibrary加载C库 System.loadLibrary("android_servers");nativeInit();//...startOtherServices(); //...//利用本地方法,构造一个service   InputManagerService  在这个java文件中嗲用native_init。从而跳转到了本地  inputManager = null;inputManager = new InputManagerService(context);//添加到系统中ServiceManager.addService(Context.INPUT_SERVICE, inputManager);//以上属于系统进程//用户进程如何使用呢?getSystemService(Context.INPUT_SERVICE);//就得到了这个服务。就可以通过service执行的一些操作

app使用

app的使用是调用getSystemService(Context.xxx来使用的)
getSystemService在Context.java中进行定义

    public abstract Object getSystemService(@ServiceName @NonNull String name);

可以看出其为抽象的基类,其实现实在ContextImpl中实现的。

 @Overridepublic Object getSystemService(String name) {ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);return fetcher == null ? null : fetcher.getService(this);}

使用getSystemService获得的返回值,一般需要强转为一个Manager的类。
例如

mIm = (InputManager)Context.getSystemService(Context.INPUT_SERVICE);

问题

  • nativeInit(); 是怎么关联本地方法
  • 应用程序中自己LoadLibrary的话,另外一个app,是如何得到这个service的。其可能是通过aidl来获得这个服务的。这是和系统getSystemService不同的地方。getSystemService也是通过ServiceManager.getService来获得的。应用本身通过aidl来实现,android在编译的时候,自动实现了binder的机制。

注册本地方法

在JNI中实现
在onLoad.cpp中

android_server的实现

在framework/base/services下,
有一个Andrpid.mk
这个编译文件中,会将整个的Services目录的内容编译成两部分,

LOCAL_MODULE := services
LOCAL_MODULE:= libandroid_servers

目录下的java文件会编译为services
目录下jni下的
include (wildcard (LOCAL_PATH)/*/jni/Android.mk)
有android.mk包含的文件将会形成一个 动态库 android_service 供SystemServer进行调用。

JNI目录下的Android.mk

LOCAL_SRC_FILES += \
    $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
    $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
$(LOCAL_REL_DIR)/onload.cppLOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
frameworks/base/services \
frameworks/base/libs \

LOCAL_SHARED_LIBRARIES += \
    libandroid_runtime \

主要是包含一些cpp文件、头文件以及需要的动态库文件

Load_Library的入口 onload.cpp

extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)

调用

System.loadLibrary("android_servers");

的时候,会调用到JNI_OnLoad方法。
在这个方法中,会调用到和硬件相关的jni的cpp文件

register_android_server_PowerManagerService(env);
register_android_server_SerialService(env);
register_android_server_InputApplicationHandle(env);
register_android_server_InputWindowHandle(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbHostManager(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GpsLocationProvider(env);
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
register_android_server_fingerprint_FingerprintService(env);
register_android_server_Watchdog(env);

服务的加载和被调用的过程

利用本地函数构造service是怎么样的过程呢?

答:在new InputManagerService的时候调用本地函数native_init
InputManagerService 继承IInputManager.stub
InputManagerService中提供相关的服务端的程序,供客户端调用。

在构造出service之后,利用

ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

添加到ServiceManager中。

Context中InputManager的实话

在Context的实现类ContextImpl中,

registerService(INPUT_SERVICE, new StaticServiceFetcher() {public Object createStaticService() {return InputManager.getInstance();}});

此时复写的createStaticService在调用getSystemService的时候被掉用。

在app应用中,需要使用这些Context的service的时候,调用
getSystemService(Context.xxx)同时将返回值强转为一个xxxManager类型。

InputManager 中通过getInstance获得 添加到ServiceManager的服务

public static InputManager getInstance() {synchronized (InputManager.class) {if (sInstance == null) {IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);sInstance = new InputManager(IInputManager.Stub.asInterface(b));}return sInstance;}}

如此一来,客户端app就能通过binder机制,调用系统提供的服务了。

ClipboardService实例

抽象类
frameworks\base\core\java\android\text\ClipboardManager.java
实现类
frameworks\base\core\java\android\content\ClipboardManager.java
ClipboardManager中获取到服务

   ClipboardManager clipboardManager =(ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);

ClipboardManager提供的一个方法。

 clipboardManager.setText(expected);

在text目录下的ClipboardManger.java中的setText是一个抽象方法。

frameworks\base\core\java\android\text\ClipboardManager.javapublic abstract void setText(CharSequence text);

在Content下的ClipbpadrManager.java实现了这个方法。故而调用如下代码

//首先调用InputManager下的setPrimaryClippublic void setText(CharSequence text) {setPrimaryClip(ClipData.newPlainText(null, text));}//调用getService的setPrimaryClippublic void setPrimaryClip(ClipData clip) {try {if (clip != null) {clip.prepareToLeaveProcess();}getService().setPrimaryClip(clip, mContext.getOpPackageName());} catch (RemoteException e) {}}//getService 通过ServiceManager获得clipboard的IBinder对象,并转换成为IClipboard 对象static private IClipboard getService() {synchronized (sStaticLock) {if (sService != null) {return sService;}IBinder b = ServiceManager.getService("clipboard");sService = IClipboard.Stub.asInterface(b);return sService;}}// 通过aidl调用服务器部分的setPrimaryClip,这部分代码系统提供。void setPrimaryClip(in ClipData clip, String callingPackage);//aidl的实现//ClipboardServicepublic void setPrimaryClip(ClipData clip, String callingPackage) {synchronized (this) {if (clip != null && clip.getItemCount() <= 0) {throw new IllegalArgumentException("No items");}final int callingUid = Binder.getCallingUid();if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,callingPackage) != AppOpsManager.MODE_ALLOWED) {return;}checkDataOwnerLocked(clip, callingUid);final int userId = UserHandle.getUserId(callingUid);PerUserClipboard clipboard = getClipboard(userId);revokeUris(clipboard);setPrimaryClipInternal(clipboard, clip);List<UserInfo> related = getRelatedProfiles(userId);if (related != null) {int size = related.size();if (size > 1) { // Related profiles list include the current profile.boolean canCopy = false;try {canCopy = !mUm.getUserRestrictions(userId).getBoolean(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);} catch (RemoteException e) {Slog.e(TAG, "Remote Exception calling UserManager: " + e);}// Copy clip data to related users if allowed. If disallowed, then remove// primary clip in related users to prevent pasting stale content.if (!canCopy) {clip = null;} else {clip.fixUrisLight(userId);}for (int i = 0; i < size; i++) {int id = related.get(i).id;if (id != userId) {setPrimaryClipInternal(getClipboard(id), clip);}}}}}}

总结

  • 分析安卓系统时,需要记住android的c/s框架。SystemServer提供众多的service。这些service是由ServiceManager来进行管理的。注册时候需要使用ServiceManager.addService进行添加,客户端获取service,需要通过ServiceManager.getService来获取。
  • Context上下文是和应用程序密切相关的。应用程序可以通过Context提供的getSystemService获取系统的服务,比如INPUT_SERVICE。
    这些service的返回值通常是xxxManger 例如InputManager. 在这个xxxManager类中,调用了ServiceManager.getService。因此这个xxxManager就是在进一步的封装,提供了一些相关的方法。但是这些方法,最终还是通过获取的那个service,通过binder,调用系统提供的服务来实现的。
  • 在系统和应用之前进行传递的是通过binder方式来进行的。在java层层面试下binder机制,需要使用AIDL。在aidl中定义接口,并在系统服务中实现这些接口,通常是实现接口的内部类stub。 并在SystemService中添加到系统中。

这篇关于android硬件访问服务程序框架和简单实例分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1140218

相关文章

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

MyBatis Plus大数据量查询慢原因分析及解决

《MyBatisPlus大数据量查询慢原因分析及解决》大数据量查询慢常因全表扫描、分页不当、索引缺失、内存占用高及ORM开销,优化措施包括分页查询、流式读取、SQL优化、批处理、多数据源、结果集二次... 目录大数据量查询慢的常见原因优化方案高级方案配置调优监控与诊断总结大数据量查询慢的常见原因MyBAT

分析 Java Stream 的 peek使用实践与副作用处理方案

《分析JavaStream的peek使用实践与副作用处理方案》StreamAPI的peek操作是中间操作,用于观察元素但不终止流,其副作用风险包括线程安全、顺序混乱及性能问题,合理使用场景有限... 目录一、peek 操作的本质:有状态的中间操作二、副作用的定义与风险场景1. 并行流下的线程安全问题2. 顺

PyQt6 键盘事件处理的实现及实例代码

《PyQt6键盘事件处理的实现及实例代码》本文主要介绍了PyQt6键盘事件处理的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起... 目录一、键盘事件处理详解1、核心事件处理器2、事件对象 QKeyEvent3、修饰键处理(1)、修饰键类

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

Java 缓存框架 Caffeine 应用场景解析

《Java缓存框架Caffeine应用场景解析》文章介绍Caffeine作为高性能Java本地缓存框架,基于W-TinyLFU算法,支持异步加载、灵活过期策略、内存安全机制及统计监控,重点解析其... 目录一、Caffeine 简介1. 框架概述1.1 Caffeine的核心优势二、Caffeine 基础2

Python实现简单封装网络请求的示例详解

《Python实现简单封装网络请求的示例详解》这篇文章主要为大家详细介绍了Python实现简单封装网络请求的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录安装依赖核心功能说明1. 类与方法概览2.NetHelper类初始化参数3.ApiResponse类属性与方法使用实

Java中最全最基础的IO流概述和简介案例分析

《Java中最全最基础的IO流概述和简介案例分析》JavaIO流用于程序与外部设备的数据交互,分为字节流(InputStream/OutputStream)和字符流(Reader/Writer),处理... 目录IO流简介IO是什么应用场景IO流的分类流的超类类型字节文件流应用简介核心API文件输出流应用文