Android进阶——Android跨进程通讯机制之Binder、IBinder、Parcel、AIDL-1

三、系统调用/内核态/用户态

抽象来看,操作系统中安全边界的概念就像环路的概念一样(前提是系统支持这种特性),一个环上持有一个特定的权限组,Intel 支持四层环,但是 Linux 只使用了其中的两环(0号环持有全部权限,3号环持有最少权限,1号和2号环未使用),系统进程运行在1号环,用户进程运行在3号环,如果一个用户进程需要其他高级权限,其必须从3号环过渡成0号环,过渡需要通过一个安全参数检查的网关,这种过渡被称为系统调用,在执行过程中会产生一定数量的计算开销。所以,用户空间要访问内核空间的唯一方式就是系统调用(System Call)

四、内核模块/驱动

通过系统调用,用户空间可以访问内核空间,它是怎么做到访问内核空间的呢?Linux的动态可加载内核模块机制解决了这个问题,模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。这样,Android系统可以通过添加一个内核模块运行在内核空间,用户进程之间的通过这个模块作为桥梁,就可以完成通信了。在Android系统中,这个运行在内核空间的,负责各个用户进程通过Binder通信的内核模块叫做Binder驱动

五、简单的总结

将前面的所有概念连接起来理解就会非常好消化知识点:

1.Linux的虚拟内存机制导致内存的隔离,进而导致进程隔离
2.进程隔离的出现导致对内存的操作被划分为用户空间和内核空间
3.用户空间需要跨权限去访问内核空间,必须使用系统调用去实现
4.系统调用需要借助内核模块/驱动去完成

前三步决定了进程间通讯需要借助内核模块/驱动去实现,而Binder驱动就是内核模块/驱动中用来实现进程间通讯的

###为什么要用Binder
Linux提供有管道、消息队列、信号量、内存共享、套接字等跨进程方式,那为什么Android要选择Binder另起炉灶呢?

一、传输性能好

  • Socket:是一个通用接口,导致其传输效率低,开销大
  • 共享内存:虽然在传输时不需要拷贝数据,但其控制机制复杂
  • Binder:复杂数据类型传递可以复用内存,需要拷贝1次数据
  • 管道和消息队列:采用存储转发方式,至少需要拷贝2次数据,效率低

二、安全性高

  • 传统的进程:通信方式对于通信双方的身份并没有做出严格的验证,只有在上层协议上进行架设

  • Binder机制:从协议本身就支持对通信双方做身份校检,因而大大提升了安全* 性
    ###Binder通信模型
    首先在理解模型之前先熟悉这几个概念:

  • Client进程:跨进程通讯的客户端(运行在某个进程)

  • Server进程:跨进程通讯的服务端(运行在某个进程)
    Binder驱动:跨进程通讯的介质

  • ServiceManager:跨进程通讯中提供服务的注册和查询(运行在System进程)

这里只是个简单的模型而已,只需理解模型的通讯流程:

1.Server端通过Binder驱动在ServiceManager中注册
2.Client端通过Binder驱动获取ServiceManager中注册的Server端
3.Client端通过Binder驱动和Server端进行通讯
###Binder通信原理

理解完模型流程之后,开始理解模型的通讯原理:

1.Service端通过Binder驱动在ServiceManager的查找表中注册Object对象的add方法
2.Client端通过Binder驱动在ServiceManager的查找表中找到Object对象的add方法,并返回proxy对象的add方法,add方法是个空实现,proxy对象也不是真正的Object对象,是通过Binder驱动封装好的代理类的add方法
3.当Client端调用add方法时,Client端会调用proxy对象的add方法,通过Binder驱动去请求ServiceManager来找到Service端真正对象,然后调用Service端的add方法

###Binder对象和Binder驱动

  • Binder对象:Binder机制中进行进程间通讯的对象,对于Service端为Binder本地对象,对于Client端为Binder代理对象
  • Binder驱动:Binder机制中进行进程间通讯的介质,Binder驱动会对具有跨进程传递能力的对象做特殊处理,自动完成代理对象和本地对象的转换

由于Binder驱动会对具有跨进程传递能力的对象做特殊处理,自动完成代理对象和本地对象的转换,因此在驱动中保存了每一个跨越进程的Binder对象的相关信息,Binder本地对象(或Binder实体)保存在binder_node的数据结构,Binder代理对象(或Binder引用/句柄)保存在binder_ref的数据结构

###Java层的Binder

  • Binder类:是Binder本地对象
  • BinderProxy类:是Binder类的内部类,它代表远程进程的Binder对象的本地代理
  • Parcel类:是一个容器,它主要用于存储序列化数据,然后可以通过Binder在进程间传递这些数据
  • IBinder接口:代表一种跨进程传输的能力,实现这个接口,就能将这个对象进行跨进程传递
  • IInterface接口:client端与server端的调用契约,实现这个接口,就代表远程server对象具有什么能力,因为IInterface接口的asBinder方法的实现可以将Binder本地对象或代理对象进行返回

Binder类和BinderProxy类都继承自IBinder,因而都具有跨进程传输的能力,在跨越进程的时候,Binder驱动会自动完成这两个对象的转换。IBinder是远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分,但它不仅用于远程调用,也用于进程内调用。IBinder接口定义了与远程对象交互的协议,建议不要直接实现这个接口,而应该从Binder派生。Binder实现了IBinder接口,但是一般不需要直接实现此类,而是跟据你的需要由开发包中的工具生成,这个工具叫aidi。你通过aidi语言定义远程对象的方法,然后用aidi工具生成Binder的派生类,然后使用它

###AIDL
由于编译工具会给我们生成一个Stub的静态内部类,这个类继承了Binder, 说明它是一个Binder本地对象,它实现了IInterface接口,表明它具有远程Server承诺给Client的能力

一、服务端

在服务端中,我们只要实现Stub抽象类,和实现其方法即可

private IBinder myS = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

}

@Override
public int add(int num1, int num2) throws RemoteException {
Log.i(“Hensen”, “从客户端发来的AIDL请求:num1->” + num1 + “::num2->” + num2);
return num1 + num2;
}
};

二、客户端

在客户端中,可以通过bindService的回调中获取AIDL接口

private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}

@Override
public void onServiceDisconnected(ComponentName name) {
iMyAidlInterface = null;
}
};

public void add(View view) {
try {
int res = iMyAidlInterface.add(1, 2);
Log.i(“Hensen”, “从服务端调用成功的结果:” + res);
} catch (RemoteException e) {
e.printStackTrace();
}
}

梳理客户端的调用流程:

1.调用Stub.asInterface获取BinderProxy对象
2.调用BinderProxy对象的add方法

三、分析原理

1、Stub

Stub类继承自Binder,意味着这个Stub其实自己是一个Binder本地对象,然后实现了IMyAidlInterface接口,IMyAidlInterface本身是一个IInterface,因此他携带某种客户端需要的能力(这里是方法add)。此类有一个内部类Proxy,也就是Binder代理对象

/*

  • This file is auto-generated. DO NOT MODIFY.
  • Original file: D:\workspace5\Boke\app\src\main\aidl\com\handsome\boke\IMyAidlInterface.aidl
    */
    package com.handsome.boke;
    // Declare any non-default types here with import statements

public interface IMyAidlInterface extends android.os.IInterface {
/**

  • Local-side IPC implementation stub class.
    */
    public static abstract class Stub extends android.os.Binder implements com.handsome.boke.IMyAidlInterface {
    private static final java.lang.String DESCRIPTOR = “com.handsome.boke.IMyAidlInterface”;

/**

  • Construct the stub at attach it to the interface.
    */
    public Stub() {
    this.attachInterface(this, DESCRIPTOR);
    }

/**

  • Cast an IBinder object into an com.handsome.boke.IMyAidlInterface interface,
  • generating a proxy if needed.
    */
    public static com.handsome.boke.IMyAidlInterface asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.handsome.boke.IMyAidlInterface))) {
    return ((com.handsome.boke.IMyAidlInterface) iin);
    }
    return new com.handsome.boke.IMyAidlInterface.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_basicTypes: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_add: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}

private static class Proxy implements com.handsome.boke.IMyAidlInterface {
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;
}

/**

  • Demonstrates some basic types that you can use as parameters
  • and return values in AIDL.
    */
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    _data.writeInt(anInt);
    _data.writeLong(aLong);
    _data.writeInt(((aBoolean) ? (1) : (0)));
    _data.writeFloat(aFloat);
    _data.writeDouble(aDouble);
    _data.writeString(aString);
    mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
    _reply.readException();
    } finally {
    _reply.recycle();
    _data.recycle();
    }
    }

@Override
public int add(int num1, int num2) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(num1);
_data.writeInt(num2);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}

总结

写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于Flutter的学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的
还有高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。

跨平台开发:Flutter.png
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的
还有高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。**

[外链图片转存中…(img-UnJvKve3-1714873980687)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值