手写Binder实现android中的进程间通信

作者 : 开心源码 本文共13048个字,预计阅读时间需要33分钟 发布时间: 2022-05-12 共119人阅读

在Android系统中,每个应用都运行在一个进程上,具备自己的DVM实例,而且进程之间是相互隔离的,也就是说各个进程之间的数据是互相独立,互不影响的,而假如一个进程崩溃了,也不会影响到另一个进程。
为什么采取这样的设计呢,比方这样的前提下将互相不影响的系统功能分拆到不同的进程里面去,有助于提升系统的稳固性,毕竟我们都不想自己的应用进程崩溃会导致整个手机系统的崩溃。
进程之间隔离是不错的选择,可是假如进程之间想要互相通信,进行数据交互的时候那该怎样办呢?例如我们在自己的应用中想要访问手机通讯录中的联络人,很显然这是两个不同的进程,假如Android没有提供一种进程之间交流的机制,那么这种功能将无法实现,不过因为Android系统使用的是Linux内核,而在Linux系统中进程之间的交互是有一套机制的,所以Android也借鉴了其中的少量机制,从而形成了Android的IPC机制,其意思就是进程间的通信,也就是两个进程之间的通信过程。
下面我们通过小例子看看;

1、新建一个Person类,并公告一个静态变量:

 public class Person {     public static String name="张三"; }

2、在MainActivity的onCreate方法中修改name的值,并打印log

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    Log.d("MainActivity", "原名:" + Person.name);    person.name = "李四";    Log.d("MainActivity", "修改后:" + Person.name);}

3、将TestActivity设置为新进程,并在其onCreate方法中访问name

<activity android:name=".TestActivity"android:process=":second"></activity>  public class TestActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_test);        Log.d("TestActivity" , Person.name);    }}  

运行看看结果:

1112.png

TestActivity中获取到了name值并未修改。

1113.png

通过以上的例子,大家应该明白了一点:在不同的进程之间访问同一个静态变量是行不通的。其起因是:每一个进程都分配有一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机上访问同一个对象会产生多个副本。例如我们在MainActivity中访问的name的值只会影响当前进程,而对其余进程不会造成影响,所以在TestActivity中访问name时仍旧只能访问自己进程中的副本。

Android处理IPC的方法中有一种是AIDL,它使用的原理就是Binder,只有了解了Binder,我们才算是了解了Android跨进程通信的原理。在这里我会带大家看看Android中有哪少量重要的地方使用到了Binder,接着我们会通过一个实例来理解如何使用Binder。
Binder在Android中的运用

说起Binder在Android的使用场景,可以说是无处不在,我列出少量最常见的场景:

四大组件的生命周期都是使用Binder机制进行管理的,比方AMS,PMS,PMS,
View的工作原理也使用了Binder
WindowManager的工作机制同样使用了Binder

接下来我们通过传统的AIDL实现进程间通讯。
1、创立Person.java,Person.aidl,IPersonManager.aidl

public class Person implements Parcelable {    public String name = "张三";    public Person() {    }    public Person(String name) {        this.name = name;    }    public Person(Parcel in) {        this.name = in.readString();    }    public static final Creator<Person> CREATOR = new Creator<Person>() {        @Override        public Person createFromParcel(Parcel in) {            return new Person(in);        }        @Override        public Person[] newArray(int size) {            return new Person[size];        }    };    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeString(this.name);    }}

创立完毕之后手动编译项目(Build–>make Project),接着就会在

app/build/generated/source/aidl/debug/com/binder/IPersonManager.java中看到自动生成的IStudentManager接口

1114.png

2、分析IPersonManager.java

        public interface IPersonManager extends android.os.IInterface {    /**     * 内部类Stub,继承自Binder并且实现了IStudentManager接口,因而他也是一个Binder对象,这个内部类是需要在服务端手动实现的,并且会通过onBind方法返回给用户端     * Local-side IPC implementation stub class.     */    public static abstract class Stub extends android.os.Binder implements com.binder.IPersonManager {        /**         * 唯一的binder标示 可以看到就是IPersonManager的全路径名         */        private static final java.lang.String DESCRIPTOR = "com.binder.IPersonManager";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * 将服务端的Binder对象转换为用户端的所需的AIDL接口类型的对象,用户端拿到这个对象即可以通过这个对象远程访问服务端的方法         * Cast an IBinder object into an com.binder.IPersonManager interface,         * generating a proxy if needed.         */        public static com.binder.IPersonManager asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.binder.IPersonManager))) {                return ((com.binder.IPersonManager) iin);            }            return new com.binder.IPersonManager.Stub.Proxy(obj);        }        @Override        public android.os.IBinder asBinder() {            return this;        }        /**         * 运行在服务端进程的Binder线程池中;当用户端进程发起远程请求时,远程请求会要求系统底层执行回调该方法         * @param code 用户端进程请求方法标识符。服务端进程会根据该标识确定所请求的目标方法         * @param data 目标方法的参数,他是用户端进程传进来的,当我们调用addPerson(Person person)方法时,参数就是Person对象         * @param reply 目标方法执行后的结果,将会返回给用户端,例如当我们调用getPersonList,返回的就是一个Person的列表         */        @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_getPersonList: {                    data.enforceInterface(DESCRIPTOR);                    java.util.List<com.binder.Person> _result = this.getPersonList();                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }                case TRANSACTION_addPerson: {                    data.enforceInterface(DESCRIPTOR);                    com.binder.Person _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.binder.Person.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    this.addPerson(_arg0);                    reply.writeNoException();                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        /**         * 代理商的内部类,他实现了IStudentManager接口,这个代理商类就是服务端返回给用户端的AIDL接口对象,用户端可以通过这个代理商类访问服务端的方法         */        private static class Proxy implements com.binder.IPersonManager {            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;            }            /**             *这里我们一共有2个方法 一个getPersonList 一个addPerson 我们就分析一个方法即可以了             *并且要知道 这2个方法运行在用户端!!!!!!!!!!!!!!!!             *首先就是创立了3个对象_data 输入对象,_reply输出对象,_result返回值对象             *而后把参数信息 写入到_data里,接着就调用了transact这个方法 来发送rpc请求,而后接着             *当前线程挂起, 服务端的onTransace方法才被调用,调用结束以后 当前线程继续执行,直到             *从_reply中取出rpc的返回结果 而后返回_reply的数据             *所以这里我们就要注意了,用户端发起调用远程请求时,当前用户端的线程就会被挂起了,             *所以假如一个远程方法 很耗时,我们用户端就肯定不能在ui main线程里在发起这个rpc请求,不然就anr了。             * @return             * @throws android.os.RemoteException             */            @Override            public java.util.List<com.binder.Person> getPersonList() throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.util.List<com.binder.Person> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.binder.Person.CREATOR);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            @Override            public void addPerson(com.binder.Person person) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    if ((person != null)) {                        _data.writeInt(1);                        person.writeToParcel(_data, 0);                    } else {                        _data.writeInt(0);                    }                    mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);                    _reply.readException();                } finally {                    _reply.recycle();                    _data.recycle();                }            }        }        static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);        static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);    }    public java.util.List<com.binder.Person> getPersonList() throws android.os.RemoteException;    public void addPerson(com.binder.Person person) throws android.os.RemoteException;}

对于进程间通信来说,具体的流程就分为如下几步:

1.Client 发起远程调用请求 也就是RPC 到Binder。同时将自己挂起,挂起的起因是要等待RPC调用结束以后返回的结果

2.Binder 收到RPC请求以后 把参数收集一下,调用transact方法,把RPC请求转发给service端。

3.service端 收到rpc请求以后 就去线程池里 找一个空闲的线程去走service端的 onTransact方法 ,实际上也就是真正在运行service端的 方法了,等方法运行结束 就把结果 写回到binder中。

4.Binder 收到返回数据以后 就唤醒原来的Client 线程,返回结果。至此,一次进程间通信 的过程就结束了

创立RemoteService,模拟服务端;

public class RemoteService extends Service {//适合用于进程间传输的列表类private CopyOnWriteArrayList<Person> mPersonsList = new CopyOnWriteArrayList<>();public final IPersonManager.Stub mBinder = new IPersonManager.Stub() {    @Override    public List<Person> getPersonList() throws RemoteException {        return mPersonsList;    }    @Override    public void addPerson(Person person) {        mPersonsList.add(person);    }};@Overridepublic void onCreate() {    super.onCreate();    mPersonsList.add(new Person("小明"));    mPersonsList.add(new Person("小李"));    mPersonsList.add(new Person("小华"));    Log.d(RemoteService.class.getSimpleName(), "RemoteService 启动了");}@Nullable@Overridepublic IBinder onBind(Intent intent) {    return mBinder;}

}

在用户端绑定Service!

public class TestActivity extends AppCompatActivity {public static String TAG = TestActivity.class.getSimpleName();private IPersonManager mPersonManager;private ServiceConnection mConnection = new ServiceConnection() {    //onServiceConnected与onServiceDisconnected都是在主线程中的,所以假如里面假如涉及到服务端的耗时操作那么需要在子线程中进行    @Override    public void onServiceConnected(ComponentName name, IBinder service) {        //获取到IPersonManager对象        mPersonManager = com.binder.IPersonManager.Stub.asInterface(service);    }    @Override    public void onServiceDisconnected(ComponentName name) {        mPersonManager = null;    }};@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_test);    Intent intent = new Intent(this, RemoteService.class);    bindService(intent, mConnection, BIND_AUTO_CREATE);}/** * 在用户端向服务端增加Person * * @param view */public void addPerson(View view) {    if (mPersonManager != null) {        try {            Person mPerson1 = new Person("王五");            mPersonManager.addPerson(mPerson1);            Log.d(TAG, "增加一位学生:" + mPerson1.name);            Person mPerson2 = new Person("赵六");            mPersonManager.addPerson(mPerson2);            Log.d(TAG, "增加一位学生:" + mPerson2.name);            Person mPerson3 = new Person("麻子");            mPersonManager.addPerson(mPerson3);            Log.d(TAG, "增加一位学生:" + mPerson3.name);        } catch (Exception e) {            e.printStackTrace();        }    }}/** * 在用户端向服务端发起查询学生的请求 * * @param view */public void getPerson(View view) {    //因为服务端的查询操作是耗时操作,所以用户端需要开启子线程进行工作    new Thread(new Runnable() {        @Override        public void run() {            if (mPersonManager != null) {                try {                    final List<Person> students = mPersonManager.getPersonList();                    for (int i = 0; i < students.size(); i++) {                        Log.d(TAG, "从服务器获取到学生:" + students.get(i).name);                    }                } catch (Exception e) {                    e.printStackTrace();                }            }        }    }).start();}

}

增加数据:

1116.png

查询服务端数据

1117.png

通过上面的案例大概明白,分别是Activity充任用户端,服务端的RemoteService,充任服务管理者的IPersonManager以及充任访问介质的Binder驱动。他们的职责如下:

RemoteService: 服务提供者,这里面会有许多我们常用的服务,在本 例中提供的服务就是增加学生以及获取学生列表。而在系统中则包括有ActivityService 、 WindowMananger等服务,这些系统服务提供的功能,对四大组件以及Window的工作提供的保障。
Activity: 服务调用者,一般就是我们的应用,在这里我们通过调用RemoteService的服务来完成工作。
IPersonManager: 他是负责管理服务的,在其内部通过Map集合来存储Service与Binder的映射关系,这样用户端在向其请求服务的时候就能够返回特定的Binder。
Binder驱动: 他是IPersonManager连接各种Service的桥梁,同时也是用户端与服务端交流的桥梁。

连串起来就是用户端(Activity)首先向IPersonManager发送请求RemoteService的服务,IPersonManager查看已经注册在里面的服务的列表,找到相应的服务后,通过Binder驱动将其中的Binder对象返回给用户端,从而完成对服务的请求。

接下来,我们即可以来尝试着手写一下Binder:
写一个接口IPersonManager

 public interface IPersonManager extends IInterface {      List<Person> getPersonList() throws RemoteException;     void addPerson(Person person) throws RemoteException; }

写一个继承自Binder的笼统类PersonManagerImpl并实现IPersonManager接口,

public abstract class PersonManagerImpl extends Binder implements IPersonManager {//唯一标识用于注册该BInder,用包名+接口名定义private static final String DESCRIPTOR = "com.binder.aidl.IPersonManager";//getList方法唯一标识static final int TRANSACTION_getList = (IBinder.FIRST_CALL_TRANSACTION + 0);//add方法唯一标识static final int TRANSACTION_add = (IBinder.FIRST_CALL_TRANSACTION + 1);public PersonManagerImpl() {    //注册该binder    this.attachInterface(this, DESCRIPTOR);}public static IPersonManager asInterface(IBinder obj) {    if ((obj == null)) {        return null;    }    IInterface iin = obj.queryLocalInterface(DESCRIPTOR);    //查询当前进程    if (((iin != null) && (iin instanceof PersonManagerImpl))) {        return (PersonManagerImpl) iin;//当前进程返回IBookManager    }    return new Proxy(obj);//非当前进程返回Proxy}@Overrideprotected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,                             int flags) throws RemoteException {    switch (code) {        case INTERFACE_TRANSACTION: {            reply.writeString(DESCRIPTOR);            return true;        }        case TRANSACTION_getList: {            data.enforceInterface(DESCRIPTOR);            List<Person> _result = this.getPersonList();            reply.writeNoException();            reply.writeTypedList(_result);            return true;        }        case TRANSACTION_add: {            data.enforceInterface(DESCRIPTOR);            Person person;            if ((0 != data.readInt())) {                person = Person.CREATOR.createFromParcel(data);            } else {                person = null;            }            this.addPerson(person);            reply.writeNoException();            return true;        }    }    return super.onTransact(code, data, reply, flags);}@Overridepublic IBinder asBinder() {    return this;}public static class Proxy implements IPersonManager {    private IBinder mRemote;    public String getInterfaceDescriptor() {        return DESCRIPTOR;    }    public Proxy(IBinder obj) {        this.mRemote = obj;    }    @Override    public List<Person> getPersonList() throws RemoteException {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        List<Person> result;        try {            data.writeInterfaceToken(DESCRIPTOR);            mRemote.transact(TRANSACTION_getList, data, reply, 0);            reply.readException();            result = reply.createTypedArrayList(Person.CREATOR);        } finally {            reply.recycle();            data.recycle();        }        return result;    }    @Override    public void addPerson(Person person) throws RemoteException {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        try {            data.writeInterfaceToken(DESCRIPTOR);            if ((person != null)) {                data.writeInt(1);                person.writeToParcel(data, 0);            } else {                data.writeInt(0);            }            mRemote.transact(TRANSACTION_add, data, reply, 0);            reply.readException();        } finally {            reply.recycle();            data.recycle();        }    }    @Override    public IBinder asBinder() {        return null;    }}

}

我们的手写binder 就完成了,而后看看 service 以及用户端 怎样调用。

public class RemoteService extends Service {    public final PersonManagerImpl mBinder = new PersonManagerImpl() {    @Override    public List<Person> getPersonList() throws RemoteException {        return mPersonsList;    }    @Override    public void addPerson(Person person) {        mPersonsList.add(person);    }};//适合用于进程间传输的列表类private CopyOnWriteArrayList<Person> mPersonsList = new CopyOnWriteArrayList<>();@Overridepublic void onCreate() {    super.onCreate();    mPersonsList.add(new Person("小明"));    mPersonsList.add(new Person("小李"));    mPersonsList.add(new Person("小华"));    Log.d(RemoteService.class.getSimpleName(), "RemoteService 启动了");}@Nullable@Overridepublic IBinder onBind(Intent intent) {    return mBinder;}

}

启动 Service:

 private ServiceConnection mConnection = new ServiceConnection() {    //onServiceConnected与onServiceDisconnected都是在主线程中的,所以假如里面假如涉及到服务端的耗时操作那么需要在子线程中进行    @Override    public void onServiceConnected(ComponentName name, IBinder service) {        //获取到IPersonManager对象        mPersonManager = PersonManagerImpl.asInterface(service);    }    @Override    public void onServiceDisconnected(ComponentName name) {        mPersonManager = null;    }}; 

到这 就基本写完了

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 手写Binder实现android中的进程间通信

发表回复