目录
-
Binder
Android系统中,每个应用程序是由Android的
Activity
,Service
,Broadcast
,ContentProvider
这四大组件的中一个或多个组合而成,这四大组件所涉及的多进程间的通信底层都是依赖于Binder IPC机制。例如当进程A中的Activity要向进程B中的Service通信,这便需要依赖于Binder IPC。不仅于此,整个Android系统架构中,大量采用了Binder机制作为IPC(进程间通信)方案,当然也存在部分其他的IPC方式,比如Zygote通信便是采用socket。 -
一次完整的通信过程
-
IPC&&RPC
-
IPC(进程间通讯),RPC(远程过程调用)
-
从组件的角度,通信涉及三部分:
-
源程序:假设是A进程
-
目的进程:假设为B进程,假设提供led服务
-
数据:char buf[512],数据就是一个buff,双方约定好数据格式;
-
-
进程A怎么知道进程B提供的led的服务?为什么不是其他进程?
-
进程B向service_manager注册led服务;
-
进程A向service_manager查询led服务,得到一个handle,这个handle指向某个的某个服务,是服务的引用;binder驱动会自动根据服务对应的handle值,确定这个服务所在进程;
-
-
RPC关注的一些问题:
-
RPC:称为远程过程调用,Client调用Server端函数时,要调用哪个函数?
-
对server的函数编号,要调用哪个函数,把函数编号(这个编号最后会被封装成txn->code)发给server;
-
-
调用的函数,给被调用的函数传什么参数?这些参数怎么传递过去的?
-
通过IPC的buffer传递给server
-
-
调用的返回值是什么?
-
server端通过buffer将返回值传递给client端的调用;
-
-
-
Binder原理简介
-
Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务;
-
从流程的角度:Binder分为三大基础流程,分别是:
-
注册服务(addService)
-
获取服务(getService)
-
使用服务
-
-
可以看出无论是注册服务和获取服务的过程都需要ServiceManager,需要注意的是此处的Service Manager是指Native层的ServiceManager(C++),并非指framework层的ServiceManager(Java);
-
ServiceManager是整个Binder通信机制的大管家,是Android进程间通信机制Binder的守护进程,要掌握Binder机制,首先需要了解系统是如何首次启动Service Manager;
-
当Service Manager启动之后,Client端和Server端通信时都需要先获取Service Manager接口,才能开始通信服务;
-
注册服务(addService):Server进程要先注册Service到ServiceManager。该过程:Server是客户端,ServiceManager是服务端;
-
获取服务(getService):Client进程使用某个Service前,须先向ServiceManager中获取相应的Service。该过程:Client是客户端,ServiceManager是服务端;
-
使用服务:Client根据得到的Service信息建立与Service所在的Server进程通信的通路,然后就可以直接与Service交互。该过程:client是客户端,server是服务端。
-
Framework Binder
-
Binder架构图
-
Binder类图
-
图中浅蓝色都是Interface,其余都是Class
-
ServiceManager:通过getIServiceManager方法获取的是ServiceManagerProxy对象; ServiceManager的addService, getService实际工作都交由ServiceManagerProxy的相应方法来处理;
-
ServiceManagerProxy:其成员变量mRemote指向BinderProxy对象,ServiceManagerProxy的addService, getService方法最终是交由mRemote来完成。
-
ServiceManagerNative:其方法asInterface()返回的是ServiceManagerProxy对象,ServiceManager便是借助ServiceManagerNative类来找到ServiceManagerProxy;
-
Binder:其成员变量mObject和方法execTransact()用于native方法
-
BinderInternal:内部有一个GcWatcher类,用于处理和调试与Binder相关的垃圾回收。
-
IBinder:接口中常量FLAG_ONEWAY:客户端利用binder跟服务端通信是阻塞式的,但如果设置了FLAG_ONEWAY,这成为非阻塞的调用方式,客户端能立即返回,服务端采用回调方式来通知客户端完成情况。另外IBinder接口有一个内部接口DeathDecipient(死亡通告)。
-
Binder类分层
-
整个Binder从kernel至,native,JNI,Framework层所涉及的全部类
-
如何使用Binder
-
Service端
package com.transsion.binderdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class HelloService extends Service {
private static final String TAG = "HelloService";
public HelloService() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to t;he service.
Log.d(TAG, "on service bind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "on service unbind");
return super.onUnbind(intent);
}
//实现server端
private IHelloService.Stub mBinder = new IHelloService.Stub() {
@Override
public String SayHello() throws RemoteException {
Log.d(TAG, "on say hello");
String content = "say hello";
return content;
}
@Override
public String SayGoodBye() throws RemoteException {
Log.d(TAG, "on say good bye");
String content = "say good bye";
Toast.makeText(getApplicationContext(), content, Toast.LENGTH_SHORT).show();
return content;
}
};
}
-
Client端
package com.transsion.binderdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "BinderDemoMainActivity";
private IHelloService mHelloService;
private Button btBind;
private Button btUnBind;
private Button btHello;
private Button btBye;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btBind = findViewById(R.id.bt_bind);
btUnBind = findViewById(R.id.bt_unbind);
btHello = findViewById(R.id.bt_hello);
btBye = findViewById(R.id.bt_bye);
btBind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
bindHelloService();
}
});
btUnBind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
unbindRemoteService();
}
});
btHello.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mHelloService != null) {
Log.d(TAG, "on bt hello clicked ,hello service is not null");
try {
String content = mHelloService.SayHello();
if (content != null && !content.isEmpty()) {
Toast.makeText(getApplicationContext(), content, Toast.LENGTH_SHORT).show();
}
} catch (RemoteException e) {
throw new RuntimeException(e);
}
} else {
Log.d(TAG, "on bt hello clicked ,hello service is null");
}
}
});
btBye.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mHelloService != null) {
Log.d(TAG, "on bt good bye clicked ,hello service is not null");
try {
String content = mHelloService.SayGoodBye();
if (content != null && !content.isEmpty()) {
Toast.makeText(getApplicationContext(), content, Toast.LENGTH_SHORT).show();
}
} catch (RemoteException e) {
throw new RuntimeException(e);
}
} else {
Log.d(TAG, "on bt good bye clicked ,hello service is null");
}
}
});
}
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mHelloService = IHelloService.Stub.asInterface(iBinder);
Log.d(TAG, "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d(TAG, "onServiceDisconnected");
}
};
void bindHelloService() {
Intent intent = new Intent(MainActivity.this, HelloService.class);
intent.setAction(HelloService.class.getName());
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
private void unbindRemoteService() {
unbindService(mConnection);
}
}