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[20]; if (length > 20) { for (int i = 0; i < 20; i++) { mBuf[i] = array[i]; } } else { if (length > 0) { for (int i = 0; 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(1); } 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 = 0; public static final int FACTORY_TEST_LOW_LEVEL = 1; public static final int FACTORY_TEST_HIGH_LEVEL = 2; static Timer timer; static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 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 = 86400 * 1000; /** * 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目录结构写一些接口实现文件供上层使用即可。