binder是一个非常好的跨进程通信工具,Android对其进行了各种封装,虽然我们用起来简单,但是理解起来却比较困难。
1.自己设计一个跨进程通信机制
在理解binder之前呢,首先我们想一下,如果我们自己设计一个跨进程通信的机制,那我们会怎么设计呢? 如果是我的话,我可能会按照下图设计。 图中左边是客户端,右边是服务端,客户端想要调用服务端的call函数,首先我们需要先将函数名称以及参数值进行序列化,然后再使用linux系统所提供的跨进程通信方式,例如socket或者是管道,将这些序列化过后的数据传递给服务端,然后服务端拿到这些数据之后,首先进行反序列化,然后再调用相应的函数,将返回值返回给客户端。 其实和我们使用网络访问服务器的结构很像。 接着我们来看下binder的通信流程。
2.跨进程通信流程
1.生成AIDL文件
首先我们新建一个AIDL文件,
interface IFile {
Bitmap getBitmap(String path);
}
然后build过后,系统会自动帮我们生成一个IFile.java文件
public interface IFile extends android.os.IInterface {
/**
*继承binder,实现IFile接口,运行于服务端
*/
public static abstract class Stub extends android.os.Binder implements com.android.hdemo.IFile {
private static final java.lang.String DESCRIPTOR = "com.android.hdemo.IFile";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.android.hdemo.IFile interface,
* generating a proxy if needed.
*/
public static com.android.hdemo.IFile asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.android.hdemo.IFile))) {
return ((com.android.hdemo.IFile) iin);
}
return new com.android.hdemo.IFile.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBitmap: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
android.graphics.Bitmap _result = this.getBitmap(_arg0);
reply.writeNoException();
if ((_result != null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
//实现IFile接口,运行于客户端
private static class Proxy implements com.android.hdemo.IFile {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public android.graphics.Bitmap getBitmap(java.lang.String path) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.graphics.Bitmap _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(path);
mRemote.transact(Stub.TRANSACTION_getBitmap, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
_result = android.graphics.Bitmap.CREATOR.createFromParcel(_reply);
} else {
_result = null;
}
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getBitmap = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public android.graphics.Bitmap getBitmap(java.lang.String path) throws android.os.RemoteException;
}
生成的代码结构并不复杂,IFile是一个接口,继承了android.os.IInterface,并加入了我们自定义的接口方法getBitmap,IFile中包含一个静态抽象类Stub,Stub又包含一个静态内部类Proxy。Stub继承binder,实现IFile接口,运行于服务端,Proxy实现IFile接口,运行于客户端。 接着我们来看一下从客户端到服务端的整个流程
2.从客户端到服务端
客户端
首先来看下我们是如何来获取服务的,从注释1处可以看出,客户端拿到binder对象之后,调用asInterface方法将其转换成本地的IFile对象。
Intent intent = new Intent(this,TestService.class);
this.bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
//1
IFile iFile = IFile.Stub.asInterface(service);
iFile.getBitmap("");
}catch (Exception e){
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, Service.BIND_AUTO_CREATE);
而asInterface是系统生成的代码,从下面注释1处可以看出,如果客户端和服务端在同一个进程,则直接将binder强转成本地接口对象,否则返回Proxy对象。如注释2所示,Proxy的getFile方法会调用mRemote.transact方法,mRemote是一个binder对象,其真正的实现是BinderProxy。
public static com.android.hdemo.IFile asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//1.如果客户端和服务端在同一个进程,则直接调用,否则使用Proxy
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.android.hdemo.IFile))) {
return ((com.android.hdemo.IFile) iin);
}
return new com.android.hdemo.IFile.Stub.Proxy(obj);
}
//Proxy
private static class Proxy implements com.android.hdemo.IFile {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public android.graphics.Bitmap getBitmap(java.lang.String path) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.graphics.Bitmap _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(path);
//2.调用binder的transact方法
mRemote.transact(Stub.TRANSACTION_getBitmap, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
_result = android.graphics.Bitmap.CREATOR.createFromParcel(_reply);
} else {
_result = null;
}
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
BinderProxy的transact方法会调用transactNative方法,最终会调用native层的BpBinder的transact方法,然后由BpBinder和binder驱动进行交互。
//BinderProxy
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
......
try {
return transactNative(code, data, reply, flags);
} finally {
......
}
}
//Native层BpBinder
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
bool privateVendor = flags & FLAG_PRIVATE_VENDOR;
// don't send userspace flags to the kernel
flags = flags & ~FLAG_PRIVATE_VENDOR;
// user transactions require a given stability level
if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
using android::internal::Stability;
auto stability = Stability::get(this);
auto required = privateVendor ? Stability::VENDOR : Stability::kLocalStability;
if (CC_UNLIKELY(!Stability::check(stability, required))) {
ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
Stability::stabilityString(stability).c_str(),
Stability::stabilityString(required).c_str());
return BAD_TYPE;
}
}
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
服务端
binder驱动收到请求之后会调用native层BBinder的onTransact方法,
status_t BBinder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
switch (code) {
case INTERFACE_TRANSACTION:
reply->writeString16(getInterfaceDescriptor());
return NO_ERROR;
case DUMP_TRANSACTION: {
int fd = data.readFileDescriptor();
int argc = data.readInt32();
Vector<String16> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
args.add(data.readString16());
}
return dump(fd, args);
}
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
int err = data.readFileDescriptor();
int argc = data.readInt32();
Vector<String16> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
args.add(data.readString16());
}
sp<IShellCallback> shellCallback = IShellCallback::asInterface(
data.readStrongBinder());
sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(
data.readStrongBinder());
// XXX can't add virtuals until binaries are updated.
//return shellCommand(in, out, err, args, resultReceiver);
(void)in;
(void)out;
(void)err;
if (resultReceiver != nullptr) {
resultReceiver->send(INVALID_OPERATION);
}
return NO_ERROR;
}
case SYSPROPS_TRANSACTION: {
report_sysprop_change();
return NO_ERROR;
}
default:
return UNKNOWN_TRANSACTION;
}
}
接着会回掉到java层的onTransact方法,如下注释1所示,this.getBitmap(_arg0)为Stub类的方法,从服务端获取到图片,然后在注释2处,将bitmap写入到返回值。
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBitmap: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
//1.服务端获取的bitmap
android.graphics.Bitmap _result = this.getBitmap(_arg0);
reply.writeNoException();
if ((_result != null)) {
reply.writeInt(1);
//2.将bitmap写入返回值
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
我们再来看下service的定义,当绑定到一个service之后,返回的Stub对象,实现了getBitmap方法,返回了本地的bitmap。
public class TestService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new IFile.Stub() {
@Override
public Bitmap getBitmap(String path) throws RemoteException {
//1.返回本地bitmap
return mBitmap;
}
};
}
}
这样从客户端到服务端的流程就走完了,我们看下它的流程图
3.binder的优势
linux本身提供了很多跨进程通信的方式,例如socket,共享内存,管道之类的,那为啥还要再弄出个binder呢,有以下几点
方便
binder使用起来对于开发者来说非常的友好,隐藏了底层的实现细节,我们只需要关注于业务逻辑即可。
高效
binder通信过程中,将内存同时映射到内核和应用进程当中,只需要拷贝一次即可。而socket和管道均需要从应用进程拷贝到内核,再从内核拷贝到应用进程,需要两次拷贝,共享内存不需要数据拷贝,但使用起来比较复杂。
安全
调用方的身份标记由binder机制本身在内核态中添加,调用方不能自己更改。我们可以通过Binder获取到调用方的uid和pid,从而进行权限控制。
更多Framework源码相关内容已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
内容主要包含:系统启动流程、跨进程通信IPC、Handler、AMS、WMS、Surface、PKMS、InputManagerService、DisPlayManagerService、基于Android12.0的SurfaceFlinger等等最新源码解析