安卓IPC机制(一)

🧭 安卓中的多进程模式

💡 多进程模式: 安卓可以通过android:process属性为四大组件开启多进程模式,若以:开头则属于该应用的子进程,否则是另外一个新进程。
注意:开启多进程后,安卓会为每一个应用开启一个独立虚拟机,或者说每一个进程都会有一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,导致数据不共享。

使用多进程造成的问题:

  • 静态成员和单例模式完全失效;
  • 线程同步机制共享失败;
  • SharedPreferences的可靠性下降(SharedPreferences不支持两个进程同时去进行写操作,若如此会有一定几率导致数据丢失);
  • Application会多次创建。

🔭 IPC基础概念介绍

1.序列化方式

💡 主要有Parcelable和Serializable接口,通过实现这两个接口可以实现序列化,总的来说,Parcelable的效率要高一些。

2.Binder

💡 Binder是安卓中的一种跨进程的通信方式,实现了IBinder接口,是安卓系统的通信的基石。
从Framework角度来说,Binder是ServiceManager连接各种Manager及相应ManagerService的桥梁,从Android应用层来说,Binder是客户端及服务端进行通信的媒介。当bindService时,服务端会返回包含服务端业务调用的Binder对象,客户端可以获取服务端说提供的服务或数据,这里的服务包括普通服务和AIDL服务。

以AIDL为例进行分析,新建以下代码文件:

//Book.java
package com.example.artandroidlearn;

import android.os.Parcel;
import android.os.Parcelable;

import androidx.annotation.NonNull;

public class Book implements Parcelable {

    public int bookId;
    public String bookName;

    public Book() {
    }

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

    @NonNull
    @Override
    public String toString() {
        return bookId + ":" + bookName;
    }
}
// Book.aidl
package com.example.artandroidlearn;

// Declare any non-default types here with import statements

parcelable Book;
// IBookManager.aidl
package com.example.artandroidlearn;
import com.example.artandroidlearn.Book;
import com.example.artandroidlearn.IonNewBookArrivedListener;

// Declare any non-default types here with import statements

interface IBookManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    List<Book> getBookList();
    void addBook(in Book book);
}

新建完上述代码后点击运行或编译,系统会根据IBookManager.aidl生成一个名为IBookManager.java 的binder接口,分析该代码并进行拆分:

  • IBookManager继承自android.os.IInterface接口;
  • 声明了IBookManager.aidl 的两个方法,如下所示:
/**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
  public java.util.List<com.example.artandroidlearn.Book> getBookList() throws android.os.RemoteException;
  public void addBook(com.example.artandroidlearn.Book book) throws android.os.RemoteException;
  • 声明了两个内部类DefaultStub

Default类(该类作用未知,待研究)

public static class Default implements com.example.artandroidlearn.IBookManager
  {
    /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    @Override public java.util.List<com.example.artandroidlearn.Book> getBookList() throws android.os.RemoteException
    {
      return null;
    }
    @Override public void addBook(com.example.artandroidlearn.Book book) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  • Stub类,Stub类里面有Proxy
public static abstract class Stub extends android.os.Binder implements com.example.artandroidlearn.IBookManager
  {
    private static final java.lang.String DESCRIPTOR = "com.example.artandroidlearn.IBookManager";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.example.artandroidlearn.IBookManager interface,
     * generating a proxy if needed.
     */
    public static com.example.artandroidlearn.IBookManager asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.artandroidlearn.IBookManager))) {
        return ((com.example.artandroidlearn.IBookManager)iin);
      }
      return new com.example.artandroidlearn.IBookManager.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
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_getBookList:
        {
          data.enforceInterface(descriptor);
          java.util.List<com.example.artandroidlearn.Book> _result = this.getBookList();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
        case TRANSACTION_addBook:
        {
          data.enforceInterface(descriptor);
          com.example.artandroidlearn.Book _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.example.artandroidlearn.Book.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.addBook(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.example.artandroidlearn.IBookManager
    {
      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 java.util.List<com.example.artandroidlearn.Book> getBookList() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.example.artandroidlearn.Book> _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getBookList();
          }
          _reply.readException();
          _result = _reply.createTypedArrayList(com.example.artandroidlearn.Book.CREATOR);
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void addBook(com.example.artandroidlearn.Book book) 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 ((book!=null)) {
            _data.writeInt(1);
            book.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addBook(book);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.example.artandroidlearn.IBookManager sDefaultImpl;
    }

💡 当客户端和服务端位于同一个进程的时候,不会走Stub的transact过程,否则,则会调用transact过程,而具体逻辑则由Stub的内部代理类Proxy来完成。需要注意的是,跨进程通信主要是Stub类和其内部代理类Proxy来完成。

2.1 Stub类分析

  • Stub() :构造器,创建以DESCRIPTOR 为名称的Binder对象
public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
  • DESCRIPTORBinder 的唯一标识,一般用类名表示;另外两个是方法ID
private static final java.lang.String DESCRIPTOR = "com.example.artandroidlearn.IBookManager";

static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
  • asInterface 方法:将服务端的Binder对象转换成客户端所需要的AIDL接口类型的对象,其转换是区分进程的,若客户端和服务端位于同一个进程,则返回服务端Stub本身,否则直接返回Stub.Proxy对象。
/**
     * Cast an IBinder object into an com.example.artandroidlearn.IBookManager interface,
     * generating a proxy if needed.
     */
    public static com.example.artandroidlearn.IBookManager asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.artandroidlearn.IBookManager))) {
        //返回服务端Stub对象
				return ((com.example.artandroidlearn.IBookManager)iin);
      }
			//返回Stub.Proxy对象
      return new com.example.artandroidlearn.IBookManager.Stub.Proxy(obj);
    }
  • asBinder() :返回当前的Binder对象
@Override public android.os.IBinder asBinder()
    {
      return this;
    }
  • onTransact :此方法运行在服务端的Binder线程池中,客户端发起跨进程请求时,远程请求通过系统底层封装后,由此方法处理。注意onTransact 方法返回false 代表客户端请求失败
/**
*code:表明请求方法是什么
*data: 目标方法所需要的参数,若目标方法有参数的话,则会从该参数里面获取参数
*reply:目标方法执行完之后,通过写入到该参数里面返回
*flags:Additional operation flags. Either 0 for a normal RPC,
*      or FLAG_ONEWAY for a one-way RPC.
**/

@Override public boolean onTransact(int code, android.os.Parcel data, 
					android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_getBookList:
        {
          data.enforceInterface(descriptor);
          java.util.List<com.example.artandroidlearn.Book> _result = this.getBookList();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
        case TRANSACTION_addBook:
        {
          data.enforceInterface(descriptor);
          com.example.artandroidlearn.Book _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.example.artandroidlearn.Book.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.addBook(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
  • sDefaultImpl 的set和get方法,这里面*sDefaultImpl* 方法是IBookManager 的一个对象本身
public static boolean setDefaultImpl(com.example.artandroidlearn.IBookManager impl) {
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.example.artandroidlearn.IBookManager getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  • Proxy :内部策略类:客户端本地的Binder对象,这里面实现了在IBookManager 里面定义的方法,通过调用transact 方法最后调用到了onTransact 方法实现了客户端和服务端的通信。
private static class Proxy implements com.example.artandroidlearn.IBookManager
    {
      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 java.util.List<com.example.artandroidlearn.Book> getBookList() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.example.artandroidlearn.Book> _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
          //若_status为false表明客户端请求失败,调用客户端本地实现的方法
					if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getBookList();
          }
          _reply.readException();
          _result = _reply.createTypedArrayList(com.example.artandroidlearn.Book.CREATOR);
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void addBook(com.example.artandroidlearn.Book book) 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 ((book!=null)) {
            _data.writeInt(1);
            book.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addBook(book);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.example.artandroidlearn.IBookManager sDefaultImpl;
    }

💡 注意客户端发起请求时,当前线程会被挂起直到服务端进程返回数据,因此如果远程请求是耗时方法则不能通过UI线程发起此远程请求,另外,由于服务端的Binder方法运行在Binder线程池中,因此Binder方法不管是否耗时都应该采取同步的方式去实现。

综上,Binder工作机制及流程

在这里插入图片描述

根据系统由aidl生成IBookManager.java方式,用自己的方式进行改写,如下,改写完的基本和原来一致,但是可以不用通过aidl的方式生成:

package com.example.artandroidlearn;

import android.os.IInterface;

public interface IBookManager1 extends IInterface {
    public static final String DESCRIPTOR = "com.example.learnartandroid.IBookManager";
    static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

    public java.util.List<com.example.artandroidlearn.Book> getBookList() throws android.os.RemoteException;

    public void addBook(com.example.artandroidlearn.Book book) throws android.os.RemoteException;
}
package com.example.artandroidlearn;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

import java.util.List;

public class BookManagerImpl extends Binder implements com.example.artandroidlearn.IBookManager1 {

    public BookManagerImpl() {
        this.attachInterface(this, DESCRIPTOR);
    }

    public static com.example.artandroidlearn.IBookManager1 asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (iin != null && iin instanceof BookManagerImpl) {
            return (com.example.artandroidlearn.IBookManager1) obj;
        }
        return new Proxy(obj);
    }

    @Override
    public List<Book> getBookList() throws RemoteException {
        return null;
    }

    @Override
    public void addBook(Book book) throws RemoteException {

    }

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

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        String descriptor = DESCRIPTOR;
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(descriptor);
                return true;
            }
            case TRANSACTION_getBookList: {
                data.enforceInterface(descriptor);
                List<com.example.artandroidlearn.Book> result = this.getBookList();
                reply.writeNoException();
                reply.writeTypedList(result);
                return true;
            }
            case TRANSACTION_addBook: {
                data.enforceInterface(descriptor);
                com.example.artandroidlearn.Book _arg0;
                if ((0 != data.readInt())) {
                    _arg0 = com.example.artandroidlearn.Book.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }
                this.addBook(_arg0);
                reply.writeNoException();
                return true;
            }
            default: {
                return super.onTransact(code, data, reply, flags);
            }
        }
    }

    private static class Proxy implements com.example.artandroidlearn.IBookManager1 {

        private IBinder mRemote;

        public Proxy(IBinder mRemote) {
            this.mRemote = mRemote;
        }

        public String getInterfaceDescriptor() {
            return DESCRIPTOR;
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            List<Book> result;
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                mRemote.transact(TRANSACTION_getBookList, data, reply, 0);
                reply.readException();
                result = reply.createTypedArrayList(Book.CREATOR);
            } finally {
                reply.recycle();
                data.recycle();
            }
            return result;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                if (book != null) {
                    data.writeInt(1);
                    book.writeToParcel(data, 0);
                } else {
                    data.writeInt(0);
                }
                mRemote.transact(TRANSACTION_addBook, data, reply, 0);
                reply.readException();
            } finally {
                reply.recycle();
                data.recycle();
            }

        }

        @Override
        public IBinder asBinder() {
            return mRemote;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值