Android硬件访问服务-Service
来源:互联网 发布:mac 文件重命名 命令 编辑:程序博客网 时间:2024/05/21 19:48
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的过程:
- 通过LoadLibrary来加载C库,
- C库的JNI_Onload函数里面注册本地方法,分别调用各个硬件的函数来注册本地方法,比如LED、振动器、串口等等
- SystemServer:对每个硬件addService(Server里面有很多个Service,由Server提供Service),每个硬件都需构造Service(即注册本地方法)
- 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放到下一章讲)。
整个过程文字描述如下:
实现一个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接口文件
实现LedService.java
里面主要实现调用我们定义的本地方法然后修改SystemServer.java把这个service添加进去,之后APP就可以通过getService获得LedService从而操作LED了实现com_android_server_LedService.cpp
上面LedService.java的方法都是由这个文件来实现的,即JNI的相关代码,主要将数组里面的方法注册到LedService这个方法里面,并修改Onload.cpp将这个注册函数添加进去APP使用
ILedService iLedService;
iLedService = ILedService.Stub.asInterface(ServiceManager.getService(“led”));
iLedService.ledCtrl(0, 1);
整个过程代码描述如下:
(1) AIDL
1. 把 ILedService.aidl 放入 frameworks/base/core/java/android/osaidl代码如下:
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.java5. 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, status, which);//给设备节点传输控制信息 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
- Android硬件访问服务-Service
- Android 硬件访问服务
- Android硬件访问服务
- 开发Android硬件访问服务
- 开发Android硬件访问服务
- Android 编写硬件访问服务
- Android添加硬件访问服务
- Android硬件访问服务框架
- Android硬件访问服务-JNI
- Android硬件访问服务-HAL
- Android硬件访问服务学习之(二)Android通过硬件访问服务访问硬件
- 编写Android应用程序验证硬件访问服务
- android app 访问framework硬件服务
- Android硬件访问服务框架分析
- Android硬件访问服务框架代码编写
- Android 6.0中添加硬件访问服务
- android系统源码分析,硬件访问服务
- android系统级别硬件访问服务程序
- Unix is 命令 (排序和字符串处理) UVA
- jQuery中filter()和find()的区别深入了解
- Oracle where条件,当天时间段
- HDU 3697 Selecting courses
- Glide使用详解(二)
- Android硬件访问服务-Service
- android 显示刚刚下载的图片
- Bandwidth UVA
- 最短路径算法模板:Dijkstra/Floyd/Bellman-Ford模板
- Android中Activity的生命周期【详】
- 查看可执行文件依赖的动态库 ldd
- Spring Boot入门二:使用ThymeLeaf+表单验证
- unordered_map及map访问键值速率对比
- python-5-pexpect交互模块