IPC的基础概念

IPC是Inter-Process Communication的缩写,含义是跨进程通信,今天先来了解下IPC的基础知识。

  • 多进程
  • 序列化
  • Binder机制

一.多进程概念

1.进程&线程

进程是资源分配的最小单位,在PC和移动设备上指一个程序和应用,而线程是CPU调度的最小单位,是一种有限的系统资源,一个进程可以包含多个线程,线程分为主线程(UI线程)和子线程(做耗时操作),不可在主线程中做大量耗时操作,会导致ANR。

2.多进程的开启方式

(1)通过JNI在native层fork一个新的进程,这个不常用。

(2)在AndroidMenifest中给四大组件设置属性android:process,这个比较常用,这里来了解下process属性的命名规则。

a.默认进程,没有指定该属性则运行在默认进程,默认进程名为包名。

b.私有进程,以":“开头的进程,省略了包名,如android:process=”:remote",其完整的名称为com.example.myapplication:remote,私有进程表示其它进程的组件不能和它跑在同一个进程当中。

c.全局进程,完整命名的进程,如android.process=“com.example.myapplication.remote”,它表示其它应用可以通过shareUID的方式和它跑在同一个进程当中。

UID和shareUID:
Android系统为每个应用分配一个唯一的UID,具有相同UID的应用才能共享数据。
两个应用通过shareUID跑在同一进程中的条件:shareUID相同且签名相同。满足这两个条件的应用无论是否跑在同一个进程中,都可以共享data目录、组件信息。若两个应用跑在同一个进程中,还可以共享内存数据。

3.多进程的使用场景

(1)某个应用由于自身原因需要多进程方式来实现,如某些模块由于特殊原因需要运行在独立进程。

(2)为了加大一个应用可使用的内存,通过多进程来获取多份内存空间。

(3)当前应用需要向其它应用获取数据。

4.多进程可能遇到的问题

(1)静态变量和单例模式失效,这是由于独立的虚拟机造成的。

(2)线程同步机制完全失效,这是由于独立的虚拟机造成的。

(3)SharedPreference可靠性降低,SharedPreference不支持两个进程并发读写操作,会有一定几率导致数据丢失。

(4)Application多次创建,android系统会为新进程分配独立的虚拟机,相当于系统把应用重新启动了一次。

二.序列化

1.序列化介绍

(1)含义:序列化表示把一个对象转换成可存储或可传输的状态,序列化后的对象可以在网络上进行传输,也可以存储到本地。

(2)使用场景:需要通过Intent或Binder传输类对象就必须完成对象的序列化过程。

(3)方式:通过Serializable和Parcelable接口。

2.Serializable和Parcelable的比较

IPC的基础概念_第1张图片
注意:两种变量不会参与序列化过程,一个是静态成员变量属于类,而不属于对象,另外一个是被transient关键字标记的成员变量。

3.具体实现

(1)实现Serializable接口

public class Person implements Serializable {

    private static final long serialVersionUID = 162468432145313L;//辅助序列化和反序列化,原则上序列化后数据的中serialVersionUID要和当前类的serialVersionUID相同才能正常的序列化
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

(2)实现Parcelable接口

public class Person implements Parcelable {

    private String name;
    private int age;

    protected Person(Parcel in) {
        name = in.readString();
        age = in.readInt();
    }

    public static final Creator CREATOR = new Creator() {
        @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(name);
        dest.writeInt(age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

三.Binder机制

1.进程架构

每个Android的进程都运行在独立的虚拟空间,虚拟空间又分为用户空间和内核空间,对于用户空间是不能共享的,内核空间则可以共享,Client端和Service端进行进程通信,利用的就是可共享的内核内存空间来完成底层的通信工作,其原理图如下:

IPC的基础概念_第2张图片
2.概念

(1)从API角度,是一个类,实现IBinder接口。

(2)从IPC角度,是Android中的一种跨进程通信方式。

(3)从Framework角度,是ServiceManager连接各个Manager和相应的ManagerService的桥梁。

(4)从应用层角度,是客户端和服务端进行通信的媒介。

3.优点

(1)性能方面

Binder机制传输效率高、可操作性强,其传输效率主要影响因素是内存拷贝次数,拷贝次数越少,传输效率越高,对于消息队列、socket和管道来说,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方缓存区,一共要拷贝两次。而对于Binder来说,数据从发送方的缓存区拷贝到内核缓存区,而接收方的缓存区与内核缓存区是映射到同一块物理地址的,节省了一次数据拷贝的过程。

(2)安全方面

Binder机制安全性能高,传统Linux IPC接收方无法获得对方进程可靠的PID/UID,从而没法鉴别对方身份,而Binder机制为每个进程分配了PID/UID且在Binder通信时会根据PID/UID进行有效性检测。

4.通信模型

Binder基于C/S的结构下,定义了四个角色:Server、Client、ServerManager、Binder驱动。其中前三者是在用户空间的,彼此之间无法直接进行交互,Binder驱动是属于内核空间的,负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持,其原理图如下:

IPC的基础概念_第3张图片
5.工作流程

(1)从Server进程来看,Binder是存在的实体对象,client通过transact()函数,经过Binder驱动,最终回调到Binder实体的onTransact()函数中。

(2)从Client进程的角度看,Binder指的是对Binder代理对象,是Binder实体对象的一个远程代理,通过Binder驱动进行交互。

6.代码实现

(1)定义一个接口,继承IInterface,代表服务端提供给客户端的能力。

public interface PersonManager extends IInterface {
    void addPerson(Person person);
    List getPersonList();
}

(2)定义Server中Binder实体对象,继承Binder,实现PersonManager。

public abstract class IPersonManager extends Binder implements PersonManager {
    //唯一标识
    public static final String DESCRIPTOR = "com.czy.binderdemo.ipc";
    public static final int TRANSAVTION_addPerson = IBinder.FIRST_CALL_TRANSACTION;
    public static final int TRANSAVTION_getPerson = IBinder.FIRST_CALL_TRANSACTION+1;
    //Binder驱动传递过来的IBinder对象
    public static PersonManager asInterface(IBinder iBinder) {
        //查找本地binder对象,如果有就返回,没有就返回代理
        IInterface iInterface = iBinder.queryLocalInterface(DESCRIPTOR);
        if(null!=iInterface && iInterface instanceof PersonManager){
            return (PersonManager) iInterface;
        }
        return new Proxy(iBinder);
    }
    //返回当前Binder对象
    @Override
    public IBinder asBinder() {
        return this;
    }
    //调用服务端不同的方法
    //code用于区分执行哪个方法
    //data客户端传递过来的参数
    //reply服务器返回回去的值
    //flags标明是否有返回值,0为有(双向),1为没有(单向
    @Override
    protected 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 TRANSAVTION_addPerson://执行addPerson方法
                data.enforceInterface(DESCRIPTOR);
                Person parcel= null;
                if (data.readInt() != 0) {
                    parcel = Person.CREATOR.createFromParcel(data);
                }
                this.addPerson(parcel);
                reply.writeNoException();
                return true;
            case TRANSAVTION_getPerson://执行getPerson方法
                data.enforceInterface(DESCRIPTOR);
                List result = this.getPersonList();
                reply.writeNoException();
                reply.writeTypedList(result);
                return true;
        }
        return super.onTransact(code, data, reply, flags);

    }
    //不在同一个进程时返回的代理
    public static class Proxy implements PersonManager{
    	//远程代理Binder
        private IBinder mIBinder;
        public Proxy(IBinder binder) {
            this.mIBinder = binder;
        }

        @Override
        public void addPerson(Person mPerson) {
            Parcel data = Parcel.obtain();
            Parcel replay = Parcel.obtain();

            try {
                data.writeInterfaceToken(DESCRIPTOR);
                if (mPerson != null) {
                    data.writeInt(1);
                    mPerson.writeToParcel(data, 0);
                } else {
                    data.writeInt(0);
                }
                //客户端会通过Binder驱动的transact()方法调用服务端代码
                mIBinder.transact(IPersonManager.TRANSAVTION_addPerson, data, replay, 0);
                replay.readException();
            } catch (RemoteException e){
                e.printStackTrace();
            } finally {
                replay.recycle();
                data.recycle();
            }
        }

        @Override
        public List getPersonList() {
            Parcel data = Parcel.obtain();
            Parcel replay = Parcel.obtain();
            List result = null;
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                mIBinder.transact(IPersonManager.TRANSAVTION_getPerson, data, replay, 0);
                replay.readException();
                result = replay.createTypedArrayList(Person.CREATOR);
            }catch (RemoteException e){
                e.printStackTrace();
            } finally{
                replay.recycle();
                data.recycle();
            }
            return result;
        }

        @Override
        public IBinder asBinder() {
            return null;
        }
    }

}

(3)定义Service

public class PersonService extends Service {

    private List mPeople = new ArrayList<>();
    private String TAG = "PersonService";

    @Override
    public void onCreate() {
        super.onCreate();
        mPeople.add(new Person("张三",12));
        mPeople.add(new Person("李四",15));
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return iPersonManager;
    }

    public IPersonManager iPersonManager = new IPersonManager() {
        @Override
        public void addPerson(Person person) {
            if (person != null) {
                mPeople.add(person);
            }
            Log.d(TAG,"Person 数量 : "+mPeople.size());
        }

        @Override
        public List getPersonList() {
            return mPeople;
        }
    };

}

(4)客户端绑定服务,获取Binder对象,调用方法进行交互。

 Intent intent = new Intent(this, PersonService.class);
 bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
 private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG,"connect success");
            personManager = IPersonManager.asInterface(service);
            List personList = personManager.getPersonList();
            Log.d(TAG,"Person 数量 :"+personList.size());
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG,"connect failed");
        }
    };
 public void click(View view) {
        if (personManager != null) {
            personManager.addPerson(new Person("王二麻子",14));
        }
    }

你可能感兴趣的:(IPC的基础概念)