天天看點

linux程序間通訊 aidl,極簡開發 -- 程序間通訊架構非AIDL(IPCCommunication)

程序間通信

說到Android程序間通信,大家肯定能想到的是編寫aidl檔案,然後通過aapt生成的類友善的完成服務端,以及用戶端代碼的編寫。

為什麼要寫這個架構

曾經聽過一個人說過,程式中盡量使用通用元件或者架構,這樣可以盡量的少寫代碼,這樣有兩個好處,一是少寫代碼就意味着少犯錯誤,二是可以多出喝咖啡的時間 ;

使用

手寫Binder方式有兩種方式

1.使用通用的IPCService服務庫,包括與Activity通信

服務端

服務端可以通過Activity 啟動也可以不啟動,若不啟動可以通過繼承BaseIPCService的方式,具體實作檢視SimpleService

public class MainActivity extends AppCompatActivity {

private ServiceUtils mServiceUtils;

private static final String TAG = "jcy_service";

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mServiceUtils = new ServiceUtils(this);

}

@Override

protected void onResume() {

super.onResume();

//調用預設IPC 服務

mServiceUtils.setConnectListener(mConnectListener);

mServiceUtils.bindService();

}

@Override

protected void onStop() {

super.onStop();

}

@Override

protected void onDestroy() {

super.onDestroy();

mServiceUtils.unBindService();

}

ConnectListener mConnectListener = new ConnectListener() {

@Override

public void onBind() {

}

@Override

public void onDisconnected() {

}

@Override

public void onConnected(boolean success) {

mServiceUtils.setReceiverListener(mReceiverListener);

}

@Override

public void onUnbind() {

mServiceUtils.setReceiverListener(null);

}

;

};

private ReceiverListener mReceiverListener = new ReceiverListener() {

@Override

public Bundle receiveInfo(int code, Bundle msg) {

String msgStr = msg.getString("msgStr");

int msgInt = msg.getInt("msgInt");

Log.d(TAG, "receiveInfo: msgStr " + msgStr + " ,msgInt : " + msgInt);

Bundle ret = new Bundle();

ret.putString("return", "服務端傳回 code " + code + " ,msgStr " + msgStr + " ,msgInt : " + msgInt);

return ret;

}

};

}

用戶端

public class MainActivity extends AppCompatActivity {

private static final String TAG = "jcy_client_one";

private TextView mTextView;

private TextView tv_state;

private ClientUtils mClientUtils;

private Button btnGet, btn_bind, btn_unbind;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mTextView = (TextView) findViewById(R.id.tv_service);

tv_state = (TextView) findViewById(R.id.tv_state);

btnGet = (Button) findViewById(R.id.btn_getService);

btn_bind = (Button) findViewById(R.id.btn_bind);

btn_unbind = (Button) findViewById(R.id.btn_unbind);

btnGet.setEnabled(false);

tv_state.setText(" 服務未綁定 ");

mClientUtils = new ClientUtils(this);

mClientUtils.setConnectListener(mConnectListener);

btn_bind.setEnabled(true);

btn_unbind.setEnabled(false);

}

@Override

protected void onResume() {

super.onResume();

}

@Override

protected void onDestroy() {

super.onDestroy();

if(mClientUtils!=null){

mClientUtils.unBindService();

}

}

public void onGetServie(View v) {

if (mClientUtils.isConnect()) {

Bundle send = new Bundle();

send.putString("msgStr", "ClientOneApp發送消息");

send.putInt("msgInt", 110);

try {

Bundle ret = mClientUtils.send(110, send);

if (ret == null) {

Log.e(TAG, "onGetServie: ret==null");

} else {

String retStr = ret.getString("return");

mTextView.append("\n"+retStr);

}

} catch (Exception e) {

e.printStackTrace();

Log.e(TAG, "onGetServie:Exception " + e.toString());

}

} else {

Toast.makeText(this, "未連接配接服務,無法擷取消息", Toast.LENGTH_SHORT).show();

}

}

public void onBindServie(View v) {

mClientUtils.bindService();

}

public void onUnBindServie(View v) {

mClientUtils.unBindService();

}

private ConnectListener mConnectListener = new ConnectListener() {

@Override

public void onBind() {

tv_state.setText(" 服務正在綁定中…… ");

}

@Override

public void onDisconnected() {

btnGet.setEnabled(false);

tv_state.setText(" 服務斷開連接配接 ");

btn_bind.setEnabled(true);

btn_unbind.setEnabled(false);

}

@Override

public void onConnected(boolean success) {

if (success) {

tv_state.setText(" 服務綁定成功 ");

btn_bind.setEnabled(false);

btn_unbind.setEnabled(true);

btnGet.setEnabled(true);

} else {

btnGet.setEnabled(false);

tv_state.setText(" 服務綁定失敗 ");

mClientUtils.unBindService();

btn_bind.setEnabled(true);

btn_unbind.setEnabled(false);

}

}

@Override

public void onUnbind() {

btn_bind.setEnabled(true);

btn_unbind.setEnabled(false);

tv_state.setText(" 服務已解除綁定 ");

mTextView.setText("");

}

};

}

另外還支援自定義Service 的方式 具體檢視SimpleService類

Message的使用方式與自定義Binder的形式類似,大部分使用方式幾乎相同

分析

手寫Binder

linux程式間通訊 aidl,極簡開發 -- 程式間通訊架構非AIDL(IPCCommunication)

Binder.png

這個圖是盜用别人的嘿嘿;

首先Activity通過調用bindService去綁定一個遠端的服務(Service),綁定成功後傳回一個IBinder對象。這時候雙方就算是建立了連接配接了。

建立連接配接之後,雙方就可以通過持有的IBinder進行通信。Activity使用IBinder的transact方法去給底層的Binder Driver(Linux層)發送消息間接調用底層的IBinder的execTransact方法。

而execTransact導緻的結果就是調用onTransact方法。那麼這時候事件的處理就可以在該環節進行了。

上層主要使用 這個方法進行通信 處理消息;

public boolean onTransact(int code, android.os.Parcel data,

android.os.Parcel reply, int flags)

這個方法 一般情況下 都是傳回true的,也隻有傳回true的時候才有意義,如果傳回false了 就代表這個方法執行失敗,onTransact 這個方法 就是運作在Binder線程池中的,一般就是用戶端發起請求,然後android底層代碼把這個用戶端發起的,請求 封裝成3個參數 來調用這個onTransact方法,第一個參數code 就代表通信的标志位,data就是方法參數(用戶端傳遞過來的資料),reply就是方法傳回值(通過這個方法可以向用戶端中傳回資料)。

自定義Binder為

public class IPCBinder extends Binder {

@Override

protected boolean onTransact(final int code, final Parcel data, final Parcel reply, final int flags) throws RemoteException {

data.enforceInterface(Contant.DESCRIPTOR);

Bundle bundle = dealMessage(code,data.readBundle());

reply.writeNoException();

reply.writeBundle(bundle);

return true;

}

public BaseIPCService getService(){

return BaseIPCService.this;

}

}

暫時還未找到如何實作異步通信

用戶端發送消息

private ServiceConnection conn = new ServiceConnection() {

@Override

public void onServiceDisconnected(ComponentName name) {

// TODO Auto-generated method stub

Log.d(TAG, "--- onServiceDisconnected --- ");

connect = false;

if (mConnectListener != null) {

mConnectListener.onDisconnected();

}

}

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

// TODO Auto-generated method stub

if (service == null) {

connect = false;

Log.d(TAG, "--- onServiceConnected failed service == null ---");

if (mConnectListener != null) {

mConnectListener.onConnected(false);

}

} else {

Log.d(TAG, "--- onServiceConnected sucessed ---");

connect = true;

if (mConnectListener != null) {

mConnectListener.onConnected(true);

}

mIBinder = service;

}

}

};

連接配接成功後通過可以擷取到Binder對象

發送消息使用 mIBinder.transact(code, _data, _reply, 0);

public Bundle send(int code, Bundle bundle) throws Exception {

if (mIBinder == null) {

throw new NullPointerException("IBinder is Null");

}

Bundle result = null;

Parcel _data = Parcel.obtain();

Parcel _reply = Parcel.obtain();

try {

_data.writeInterfaceToken(DESCRIPTOR);

_data.writeBundle(bundle);

mIBinder.transact(code,

_data, _reply, 0);

_reply.readException();

result = _reply.readBundle();

} catch (Exception e) {

e.printStackTrace();

throw new Exception(e);

} finally {

_reply.recycle();

_data.recycle();

return result;

}

}

Message通信

服務端的onBind是這麼寫的:

public IBinder onBind(Intent intent)

{

return mMessenger.getBinder();

}

那麼點進去:

public IBinder getBinder() {

return mTarget.asBinder();

}

可以看到傳回的是mTarget.asBinder();

mTarget是哪來的呢?

HandlerThread mHandlerThread = new HandlerThread("BaseMsgIPCService");

mHandlerThread.start();

Handler mHandler= new Handler(mHandlerThread.getLooper()){

@Override

public void handleMessage(Message msgfromClient)

{

super.handleMessage(msgfromClient);

}

};

mMessenger= new Messenger(mHandler);

public Messenger(Handler target) {

mTarget = target.getIMessenger();

}

原來是Handler傳回的,我們繼續跟進去

final IMessenger getIMessenger() {

synchronized (mQueue) {

if (mMessenger != null) {

return mMessenger;

}

mMessenger = new MessengerImpl();

return mMessenger;

}

}

private final class MessengerImpl extends IMessenger.Stub {

public void send(Message msg) {

msg.sendingUid = Binder.getCallingUid();

Handler.this.sendMessage(msg);

}

}

mTarget是一個MessengerImpl對象,那麼asBinder實際上是傳回this,也就是MessengerImpl對象;

用戶端

用戶端首先通過onServiceConnected拿到sevice(Ibinder)對象,這裡沒什麼特殊的,我們平時的寫法也是這樣的,隻不過我們平時會這麼寫:

IMessenger.Stub.asInterface(service)拿到接口對象進行調用;

而,我們的代碼中是

mService = new Messenger(service);

跟進去,你會發現:

public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }

和我們平時的寫法一模一樣!

到這裡就可以明白,用戶端與服務端通信,實際上和我們平時的寫法沒有任何差別,通過編寫aidl檔案,服務端onBind利用Stub編寫接口實作傳回;用戶端利用回調得到的IBinder對象,使用IMessenger.Stub.asInterface(target)拿到接口執行個體進行調用。

(2)服務端與用戶端通信

那麼,用戶端與服務端通信的确沒什麼特殊的地方,我們完全也可以編寫個類似的aidl檔案實作;那麼服務端是如何與用戶端通信的呢?

還記得,用戶端send方法發送的是一個Message,這個Message.replyTo指向的是一個mMessenger,我們在Activity中初始化的。

那麼将消息發送到服務端,肯定是通過序列化與反序列化拿到Message對象,我們看下Message的反序列化的代碼:

# Message

private void readFromParcel(Parcel source) {

what = source.readInt();

arg1 = source.readInt();

arg2 = source.readInt();

if (source.readInt() != 0) {

obj = source.readParcelable(getClass().getClassLoader());

}

when = source.readLong();

data = source.readBundle();

replyTo = Messenger.readMessengerOrNullFromParcel(source);

sendingUid = source.readInt();

}

主要看replyTo,調用的是Messenger.readMessengerOrNullFromParcel

public static Messenger readMessengerOrNullFromParcel(Parcel in) {

IBinder b = in.readStrongBinder();

return b != null ? new Messenger(b) : null;

}

public static void writeMessengerOrNullToParcel(Messenger messenger,

Parcel out) {

out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()

: null);

}

通過上面的writeMessengerOrNullToParcel可以看到,它将用戶端的messenger.mTarget.asBinder()對象進行了恢複,用戶端的message.mTarget.asBinder()是什麼?

用戶端也是通過Handler建立的Messenger,于是asBinder傳回的是:

public Messenger(Handler target) {

mTarget = target.getIMessenger();

}

final IMessenger getIMessenger() {

synchronized (mQueue) {

if (mMessenger != null) {

return mMessenger;

}

mMessenger = new MessengerImpl();

return mMessenger;

}

}

private final class MessengerImpl extends IMessenger.Stub {

public void send(Message msg) {

msg.sendingUid = Binder.getCallingUid();

Handler.this.sendMessage(msg);

}

}

public IBinder getBinder() {

return mTarget.asBinder();

}

那麼asBinder,實際上就是MessengerImpl extends IMessenger.Stub

中的asBinder了。

#IMessenger.Stub

@Override

public android.os.IBinder asBinder()

{

return this;

}

那麼其實傳回的就是MessengerImpl對象自己。到這裡可以看到message.mTarget.asBinder()其實傳回的是用戶端的MessengerImpl對象。

最終,發送給用戶端的代碼是這麼寫的:

msgfromClient.replyTo.send(msgToClient);

public void send(Message message) throws RemoteException {

mTarget.send(message);

}

這個mTarget實際上就是對用戶端的MessengerImpl對象的封裝,那麼send(message)(屏蔽了transact/onTransact的細節),這個message最終肯定傳到用戶端的handler的handleMessage方法中。

Message源碼分析部分摘抄自鴻洋_的部落格

歡迎大家follow,star,如果發現bug,希望您能夠及時聯系我