Android开发如何定制framework层服务
刚刚跨完年,新年第一篇文章,那么今天将对Android开发framework中间层的服务定制使用作个总结。首先我们先导入Android平台源码framework层的代码到开发工具eclipse中,代码工程目录如下:
当然了除了用eclipse之外也可以用其它软件进行开发使用,比如用Source Insight 3方式,效果图如下:

那么喜欢哪种就用哪种吧。

我这边这部分代码是经过ATC公司的人移植过后的代码,一般情况下我们要维护这中间层的代码,我们进去某家公司这层的代码估计都是已经写得七七八八的了,我们只是在此基础上进行一个修改及新增一些服务而已。依我个人Android平台android4.2.2项目看包名即可见名知义各个包的责任,我们要修改或者定制自己的服务只需要关心下面两个包就可以了,其它的是SystemUI以及多媒体,蓝牙等相关的包,关键包目录如下:
好的先将上面的放一边,我们且先看看上层是如何使用我们这层定制的服务接口的,这边例举一个个人项目canbus服务接口的使用方式,关键代码如下:


好的先将上面的放一边,我们且先看看上层是如何使用我们这层定制的服务接口的,这边例举一个个人项目canbus服务接口的使用方式,关键代码如下:
private CanCallback mCanCallBack = null;
private ICanbusManager mCanManager = null; mContext = ctx;
mCanCallBack = new CanCallback();
mCanManager = CanbusManager.getInstance();
mCanManager.init(ctx); try {
mCanManager.setcallback(mCanCallBack);
} catch (RemoteException e) {
e.printStackTrace();
}
//******************
if (mCanManager == null) {
mCanManager = CanbusManager.getInstance();
if ((mCanManager != null) && (mCanCallBack != null)) {
try {
mCanManager.setcallback(mCanCallBack);
} catch (RemoteException e) {
e.printStackTrace();
}
}
} if (mCanCallBack == null) {
mCanCallBack = new CanCallback();
if ((mCanManager != null) && (mCanCallBack != null)) {
try {
mCanManager.setcallback(mCanCallBack);
} catch (RemoteException e) {
e.printStackTrace();
}
}
} //************接口实现*****************
private class CanCallback implements IClientCanCallback {
@Override
public void onCanbusEvent(final int paramInt,final byte[] array,final int length) {
byte[] mBuf = new byte[];
if (length > ) {
for (int i = ; i < ; i++) {
mBuf[i] = array[i];
}
} else {
if (length > ) {
for (int i = ; i < length; i++) {
mBuf[i] = array[i];
}
}
} String mBufString = CanHepler.getHexStringOfBytes(mBuf);
LogUtil.systemOutln(mBufString);
// new Thread() {
// public void run() {
// parser(paramInt, array, length);
// };
// }.start(); pushNode(paramInt, array, length); if (mExecutorService == null) {
// mExecutorService = Executors.newCachedThreadPool();
// mExecutorService = Executors.newSingleThreadExecutor();
mExecutorService = Executors.newFixedThreadPool();
} if (mExecutorService != null) {
mExecutorService.execute(new CanRunnable());
}
}
} //*****************向底层发送该数据
public void sendCmdToCan(byte[] data, int nLength){
if(mCanManager != null){
mCanManager.sendCmd(data, nLength);
}
}
以上代码逻辑解释:上层拿到ICanbusManager这个接口即可向底层发送数据,以及注册一个回调底层发送上来的接口IClientCanCallback,即是CanCallback。那么我们在上层即可根据这个ICanbusManager和IClientCanCallback跟踪代码到framework层上面那两个核心包下的代码。
好,那么我们在base/core/java/包下找到ICanbusManager.java的代码实现如下:


如上图可见在ICanbusManager.java类内部是通过CanbusProxy.java这个类去操作的,即在这个包下

我们继续看看;这几个文件的内容:首先这边涉及到aidl的使用,如果对这方面的知识使用不够了解的请自行移步到AIDL实现不同应用之间跨进程通讯及传递与返回各种数据类型和远程接口回调 及Android进程间通信(IPC)机制Binder简要介绍和学习计划 作个详细的理解再回来看看这篇文章
CanbusProxy.java:
public class CanbusProxy {
private static CanbusProxy sCanbusProxyInstance = null;
private Handler mHandler = null;
private ICanbus mCanbusService = null;
static Context mContext = null;
ICanbusCallback mICanbusCallback = null;
IClientCanCallback mIClientCallback = null; public void SetContext(Context context){
mContext = context;
} public static CanbusProxy getInstance() {
if (sCanbusProxyInstance == null)
sCanbusProxyInstance = new CanbusProxy();
return sCanbusProxyInstance;
} private void initService(){
if(null == mCanbusService){
IBinder b = ServiceManager.getService(Context.CANBUS_SERVICE);
mCanbusService = ICanbus.Stub.asInterface(b);
if(null != mCanbusService){
try {
mCanbusService.setCallback(mICanbusCallback);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} private CanbusProxy() { mICanbusCallback = new ICanbusCallback.Stub() {
public void onEvent(int paramInt, byte[] array, int length)
throws RemoteException {
if(null != mIClientCallback){
mIClientCallback.onCanbusEvent(paramInt, array, length);
}
}
}; initService();
} public void setContext(Context context) {
mContext = context;
} public void setHandler(Handler handler){
mHandler = handler;
} public void setCallback(IClientCanCallback paramClientCallback) throws RemoteException {
mIClientCallback = paramClientCallback;
} public void sendCmd(byte[] data, int nLength) throws RemoteException{
initService();
mCanbusService.sndCanCmd(data, nLength);
} }
ICanbusCallback.aidl和ICanbus.aidl如下:


逻辑分析:
看代码可知,那么CanbusProxy.java里面主要就是做了两个操作:
1、利用CanbusManager那边传过来的IClientCanCallback注册到这边ICanbusCallback接口中,这个ICanbusCallback是个aidl文件,我们可通过ICanbusCallback.stub得到,然后实现ICanbusCallback.aidl文件中的接口,就看作上层实现一个interface那样好了,然后再将ICanbusCallback.aidl文件中的接口注册到ICanbus.aidl文件接口中,为什么这边要采用这么麻烦的方式注册两次呢?我们这边直接将这个IClientCanCallback放在ICanbus.aidl文件接口实现处不就好了?看上层的调用方式就可知道,上层是在CanbusManager.getInstance()之后再mCanManager.setcallback(mCanCallBack)的,所以这边需要再抽象一个接口去回调这个IClientCanCallback,否则这个IClientCanCallback将一直为null。
2、封装ICanbus.aidl文件,将回调上层数据的IClientCanCallback以ICanbusCallback.aidl接口方式以及上层向底层发送数据的接口封装到ICanbus.aidl接口里面
那么到此这个包下的内容解释完毕,我们再去看看这个最关键的ICanbus.aidl服务接口实现位置,到底是如何实现的?
那么个人这个framework服务定制所有的aidl服务实现都放在这个base/services/java包下,ICanbus.aidl实现如下:

import com.auto.constant.McuConstant;
import com.auto.mcuservice.McuService;
import com.auto.source.McuCBMService;
import com.auto.source.ICBMCallback; import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.DeadObjectException;
import android.util.Log; public class CanbusService extends ICanbus.Stub implements McuConstant.HostCmd{ private static final String Y_TAG = "liugx";
private McuService mMcuService = null;
private static CanbusService sInstance = null;
ICanbusCallback mCanBusCallback = null; private CanbusService(){
mMcuService = McuService.getMcuService();
} public static CanbusService getInstance() {
if (null == sInstance) {
sInstance = new CanbusService();
}
return sInstance;
} public boolean init(){
return true;
} public void sndCanCmd(byte[] canCmd, int length) throws RemoteException {
mMcuService.SndCmd(CMD_SND_CAN_PUBLIC_CMD, canCmd, length);
} public void setCallback(ICanbusCallback callback) throws RemoteException {
mCanBusCallback = callback;
} public void onMessage(int paramInt, byte[] array, int length) throws RemoteException{
try {
if(null != mCanBusCallback){
mCanBusCallback.onEvent(paramInt, array, length);
}
} catch (DeadObjectException e) {
mCanBusCallback = null;
e.printStackTrace();
Log.e(Y_TAG,"CanbusService::onMessage.DeadObjectException...");
} catch (Exception e) {
mCanBusCallback = null;
e.printStackTrace();
}
}
}
写一个CanbusService类去继承ICanbus.Stub然后实现ICanbus.aidl文件里面的接口方法,CanbusService类代码相当的简单,无非是拿到其它的接口调用一些接口里面的方法或者被其它需要它的接口去getinstance()罢了,ctrl+shift+G看看CanbusService再哪被调用过吧 
另一个MCU的接口我们不用看,看SystemServer的实现就好了,SystemServer.java关键代码:
public class SystemServer {
private static final String TAG = "SystemServer";
public static final int FACTORY_TEST_OFF = ;
public static final int FACTORY_TEST_LOW_LEVEL = ;
public static final int FACTORY_TEST_HIGH_LEVEL = ;
static Timer timer;
static final long SNAPSHOT_INTERVAL = * * ; // 1hr
// The earliest supported time. We pick one day into 1970, to
// give any timezone code room without going into negative time.
private static final long EARLIEST_SUPPORTED_TIME = * ;
/**
* This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
*/
native public static void init1(String[] args);
public static void main(String[] args) {
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it
// shortly.
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// Mmmmmm... more memory!
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
// The syst
这个类代码太长,这是其中一部分,外面还有一个ServerThread线程实现,CanbusService就在外面这个ServerThread线程里做了一个系统服务添加的操作:
在Context内部添加了如下字段:
public static final String CANBUS_SERVICE = "canbusservice";
//public static final String CANBUS_ASIR_SERVICE = "canbusasirservice";
除了CanbusService服务添加之外我们可以看看系统其它服务方式的添加,例如电源管理,larm闹钟,LocationManagerService等等一系列的服务



LocationManagerService.java文件

是不是觉得跟上面那个CanbusService实现方式很相似呢,其实我们定制的一些服务就是仿照系统服务添加方式去做的。。。
那么SystemServer这个类就是Android所有服务启动的起始类,内部有一个main方法实现,其中还有一个本地方法init1()
/**
* This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
*/
native public static void init1(String[] args);
看注释就可以知道这个SystemServer进程是在Zygote 进程init的时候启动的,在Zygote 内部回去回调这个init1(),然后在init1()再去调用这个init2()方法即是启动外面的ServerThread执行一些服务添加及启动操作,对于Android启动流程不是很理解的同学请移步居于mtk芯片安卓车机系统启动流程 作个详细的了解
其实我们也可以在这里继续跟代码看看是怎么在Zygote进程中实现的,我们先找到android_servers这个so库的CPP实现文件目录路径如下:

用Source Insight 3打开这个文件瞧一瞧:

由于导入framework所有相互关联的文件等要耗费很长时间,我这边就点不进去是哪里system_init()这个方法了,有兴趣的同学请继续研究,最后是一路走到这的

那么说了这么多,作个简短的总结吧!首先我们要有Android平台代码,各个平台代码根据厂商不同,定制方式,移植方式又不同,其实我们要在一家公司成熟的代码框架中去修改,去维护这中间层的代码也是很容易的,至于新增加一些服务具体流程就是从SystemServer中开始,然后就是根据framework的os目录结构写一些接口实现文件供上层使用即可。
Android开发如何定制framework层服务的更多相关文章
- AI应用开发实战 - 定制化视觉服务的使用
AI应用开发实战 - 定制化视觉服务的使用 本篇教程的目标是学会使用定制化视觉服务,并能在UWP应用中集成定制化视觉服务模型. 前一篇:AI应用开发实战 - 手写识别应用入门 建议和反馈,请发送到 h ...
- 【Android】Sensor框架Framework层解读
Sensor整体架构 整体架构说明 黄色部分表示硬件,它要挂在I2C总线上 红色部分表示驱动,驱动注册到Kernel的Input Subsystem上,然后通过Event Device把Sensor数 ...
- Android如何完全调试framework层代码
1 之前写过一篇文章:<Android实现开机调试system_process> 2 google的eclipse插件ADT的已经能够很方便的调试Android的apk了,但是调试的时候应 ...
- Android开发实践:Java层与Jni层的数组传递
转载:http://www.linuxidc.com/Linux/2014-03/97561.htm Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是 ...
- 为Android开发人员定制的搜索引擎
我在谷歌上定制了一个专门针对Android开发人员的搜索引擎.载入慢的童鞋考虑FanQiang吧,作为技术人员使用Google才是王道. 在此推荐给大家:cx=01590883735180208228 ...
- Android开发技巧——定制仿微信图片裁剪控件
拍照--裁剪,或者是选择图片--裁剪,是我们设置头像或上传图片时经常需要的一组操作.上篇讲了Camera的使用,这篇讲一下我对图片裁剪的实现. 背景 下面的需求都来自产品. 裁剪图片要像微信那样,拖动 ...
- android开发对应高德地图定位服务进度一
进行android的高德地图开发首先需要进入高德地图的控制台进行注册登录.之后创建新的应用并且绑定软件得到相应的key. 这里面需要找到自己软件对应的多个SHA1.这里有发布版和调试版,以及对应的软件 ...
- 在Android开发中调用Rest web服务(转)
首先从维基百科上拷贝一点Rest的基本概念给大家看看,然后我们再开始详解在Android中如何调用Rest服务.表象化状态转变(英文:Representational State Transfer,简 ...
- android开发之定制ViewPager滑动事件
明天还要加班,苦逼的程序猿,简单说说最近遇到的一个问题吧. 我在viewpager+fragment学习笔记中简单介绍过ViewPager+Fragment的用法,其实并不难,当时实现了一个如下图所示 ...
随机推荐
- JAVA编程思想第一章——对象导论
- 在微信移动端input file拍照或从相册选择照片后会自动刷新页面退回到一开始网站进入的页面
<input type="file" accept="image/*"/> 调用打开摄像头后,聚焦后拍照,点击确认,这时页面会出现刷新动作,然后回退 ...
- golang (4) golang 操作mongdb
1. 数据按照时间聚合操作 1.1 正常的数据结构 { "_id" : ObjectId("5cac8d7b1202708adf5d4b64"), " ...
- 《LeetBook》leetcode题解(7): Reverse Integer[E]——处理溢出的技巧
我现在在做一个叫<leetbook>的开源书项目,把解题思路都同步更新到github上了,需要的同学可以去看看 书的地址:https://hk029.gitbooks.io/leetboo ...
- 使用Java Servlet进行简单登录
效果图 登录页面代码:login.html <%@ page language="java" contentType="text/html; charset=UTF ...
- python-TCP传输模型
#!/usr/bin/python #coding=utf-8 #服务器端 from socket import * from time import ctime HOST="192.168 ...
- 师傅领进门之6步教你跑通一个AI程序!
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由云计算基础发表于云+社区专栏 源码下载地址请点击原文查看. 初学机器学习,写篇文章mark一下,希望能为将入坑者解点惑.本文介绍一些机 ...
- jdbc oracle clob
import java.io.BufferedReader; import java.io.Reader; import java.io.Writer; import java.sql.Callabl ...
- C#通过XML导出Excel
最近IOS项目中有手机生成Excel,让我想起了之前做C#时做的生成Excel的,之前都放在空间日志中,今天把它弄到博客中分享一下
- Paypal如何实现循环扣款(订阅)?
起因 业务需求要集成Paypal,实现循环扣款功能,然而百度和GOOGLE了一圈,除官网外,没找到相关开发教程,只好在Paypal上看,花了两天后集成成功,这里对如何使用Paypal的支付接口做下总结 ...