Android RPC
Linux系統IPC包括:signals,pipes,message queues,semaphores,shared memory。Android中添加了Binder機制和AIDL來實現IPC。
RPC(Remote Procedure Call – 遠程過程調度)基本步驟介紹:
- Method and data decomposition(分解), also known as marshalling(信號編集,編組的,整理);
- Transferring the marshalled information to the remote process;
- Recomposing(重新安排) the information in the remote process, also known as unmarshalling;
- Transferring return values back to the originating process.
Binder
Binder能使Application通過調用方法來讓運行在不同進程中的Thread來傳輸functions和data。Server Process由android.os.Binder類定義了一個remote interface,Client Process中的Threads通過這個remote object來訪問這個remote interface。
(The binders enables applications to transfer both functions and data – method calls – between threads running in different processes. The server process defines a remote interface supported by the android.os.Binder class, and threads in a client process can access the remote interface through this remote object.)
RPC傳輸function和data被稱爲transaction(交易/事務)。Client Process調用transact()方法,Server Process在onTransact()方法中接收。
onTransact()方法在Binder Thread Pool中的一個Thread中執行。Binder Thread Pool 僅僅處理來自其他Process的請求。它最多有16個Thread(Android系統開源,這個值可能被修改)。
IPC可以是雙向的,two-way communication mechanism 可以在兩個Processes之間被建立,這個機制對於使用Asynchronour RPC是很重要的。
我們可以設置IBinder.FLAG_ONEWAY,Binders也就支持Asynchronous transaction。當這個Flag設置後,client thread調用transact()方法並且會立即返回。而Server Process中Binder thread上的Binder會繼續調用onTransact()方法,但是不能同步的返回任何數據到Client Thread。
https://developer.android.com/reference/android/os/IBinder.html
Binder System 支持 recursion[遞歸/循環] across processes.
如何檢測 remote objects 無效:
注意:https://developer.android.com/reference/android/os/Binder.html
不錯的Binder介紹地址:
http://weishu.me/2016/01/12/binder-index-for-newer/
http://blog.csdn.net/universus/article/details/6211589
http://blog.csdn.net/luoshengyang/article/details/6618363
AIDL
當一個進程打算暴露功能給其他進程訪問,它需要定義一個Communication Contract(合同/契約). 基本上,server定義client調用的方法接口,我們使用AIDL(Android Interface Definition Language)來定義,定義在 .aidl 文件中。編譯這個AIDL文件生成Java代碼來支持IPC。
這個被生成的Java Interface存到所有的Client Application和Server Application中。這個Interface文件定義了兩個內部類 – Proxy和Stub。這兩個內部類處理數據的marshalling和unmarshalling,也傳輸這些數據。因此AIDL的創建自動生成Java代碼,Java代碼包裹着Binder Framework,並且建立Communication Contract。
Synchronous RPC
儘管在Server Process中的Remote method 是並行執行的,即由Binder Thread Pool並行處理,但是對於Client Process中的Calling Thread而言像是順序執行的。當Server的Remote method被Binder Thread處理完了,可能會給Client返回一個值,那麼Client的Calling Thread將會Resume Execution。
Eg:
創建aidl文件,注意Server和Client的aidl文件要相同(路徑位置以及內容),可以一端創建完了,然後完整的複製到另外一端。
/**
* Server Process由Binder Thread Pool並行處理來自Client的請求,有可能給Client返回值,
* 但是Client Process是順序的處理Server Process返回的結果
*/
interface ISynchronous {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
String getThreadNameFast();
String getThreadNameSlow(long sleep);
String getThreadNameBlocking();
String getThreadNameUnblock();
}
Server端創建Service類,並修改AndroidManifest.xml文件
public class SynchronousRPCService extends Service {
// Server端實現AIDL文件中的方法
private final ISynchronous.Stub mBinder = new ISynchronous.Stub() {
CountDownLatch mLatch = new CountDownLatch(1);
@Override
public String getThreadNameFast() throws RemoteException {
Log.i("syncrpcservice", "Server # SynchronousRPCService # getThreadNameFast");
return Thread.currentThread().getName();
}
@Override
public String getThreadNameSlow(long sleep) throws RemoteException {
Log.i("syncrpcservice", "Server # SynchronousRPCService # getThreadNameSlow");
SystemClock.sleep(sleep);
return Thread.currentThread().getName();
}
@Override
public String getThreadNameBlocking() throws RemoteException {
Log.i("syncrpcservice", "Server # SynchronousRPCService # getThreadNameBlocking # mLatch: " + mLatch);
try {
mLatch.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
return Thread.currentThread().getName();
}
@Override
public String getThreadNameUnblock() throws RemoteException {
Log.i("syncrpcservice", "Server # SynchronousRPCService # getThreadNameUnblock # mLatch: " + mLatch);
mLatch.countDown();
return Thread.currentThread().getName();
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
// 返回Server的Binder,Client獲取到此Binder來調用AIDL文件中定義的方法
return mBinder;
}
}
<!-- AIDL Sychronous RPC -->
<service android:name=".ipc.aidl.SynchronousRPCService"
android:process=":synchronousremote"
android:exported="true">
<intent-filter>
<action android:name="cn.wei.thread.ipc.aidl.synchronousrpc"></action>
</intent-filter>
</service>
Client端開啓Bind Server,使用aidl生成的方法建立與Server之間的連接
public class MainActivity extends AppCompatActivity {
private Button mBoundService = null;
private Button mUnboundService = null;
private Button mFastBtn = null;
private TextView mFastResult = null;
private Button mSlowBtn = null;
private TextView mSlowResult = null;
private Button mBlockingBtn = null;
private TextView mBlockingResult = null;
private Button mUnblockBtn = null;
private TextView mUnblockResult = null;
private ISynchronous mSyncRPCService = null;
// 建立Service連接
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("syncrpcclient", "Client # ServiceConnection # onServiceConnected # name: " + name + "; service: " + service);
mSyncRPCService = ISynchronous.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mSyncRPCService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBoundService = (Button) findViewById(R.id.sync_rpc_bound_service);
mUnboundService = (Button) findViewById(R.id.sync_rpc_unbound_service);
mBoundService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 開啓Bind Service
Intent intent = new Intent("cn.wei.thread.ipc.aidl.synchronousrpc");
//新版本(5.0後)必須顯式intent啓動 綁定服務
// Service的包名和Service的文件名
intent.setComponent(new ComponentName("cn.wei.thread","cn.wei.thread.ipc.aidl.SynchronousRPCService"));
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
});
mUnboundService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(serviceConnection);
}
});
mFastBtn = (Button) findViewById(R.id.sync_rpc_fast);
mFastResult = (TextView) findViewById(R.id.sync_rpc_fast_result);
mFastBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String threadName = mSyncRPCService.getThreadNameFast();
mFastResult.setText(threadName);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
mSlowBtn = (Button) findViewById(R.id.sync_rpc_slow);
mSlowResult = (TextView) findViewById(R.id.sync_rpc_slow_result);
mSlowBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String threadName = mSyncRPCService.getThreadNameSlow(3000);
//下面的代碼不會立即執行,要等上面的方法返回結果。順序執行
mSlowResult.setText(threadName);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
mBlockingBtn = (Button) findViewById(R.id.sync_rpc_blocking);
mBlockingResult = (TextView) findViewById(R.id.sync_rpc_blocking_result);
mBlockingBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String threadName = mSyncRPCService.getThreadNameBlocking();
mBlockingResult.setText(threadName);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
mUnblockBtn = (Button) findViewById(R.id.sync_rpc_unblock);
mUnblockResult = (TextView) findViewById(R.id.sync_rpc_unblock_result);
mUnblockBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String threadName = mSyncRPCService.getThreadNameUnblock();
mUnblockResult.setText(threadName);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
推薦鏈接:
http://cjw-blog.net/2017/02/26/AIDL/ 代碼:https://github.com/V1sk/AIDL/
http://www.jianshu.com/p/a5c73da2e9be
Asynchronous RPC
我們可以把每一個Remote method定義爲異步執行來實現Asynchronous RPC(異步RPC)。Client Thread能通過Asynchronous RPC開啓一個transaction,然後立即返回。Binder會把transactions給到Server Process,然後關閉Client和Server之間的Connection。
Asynchronous method的要求:
- 由 oneway 關鍵字修飾。oneway關鍵字修飾方法時,那麼只有這個方法是Asynchronous的;如果oneway關鍵字修飾aidl接口文件,那麼這個文件中的所有方法都是Asynchronous的。
- 方法必須返回void;
- 方法不能有out或者inout修飾的參數。
注意:我們可以通過方法回調來獲取Asynchronous method的處理結果
in,out,inout介紹:
Eg.
創建aidl文件
IAsynchronous.aidl
import cn.wei.thread.IAsynchronousCallback;
/**
* 使用oneway關鍵字修飾方法爲Asynchronous method,Client調出此方法可以立即返回,而Server端異步處理,然後通過
* 回調接口的方式把結果返回給Client
*/
interface IAsynchronous {
// Asynchronous method
oneway void getThreadNameSlow(IAsynchronousCallback callback);
}
IAsynchronousCallback.aidl
/**
* 給Client返回結果的回調接口
*/
interface IAsynchronousCallback {
// Asynchronous method處理結果的回調方法
void handleResult(String name);
}
Server端創建Service類,並修改AndroidManifest.xml文件
public class AsynchronousRPCService extends Service {
private IAsynchronous.Stub mBinder = new IAsynchronous.Stub() {
@Override
public void getThreadNameSlow(IAsynchronousCallback callback) throws RemoteException {
Log.i("asyncserver", "Server # AsynchronousRPCService # getThreadNameSlow # callback: " + callback);
SystemClock.sleep(3000);
callback.handleResult(Thread.currentThread().getName());
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
<!-- AIDL Asychronous RPC -->
<service android:name=".ipc.aidl.AsynchronousRPCService"
android:process=":asyncremote"
android:exported="true">
<intent-filter>
<action android:name="cn.wei.thread.ipc.aidl.asynchronousrpc"></action>
</intent-filter>
</service>
Client端開啓Bind Server,使用aidl生成的方法建立與Server之間的連接,實現IAsynchronousCallback回調接口接收結果
public class MainActivity extends AppCompatActivity {
private Button mBoundAsyncBtn = null;
private Button mUnboundAsyncBtn = null;
private Button mAsyncSlowBtn = null;
private TextView mAsyncSlowName = null;
private IAsynchronous mAsyncService = null;
// 建立Service連接
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("asyncclient", "Client # ServiceConnection # onServiceConnected # name: " + name + "; service: " + service);
mAsyncService = IAsynchronous.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mAsyncService = null;
}
};
// 實現回調接口
private IAsynchronousCallback.Stub mCallback = new IAsynchronousCallback.Stub() {
@Override
public void handleResult(final String name) throws RemoteException {
Log.i("asyncclient", "Client # IAsynchronousCallback # handleResult # name: " + name + "; current thread: " + Thread.currentThread().getName());
runOnUiThread(new Runnable() {
@Override
public void run() {
mAsyncSlowName.setText(name);
}
});
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBoundAsyncBtn = (Button) findViewById(R.id.async_rpc_bound_service);
mUnboundAsyncBtn = (Button) findViewById(R.id.async_rpc_unbound_service);
mAsyncSlowBtn = (Button) findViewById(R.id.async_rpc_slow);
mAsyncSlowName = (TextView) findViewById(R.id.async_rpc_slow_result);
mBoundAsyncBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("cn.wei.thread.ipc.aidl.asynchronousrpc");
intent.setComponent(new ComponentName("cn.wei.thread", "cn.wei.thread.ipc.aidl.AsynchronousRPCService"));
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
});
mUnboundAsyncBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(serviceConnection);
}
});
mAsyncSlowBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mAsyncService.getThreadNameSlow(mCallback);
//下面的代碼會立即執行。getThreadNameSlow的結果通過回調接口獲取
mAsyncSlowName.setText("Async get name slow...");
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
推薦:
http://codetheory.in/android-interprocess-communication-ipc-with-aidl/
http://cjw-blog.net/2017/02/26/AIDL/ // 推薦
Messenger
Messenger支持Binder Framework,Messenger作爲Client和Server交互的中間人。
Message能通過Messenger實現進程間通信,但是發送進程(Client)需要先從接收進程(Server)獲取到Messenger引用。
Client和Server實現交互需要兩步:
1. Client進程獲取到Server進程中的Messenger引用;
2. Client通過Messenger引用發送Message到Server。如果交互是單方向的(Client -> Server),即Client發給Server,直接使用Messenger發送Message即可;
如果交互是相互的,即Client發送給Server,Server也會返回結果給Client的話,Client要設置Message.replyTo,在Client端新建個Messenger並把Client的Messenger發送給Server,然後Server可以使用Message.replyTo的Client Messenger把結果返回給Client。
## One Way Communication
Server端,下面的代碼實現了和Client交互的代碼。
public class WorkerThreadService extends Service {
private WorkerThread mWorkerThread = null;
private Messenger mWorkerMessenger = null;
@Override
public void onCreate() {
super.onCreate();
Log.i("messengerserver", "WorkerThreadService # onCreate");
// 開啓工作線程,處理Client通過Messenger發送來的消息
mWorkerThread = new WorkerThread();
mWorkerThread.start();
}
// 把Server端的Messenger通過Binder讓Client端獲取到
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i("messengerserver", "WorkerThreadService # onBind # mWorkerMessenger: " + mWorkerMessenger + "; intent: " + intent);
// 此例中onBind()調用時間比Messenger時間早,防止返回爲空
synchronized (this) {
while (mWorkerMessenger == null) {
try {
wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return mWorkerMessenger.getBinder();
}
@Override
public void onDestroy() {
super.onDestroy();
mWorkerThread.quit();
}
// 實例Server的Messenger,使用工作線程中的Handler來處理Client發送來的數據
private void onWorkerPrepared() {
Log.i("messengerserver", "WorkerThreadService # onWorkerPrepared");
mWorkerMessenger = new Messenger(mWorkerThread.mWorkerHandler);
// 此例中Messenger實例化比onBind()方法調用時間晚,爲了防止onBind()返回空
synchronized (this) {
notifyAll();
}
}
// 工作線程,處理Client通過Messenger發送來的消息
private class WorkerThread extends Thread {
Handler mWorkerHandler = null;
@Override
public void run() {
super.run();
Looper.prepare();
Log.i("messengerserver", "WorkerThreadService # WorkerThread # run");
// 實例化工作線程中的Handler,用來處理Client端通過Messenger發送過來的消息
mWorkerHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1: // one way message
Log.i("messengerserver", "WorkerThreadService # WorkerThread # run # handleMessage # one way # msg.arg1: " + msg.arg1);
break;
case 2: // two way message
Log.i("messengerserver", "WorkerThreadService # WorkerThread # run # handleMessage # two way # msg.arg1: " + msg.arg1);
try {
Message replyMsg = Message.obtain();
replyMsg.what = 22;
replyMsg.arg1 = 22;
msg.replyTo.send(replyMsg);
}
catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
};
// 工作線程的Handler實例化後,創建Messenger
onWorkerPrepared();
Looper.loop();
}
public void quit() {
mWorkerHandler.getLooper().quit();
}
}
}
AndroidManifest.xml修改
<!-- Messenger One&Two Way -->
<service android:name=".ipc.messenger.WorkerThreadService"
android:process=":messenger">
<intent-filter>
<action android:name="cn.wei.thread.ipc.messenger.IPC"></action>
</intent-filter>
</service>
單向交互的Client代碼:
public class MessengerOneWayActivity extends Activity {
private Button mBoundMessengerOnewayBtn = null;
private Button mUnboundMessengerOnewayBtn = null;
private Button mSendOnewayBtn = null;
private Messenger messenger = null;
private boolean isBound = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("messengeronewayclient", "MessengerOneWayActivity # ServiceConnection # name: " + name + "; service: " + service);
messenger = new Messenger(service);
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
messenger = null;
isBound = false;
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger_oneway_service);
mBoundMessengerOnewayBtn = (Button) findViewById(R.id.bound_messenger_oneway_service_test_btn);
mUnboundMessengerOnewayBtn = (Button) findViewById(R.id.unbound_messenger_oneway_service_test_btn);
mSendOnewayBtn = (Button) findViewById(R.id.send_oneway_test_btn);
mBoundMessengerOnewayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("cn.wei.thread.ipc.messenger.IPC");
//必須使用顯示調用
intent.setComponent(new ComponentName("cn.wei.thread", "cn.wei.thread.ipc.messenger.WorkerThreadService"));
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
});
mUnboundMessengerOnewayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(serviceConnection);
}
});
mSendOnewayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("messengeronewayclient", "MessengerOneWayActivity # mSendOnewayBtn # isBound: " + isBound);
if (isBound) {
try {
Message msg = Message.obtain();
msg.what = 1;
msg.arg1 = 111111;
messenger.send(msg);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
Two Way Communication
互相交互的Client代碼:
public class MessengerTwoWayActivity extends Activity {
private Button mBoundMessengerTwowayBtn = null;
private Button mUnboundMessengerTwowayBtn = null;
private Button mSendTwowayBtn = null;
private TextView mTwowayReply = null;
private Messenger messenger = null;
private boolean isBound = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("messengertwowayclient", "MessengerTwoWayActivity # ServiceConnection # name: " + name + "; service: " + service);
messenger = new Messenger(service);
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
messenger = null;
isBound = false;
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger_twoway_service);
mBoundMessengerTwowayBtn = (Button) findViewById(R.id.bound_messenger_twoway_service_test_btn);
mUnboundMessengerTwowayBtn = (Button) findViewById(R.id.unbound_messenger_twoway_service_test_btn);
mSendTwowayBtn = (Button) findViewById(R.id.send_twoway_test_btn);
mTwowayReply = (TextView) findViewById(R.id.twoway_reply);
mBoundMessengerTwowayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("cn.wei.thread.ipc.messenger.IPC");
//必須使用顯示調用
intent.setComponent(new ComponentName("cn.wei.thread", "cn.wei.thread.ipc.messenger.WorkerThreadService"));
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
});
mUnboundMessengerTwowayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(serviceConnection);
}
});
mSendTwowayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("messengertwowayclient", "MessengerTwoWayActivity # mSendTwowayBtn # isBound: " + isBound);
if (isBound) {
try {
Message msg = Message.obtain();
msg.what = 2;
msg.arg1 = 222222;
// Server和Client通過Messenger雙向交互時,Client使用Server的Messager發送message給Server時需要設置Message.replyTo(),
// 即設置Client的Messenger,讓Server通過的發送來的消息
msg.replyTo = new Messenger(new Handler() {
@Override
public void handleMessage(final Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 22:
Log.i("messengertwowayclient", "MessengerTwoWayActivity # msg from Server # arg1: " + msg.arg1);
runOnUiThread(new Runnable() {
@Override
public void run() {
mTwowayReply.setText(msg.arg1 + "");
}
});
break;
default:
break;
}
}
});
messenger.send(msg);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
推薦:
http://codetheory.in/android-interprocess-communication-ipc-messenger-remote-bound-services/