剛剛跨完年,新年第一篇文章,那麼今天將對Android開發framework中間層的服務定製使用作個總結。首先我們先導入Android平臺源碼framework層的代碼到開發工具eclipse中,代碼工程目錄如下:
當然了除了用eclipse之外也可以用其它軟件進行開發使用,比如用Source Insight 3方式,效果圖如下:
那麼喜歡哪種就用哪種吧。
我這邊這部分代碼是經過ATC公司的人移植過後的代碼,一般情況下我們要維護這中間層的代碼,我們進去某家公司這層的代碼估計都是已經寫得七七八八的了,我們只是在此基礎上進行一個修改及新增一些服務而已。依我個人Android平臺android4.2.2項目看包名即可見名知義各個包的責任,我們要修改或者定製自己的服務只需要關心下面兩個包就可以了,其它的是SystemUI以及多媒體,藍牙等相關的包,關鍵包目錄如下:
好的先將上面的放一邊,我們且先看看上層是如何使用我們這層定製的服務接口的,這邊例舉一個個人項目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目錄結構寫一些接口實現文件供上層使用即可。