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.youkuaiyun.com/universus/article/details/6211589
http://blog.youkuaiyun.com/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/