Android硬件访问服务-Service

2023-05-16

Android有四大组件
一、Activity
二、Service
三、Broadcast Receiver
四、Content Provider


这里写图片描述

Service是Android中一个类,它是Android四大组件之一,使用Service可以在后台执行长时间的操作( perform long-running operations in the background ),Service并不与用户产生UI交互。其他的应用组件可以启动Service,即便用户切换了其他应用,启动的Service仍可在后台运行。一个组件可以与Service绑定并与之交互,甚至是跨进程通信(IPC)。例如,一个Service可以在后台执行网络请求、播放音乐、执行文件读写操作或者与 content provider交互 等。

由于上一章JNI直接访问硬件可能导致多个应用同时访问一个驱动,就可能导致驱动出现问题,所以我们可以只让一个应用程序来访问硬件,这个应用程序成为“SystemServer”,APP有应用请求统一发给它,由它统一管理所有的service。而我们这章的目的也是建立一个led service。

SystemServer使用java写的,访问硬件只能用C,所以中间也需要使用JNI。
SystemServer的源码在android目录下:
frameworks\base\services\java\com\android\server\SystemServer.java


这里先概述一下SystemServer的过程

  1. 通过LoadLibrary来加载C库,
  2. C库的JNI_Onload函数里面注册本地方法,分别调用各个硬件的函数来注册本地方法,比如LED、振动器、串口等等
  3. SystemServer:对每个硬件addService(Server里面有很多个Service,由Server提供Service),每个硬件都需构造Service(即注册本地方法)
  4. APP使用:
    首先获得服务:get Service
    然后使用服务:执行Service方法

SystemServer源码解析
文件:SystemServer.java
SystemServer在源码中是一个类,里面实现了很多类方法,以Vibrator这个service作为参考例子,模仿写一个led service,我们从main这个方法开始解析

  • Main()
    – SystemServer().run()
    -----System.loadLibrary(“android_servers”)—>初始化native service,即加载C库,对应文件是 onload.cpp,里面有JNI_OnLoad,用于注册本地方法
    --------Register_android_server_VibratorService(env)—>对应com_ android_server_VibratorService(对应文件名),里面负责实现native方法
    -----StartOtherServices()—>里面定义了各种service—>new VibratorService—>addService

想要APP能使用service需要注册添加各种service进service_manager.c,然后通过getService来获取接口,自己添加的驱动就需要在这里面addService,最上面那副图中的几个进程都会涉及到Binder driver,这个驱动程序并不是内核自带的,而是google公司对linux内核做的修改,添加的一个驱动程序,它可以实现更加高效的进程间通信。


接下来以代码的形式描述一下上面的整个过程,从APP—>server—>service—>JNI(其实应该还有个HAL,但这章主要描述service的建立过程,HAL放到下一章讲)。


整个过程文字描述如下

  1. 实现一个aidl(Android接口定义语言)文件,写出这个文件后用Android系统里面的编译命令让它帮我们自动生成那个ILedService.java(接口)文件,怎么写参考源码目录framework里面的振动器代码(IVibratorService.aidl,位于frameworks目录),这个aidl文件位于源码目录下的frameworks/base/core/java/android/os,然后修改它的Android.mk (位于frameworks/base/),vi Android.mk,全局搜索关键字“Virbrator”可以找到相应的aidl文件定义,添加上我们自己的Led(core/ java/android/os /ILedService.aidl)文件即可,修改完后在目录(frameworks/base/)下执行mmm .(mmm <目录名>)命令,可能会遇到报错(mmm: command not found),在android源码目录下执行“. build/envsetup.sh”即可解决,执行mmm .后系统会帮我们自动生成ILedService.java文件。编译成功后在out目录下搜索“find –name “ILedService.java””可以找到相应生成的java接口文件

  2. 实现LedService.java
    里面主要实现调用我们定义的本地方法然后修改SystemServer.java把这个service添加进去,之后APP就可以通过getService获得LedService从而操作LED了

  3. 实现com_android_server_LedService.cpp
    上面LedService.java的方法都是由这个文件来实现的,即JNI的相关代码,主要将数组里面的方法注册到LedService这个方法里面,并修改Onload.cpp将这个注册函数添加进去

  4. APP使用
    ILedService iLedService;
    iLedService = ILedService.Stub.asInterface(ServiceManager.getService(“led”));
    iLedService.ledCtrl(0, 1);


整个过程代码描述如下

(1) AIDL

1. 把 ILedService.aidl 放入 frameworks/base/core/java/android/os
aidl代码如下:	
package android.os;
	
	/** {@hide} */
	interface ILedService
	{
		int ledCtrl(int which, int status);
	}
2. 修改 frameworks/base/Android.mk  添加一行
         core/java/android/os/IVibratorService.aidl \
+        core/java/android/os/ILedService.aidl \

3. mmm frameworks/base(这里需要在源码根目录先运行. build/envsetup.sh)

4. 它会生成: ./out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/ILedService.java

5. ILedService.java里面定义了ledCtrl,我们需要去实现这个方法

(2) Server

实现:LedService.java

非常简单,就是提供native方法,这些方法最后需要我们写JNI代码去实现,代码如下:

package com.android.server;

import android.os.ILedService;


/* defind a LedService class */
public class LedService extends ILedService.Stub {
    private static final String TAG = "LedService";

	/* call native c function to access hardware */
	public int ledCtrl(int which, int status) throws android.os.RemoteException
	{
		return native_ledCtrl(which, status);/* this is a native method */

	}

	public LedService(){
		native_ledOpen();
		
	}
	
	public static native int native_ledCtrl(int which, int status);
	
	public static native int native_ledOpen();
	
	public static native void native_ledClose();
}

把写好的service上传到服务器编译,上传到目录:
frameworks/base/services/core/java/com/android/server/LedService.java

由于添加了新的service,所以我们需要去修改下SystemServer.java,参考vibrator的这个service写即可,添加如下代码到startOtherServices:

Slog.i(TAG, "Led Service");
			ServiceManager.addService("led", new LedService());//The 'new' can call LedService Constructor

修改完后重新上传至:
frameworks/base/services/java/com/android/server/SystemServer.java

这里我们不需要去修改 frameworks/base/services/core/Android.mk
因为它的内容里已经把该目录下所有JAVA文件自动包含进去了,后面编译会自动重新加载这两个java文件:

LOCAL_SRC_FILES += \
    $(call all-java-files-under,java)

(3) JNI

实现:com_android_server_LedService.cpp

上面LedService.java的方法都是由这个文件来实现的,即JNI的相关代码,主要将数组里面的方法注册到LedService这个方法里面,并修改Onload.cpp将这个注册函数添加进去,代码如下:

#define LOG_TAG "LedService"

#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"

#include <utils/misc.h>
#include <utils/Log.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>


namespace android
{
	static jint fd;

	jint ledOpen(JNIEnv *env, jobject cls)
	{
		fd = open("/dev/leds_node", O_RDWR);//打开设备LED节点
		ALOGI("native ledOpen : %d", fd);
		if (fd >= 0)
			return 0;
		else
			return -1;
	}
	
	   
	void ledClose(JNIEnv *env, jobject cls)
	{
	  ALOGI("native ledClose ...");
	  close(fd);
	}

	jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
	{
		int ret = ioctl(fd, which, status);//给设备节点传输控制信息
		ALOGI("native ledCtrl : %d, %d, %d", which, status, ret);
		return ret;
	}

	/* 定义JNI字段描述符 */
	static const JNINativeMethod methods[] = {//定义一个映射数组
		{"native_ledOpen", "()I", (void *)ledOpen},//对应c语言的ledOpen,这个函数没有参数,返回值是int类型
		{"native_ledClose", "()V", (void *)ledClose},//对应c语言的ledClose,这个函数没有参数,返回值是void类型
		{"native_ledCtrl", "(II)I", (void *)ledCtrl},//对应c语言的ledCtrl,这个函数有两个int参数,返回值是int类型
	};
		
	int register_android_server_LedService(JNIEnv *env)
	{
		//注册方法
		return jniRegisterNativeMethods(env, "com/android/server/LedService",
				methods, NELEM(methods));
	}
}

onload.cpp添加如下代码:

namespace android {
	........
	int register_android_server_LedService(JNIEnv* env);
}
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
	........
	register_android_server_LedService(env);
}

把新文件上传到服务器, 所在目录:
frameworks/base/services/core/jni/onload.cpp
frameworks/base/services/core/jni/com_android_server_LedService.cpp

修改 frameworks/base/services/core/jni/Android.mk :

  • $(LOCAL_REL_DIR)/com_android_server_LedService.cpp

编译:
mmm frameworks/base/services
make snod


修改APP使用Service(此APP基于上一章“Android硬件访问服务-JNI”)

原来我们使用HardConrtol这个在JNI里面定义的类来访问,现在我们可以直接使用service来访问
首先在工程的MainActivity.java里面导入:

import android.os.ILedService;
import android.os.ServiceManger;

在MainActivity这个类里面添加如下:

/* 定义一个Service成员 */
private ILedService iLedService = null;

在OnCreate函数里面给service赋值,并且去掉之前的HardControl.ledopen()函数

/* 给service赋值*/
iLedService = ILedService.Stub.asInterface(ServiceManager.getService(“led”));

Ctrl+R将所有的hardcontrol替换为ILedService


工程中需要包含什么:
在linux系统下Android源码目录使用指令:mmm frameworks/base show commands > log.txt 2>&1可以看到aidl文件修改后会涉及哪些文件,从这个文件里面我们可以看出最后会生成一个framework.jar文件,由于我们的ledservice是一个隐藏类(使用/** {@hide} */关键字描述的部分),所以我们是不是需要导入这个framework.jar呢?经搜索后发现我们应该导入classes.jar文件,因为framework.jar文件是dex格式文件,我们的android运行的程序并不是原原本本的java程序,它是把这些java目标文件转换为了dex格式的文件,dex文件是对java文件做了一些优化
jar文件目录:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar

Android studio软件打开File->Project Structure ->左上角的’+’号添加->import .JAR->找到classed.jar文件导入->打开Modules下app的Dependencies->右边‘+’号添加classes即可,如下图
这里写图片描述

在build.gradle(Module.app)里面添加如下几项:

android {
.......
	defaultConfig {
		....
        multiDexEnabled true
    }
    dexOptions{
        javaMaxHeapSize "4g"
    }
.......
}

dependencies {
	....
    compile project(':classes')
}

在AndroidManifest.xml文件里面的“application”添加如下

<manifest .....>

    <application
        android:name = "android.support.multidex.MultiDexApplication"
        ......
    </application>

</manifest>

解决以上编译错误的参考文章如下(大部分网址需要翻墙访问):

How do I build the Android SDK with hidden and internal APIs available?
http://stackoverflow.com/questions/7888191/how-do-i-build-the-android-sdk-with-hidden-and-internal-apis-available

Creating a module library and adding it to module dependencies
https://www.jetbrains.com/idea/help/configuring-module-dependencies-and-libraries.html

java.lang.OutOfMemoryError: GC overhead limit exceeded
Android Studio Google jar causing GC overhead limit exceeded error
http://stackoverflow.com/questions/25013638/android-studio-google-jar-causing-gc-overhead-limit-exceeded-error

Too many field references
Building Apps with Over 65K Methods
https://developer.android.com/tools/building/multidex.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android硬件访问服务-Service 的相关文章

  • 蓝牙Mesh网络性能及网络特点总结(一)

    原文链接 xff1a 欢迎关注公众号 智联网事 xff0c 一周一篇原创文章 xff0c 一起探讨智联网 https mp weixin qq com s biz 61 MzI3NDE2NDMwNQ 61 61 amp mid 61 264
  • 华为物联网(IOT)开发者平台

    智联网事 关注与分享 xff0c 是对原创最大的鼓励 原文链接 https mp weixin qq com s biz 61 MzI3NDE2NDMwNQ 61 61 amp mid 61 2649905835 amp idx 61 1
  • Kubernetes v1.21.14二进制搭建单节点集群

    1 集群环境准备 1 1 主机规划 IP主机名主机角色操作系统安装组件192 168 11 71k8s master1master workerCentos7 9api server controller manager scheduler
  • shell脚本第一行:#!/bin/bash的含义

    相信有接触过shell脚本的同学们都应该知道 xff0c shell脚本的第一行一般会写有以下字样 xff1a bin bash或者 bin sh或者 bin awk 比较常见的说法是 xff1a 第一行的内容指定了shell脚本解释器的路
  • LPMS-IMU姿态解算

    参考文章 xff1a AHRS姿态解算说明 加速度 43 陀螺仪 43 磁力计原理及原始数据分析 AHRS俗称航姿参考系统 xff0c AHRS由加速度计 xff0c 磁场计 xff0c 陀螺仪构成 xff0c AHRS的真正参考来自于地球
  • 如何在我的VsCode中集成Git

    在VsCode中配置Git后 xff0c 我们就可以简单快速管理我们的代码仓库 一 下载安装Git 如果没有Git xff0c 这里可以参考我之前的文章安装 配置Git 精讲Git xff08 从安装到熟练使用一文全解 xff0c 看完轻松
  • 虚拟机:xshell连接虚拟机Ubuntu失败解决方法

    当我们买不起服务器但却想模拟服务器环境进行学习时 xff0c 再好不过的就是直接装Linux虚拟机了 xff0c 非常简单快捷 xff01 首先我们可以通过ifconfig a来查看Ubuntu Server的IP地址 xff08 前提是你
  • SVM原理:超平面方程

    xff08 1 xff09 超平面方程 3维空间中平面方程的一般形式 xff1a 1 我们都知道为平面到原点的距离 这里简单证明超平面的法向量为 d维空间平面方程的一般形式 xff1a 2 平面的法向量为 xff0c xff08 分号表示列
  • windows11编译OpenCV4.5.0 with CUDA(附注意事项)

    windows11编译OpenCV4 5 0 with CUDA 从OpenCV4 2 0 版本开始允许使用 Nvidia GPU 来加速推理 本文介绍最近使用windows11系统编译带CUDA的OpenCV4 5 0的过程 文中使用 特
  • Windows11安装Detectron2(附详细操作指南)

    Windows11安装Detectron2 0 简介 Detectron2 是 Facebook AI Research 的下一代目标检测库 xff0c 可提供最先进的检测和分割算法 它是 Detectron 和 maskrcnn benc
  • 四轴飞行器F450+Futaba 14SG+好盈电调油门行程校准

    F450 43 Futaba 14SG油门行程校准 装机前忘了进行油门校准 xff0c 装好后进行校准一开始老出现电机接收不到油门信号的提示音 因为Futaba 14SG也是新入手的控 xff0c 有些模式和操作不熟悉 xff0c 为此花了
  • NTKO控件安装:“不能装载文档控件,请在检查浏览器的选项中检查浏览器的安全设置”问题

    上礼拜手欠把OFFICE文档控件 NTKO给卸载了 xff0c 结果这周通知基金结题网上填写报告 本以为就装个控件 xff0c 没想到各种问题 xff0c 几经尝试终于解决 xff0c 总结如下 xff1a 1 问题 xff1a 不能装载文
  • Arduino - 串口操作函数与示例代码大全

    Arduino 串口操作函数与示例代码大全 本文总结了Arduino常用串口操作函数 xff0c 函数说明部分来源于Arduino 官网串口使用指南 xff0c 示例与实验部分为自编 本文是对Arduino串口操作函数的较全面总结 xff0
  • vs2010 出错:error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

    LNK1123 转换到 COFF期间失败 文件无效或损坏 的解决方法 一 错误描述 之前写的程序隔段时间使用VS2010再次运行时出现如下错误 xff1a LINK fatal error LNK1123 转换到 COFF 期间失败 文件无
  • OpenCV—基本矩阵操作与示例

    OpenCV的基本矩阵操作与示例 OpenCV中的矩阵操作非常重要 xff0c 本文总结了矩阵的创建 初始化以及基本矩阵操作 xff0c 给出了示例代码 xff0c 主要内容包括 xff1a 创建与初始化 矩阵加减法 矩阵乘法 矩阵转置 矩
  • ubuntu16.04下利用ROS启动LPMS-CURS、CURS2等型号IMU;用imu控制turtlesim--教程

    文章目录 IMU型号及协议第一步 下载安装 LPsensor library第二步 设置ROS和carkin工作空间第三步 下载编译LPMS IMU的ROS驱动第四步 启动IMU xff08 可能也会遇到问题 xff09 遇到的问题1 ub
  • PixHawk飞控和Mission Planner地面站安装调试

    PixHawk飞控和Mission Planner地面站安装调试 PixHawk是著名飞控厂商3DR推出的新一代独立 开源 高效的飞行控制器 xff0c 前身为APM飞控 xff0c 不仅提供了丰富的外设模块和可靠的飞行体验 xff0c 有
  • 飞越650四轴无人机安装全程详解(多图)

    飞越650四轴无人机安装全程详解 xff08 多图 xff09 本文根据自己的安装实际过程 xff0c 总结了开箱后一个比较合理的650四轴无人机安装顺序 xff0c 以及各个步骤的注意事项 xff0c 主要内容包括 xff1a 系统基本配
  • DIY一个基于树莓派和Python的无人机视觉跟踪系统

    DIY 一个基于树莓派和Python的无人机视觉跟踪系统 无人机通过图传将航拍到的图像存储并实时传送回地面站几乎已经是标配 如果想来点高级的 在无人机上直接处理拍摄的图像并实现自动控制要怎么实现呢 xff1f 其实视觉跟踪已经在一些高端的消
  • windows环境下的Anaconda安装与OpenCV机器视觉环境搭建

    windows环境下的Anaconda安装与OpenCV机器视觉环境搭建 本文介绍win7和win10系统下通过Anaconda配置基于python语言的机器视觉编程环境 xff08 博主测试了两个系统下的安装基本相同 xff09 xff0

随机推荐

  • OpenCV—轮廓操作一站式详解:查找/筛选/绘制/形状描述与重心标注(C++版)

    OpenCV 轮廓操作一站式详解 xff1a 查找 筛选 绘制 形状描述与重心标注 C 43 43 版 轮廓 是定义或限定形状或对象的边或线 xff0c 是机器视觉中的常用的概念 xff0c 多用于目标检测 识别 等任务 关于OpenCV轮
  • 正太分布函数和反函数 标量值函数 (借鉴)

    标准正态分布函数 CREATE function dbo normcdf 64 p decimal 28 18 AS begin
  • 离散时间傅里叶变换(一)

    一 非周期信号的表示 xff1a 离散时间博里叶变换 1 1 离散时间傅里叶变换的导出 1 离散时间傅里叶变换对 要清楚推导过程 X ejw 称为离散时间傅里叶变换 xff0c 这一对式子就是离散时间傅里叶变换对 上式称为综合公式 xff0
  • HuskyLens摄像头系列 | 写给小学生看的视觉PID巡线算法

    Hello xff0c 大家好 xff0c 光天化日之下我又来撸狗了 距离上次撸狗已经过去了个把月时间了 xff0c 那么这次又有什么新惊喜呢 xff1f 先来看一下本期的演示视频吧 https www bilibili com video
  • 时空行为检测数据集 JHMDB & UCF101_24 详解

    文章目录 0 前言1 JHMDB1 1 基本情况1 2 数据准备以及标签详解 2 UDF101 242 1 基本情况2 2 数据准备与标签详解 3 数据集可视化代码 0 前言 现在常用的时空行为检测数据集只有AVA JHMDB UCF101
  • Lock与RLock的区别

    目录 往期推荐介绍区别一区别二 往期推荐 Python多线程的使用 Python线程池的使用 Python多线程的安全问题 B站同名 有温度的算法 已经上线 想观看视频讲解的同学 点击此处直达B站 介绍 在上节中为大家说明了线程访问临界资源
  • ROS 小技巧 - OpenCV4 与 CV_Bridge 配合使用

    1 现象 ROS默认的Python版本是3 3 xff0c 但我系统安装的是OpenCV4 5 如果直接在pkg中使用cv bridge和opencv4 5就会有问题 会有一些undefined reference问题 参考资料 xff1a
  • 【做题系统】后端设计

    目录 一 设计思路 1 项目背景 2 技术栈选择 二 系统设计 1 系统结构图 2 项目结构 3 数据建模 4 数据流图 5 主要流程图 三 问题及解决办法 1 实现安全登录 访问 2 数据库中的信息安全问题 3 Mybatis plus如
  • C/C++字符串查找函数

    C C 43 43 string库 xff08 string h xff09 提供了几个字符串查找函数 xff0c 如下 xff1a memchr在指定内存里定位给定字符strchr在指定字符串里定位给定字符strcspn返回在字符串str
  • ssh命令-manpage

    SSH Section User Commands 1 Index Return to Main Contents BSD mandoc NAME ssh OpenSSH SSH 客户端 远程登录程序 总览 SYNOPSIS ssh l l
  • 一小时做出Java实战项目——飞翔的小鸟

    学姐又来啦 xff0c 今日分享一个Java实战项目 飞翔的小鸟 相信大家都玩过这个游戏 xff0c 这个游戏陪伴了我们整整一个童年 xff0c 是我们青春的回忆 飞翔的小鸟 xff0c 游戏中玩家只需通过点击方向键操纵让小鸟避开绿色管道等
  • 搭建本地仓库源

    一 如何搭建仓库源 之前讲了定制ISO的方法 xff1a 使用chroot定制系统 xff0c 但有时候我们想自定义的安装包不在上游的仓库源中 xff0c 在我们本地应该怎么办呢 xff1f 如果我们将deb包拷贝到iso目录再安装有点过于
  • 节点操作案例

    1 下拉菜单 xff08 仿微博 xff09 lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt me
  • document获取对象的三种三方法

    Document对象中有几个常用的方法 xff0c 我们在Dom简介中提到过 说到获取JavaScript对象的方法 xff0c 最常用的可能就是getElementById了 xff0c 它是Document中最常用的获取对象的方式之一
  • 程序员,最关键的跨越是什么?做到了月薪可能翻上几番~

    黑马程序员视频库 播妞微信号 xff1a boniu236 传智播客旗下互联网资讯 学习资源免费分享平台 作为一名程序员 xff0c 最关键的跨越是什么 xff1f 从普通程序员进阶为熟练开发者 xff0c 从熟练开发者跃升到技术专家或架构
  • 黑马程序员:3分钟带你读懂C/C++学习路线

    随着互联网及互联网 43 深入蓬勃的发展 xff0c 经过40余年的时间洗礼 xff0c C C 43 43 俨然已成为一门贵族语言 xff0c 出色的性能使之成为高级语言中的性能王者 而在今天 xff0c 它又扮演着什么样重要的角色呢 x
  • 数据归一化

    原文链接 xff1a 从公式出发 xff1a 什么是模型收敛的有效方法 xff1f 大家好 xff0c 我是泰哥 数据归一化在模型收敛中起着至关重要的作用 xff0c 从经典机器学习到深度学习的数据归一化方法是如何一步步演变的呢 xff1f
  • 【Python面试】 说说Python变量、函数、类的命名规则?

    最近公众号新增加了一个栏目 xff0c 就是每天给大家解答一道Python常见的面试题 xff0c 反正每天不贪多 xff0c 一天一题 xff0c 正好合适 xff0c 只希望这个面试栏目 xff0c 给那些正在准备面试的同学 xff0c
  • ​LeetCode刷题实战46:全排列

    算法的重要性 xff0c 我就不多说了吧 xff0c 想去大厂 xff0c 就必须要经过基础知识和业务逻辑面试 43 算法面试 所以 xff0c 为了提高大家的算法能力 xff0c 这个公众号后续每天带大家做一道算法题 xff0c 题目就从
  • Android硬件访问服务-Service

    Android有四大组件 xff1a 一 Activity 二 Service 三 Broadcast Receiver 四 Content Provider Service是Android中一个类 xff0c 它是Android四大组件之