Android AIDL的使用及分析

AIDL:Android Interface Definition Language,即Android接口定义语言。Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。
为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。

1.使用

1.1实现parcelable接口

跨进程通信的类必要实现Parcelable接口
Book.java

package com.example.zhouk.testproject.aidl;

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

public class Book implements Parcelable {
    public String bookName;

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

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

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

    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];
        }
    };
}

1.2对传递的类创建aidl文件

Book.aidl,且该文件必须位于com.example.zhouk.testproject.aidl目录下

package com.example.zhouk.testproject.aidl;

parcelable Book;

1.3创建接口aidl文件

IBookManager.aidl

package com.example.zhouk.testproject.aidl;

import com.example.zhouk.testproject.aidl.Book;

interface IBookManager {
    List<Book> getBookList();
    void addBook(in Book book);
}

上文代码中的接口一共有了两个函数接口,且必须引入parcelable类的路径,因为aidl与java文件不同,即使在同包下也必须手动导入。

1.4 build 项目

点击Build Project 会在build目录下生成IBookManager.java接口,在代码中继承这个接口就可以实现AIDL进程间通信了。

1.5 server实现接口

package com.example.zhouk.testproject.aidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import java.util.ArrayList;
import java.util.List;

public class BookService extends Service {
    private final String TAG = "BookService";

    private List<Book> bookList;

    public BookService() {}

    @Override
    public void onCreate() {
        super.onCreate();
        bookList = new ArrayList<>();
        bookList.add(new Book("TestBook"));
    }

    private final IBookManager.Stub binder = new IBookManager.Stub() {
        @Override
        public List<Book> getBookList() throws RemoteException {
            synchronized (bookList) {
                return bookList;
            }
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            if(book != null) {
                synchronized (bookList) {
                    bookList.add(book);
                }
            }
        }
    };
    
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

1.6 client调用接口

    IBookManager bookManager;
    Boolean connected = false;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            bookManager = IBookManager.Stub.asInterface(service);
            connected = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            connected = false;
        }
    };
    

client可以通过bindService方法,在ServiceConnection中获取到Binder,调用Stub.asInterface接口获取到接口,实现RPC 远程过程调用

2.分析

2.1总体分析

系统生成的IBookManager接口,核心功能实现主要在内部抽象类Stub里,Stub实现了IBookManager接口但未实现具体业务,且继承了android.os.Binder,故Stub就是服务端要实现的Binder接口,Stub内部有个Proxy类也实现了IBookManager接口,采用代理模式和Parcelable实现了跨进程通信,即跨进程中client调用的就是该Proxy类。

2.2 IBookManager接口分析

public interface IBookManager extends android.os.IInterface
{
public java.util.List<com.example.zhouk.testproject.aidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.zhouk.testproject.aidl.Book book) throws android.os.RemoteException;
}
IBookManager接口的代码比较简单,只有之前在aidl文件中定义的两个函数接口

2.3 Stub抽象类

Stub是IBookManager接口的内部抽象类,继承了android.os.Binder,是Binder的扩展类,在服务端的Service中,通过onBind函数返回,这里采用了里氏替换原则,而Stub的具体业务接口实现也是在Service中完成的。

  • Stub内部定义了一个DESCRIPTOR用作当前Binder的唯一标识。
  • asInterface函数
        public static com.example.zhouk.testproject.aidl.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.zhouk.testproject.aidl.IBookManager))) {
               return ((com.example.zhouk.testproject.aidl.IBookManager)iin);
            }
            return new com.example.zhouk.testproject.aidl.IBookManager.Stub.Proxy(obj);
        }

传递binder参数到函数内,调用该Binder变量的queryLocalInterface,判断当前进程是否是服务端进程,如果是就没有跨进程,直接返回改Binder,若跨进程则返回代理类Proxy,采用RPC方式处理。

  • asBinder函数
        @Override
        public android.os.IBinder asBinder()
        {
            return this;
        }

返回当前binder类

  • onTransact函数
        @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.zhouk.testproject.aidl.Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook:
                {
                data.enforceInterface(descriptor);
                com.example.zhouk.testproject.aidl.Book _arg0;
                if ((0!=data.readInt())) {
                _arg0 = com.example.zhouk.testproject.aidl.Book.CREATOR.createFromParcel(data);
                }
                else {
                _arg0 = null;
                }
                this.addBook(_arg0);
                reply.writeNoException();
                return true;
                }
                default:
                {
                return super.onTransact(code, data, reply, flags);
                }
            }
        }

RPC的核心传输代码,该函数运行在服务端中的Binder线池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。code确定目标方法,data为写入参数,reply为返回值。

2.4 Proxy类

Proxy实现了IBookManager接口,对两接口实现了RPC数据封装,

      android.os.Parcel _data = android.os.Parcel.obtain();
      android.os.Parcel _reply = android.os.Parcel.obtain();

初始化信息传递的载体

        _data.writeInterfaceToken(DESCRIPTOR);
                    if ((book!=null)) {
                    _data.writeInt(1);
                    book.writeToParcel(_data, 0);
                    }   

addBook中,book参数的传入

mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);

发起传输

                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.example.zhouk.testproject.aidl.Book.CREATOR);

读取返回值

完整代码

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: C:\\Users\\zhouk\\AndroidStudioProjects\\testProject\\app\\src\\main\\aidl\\com\\example\\zhouk\\testproject\\aidl\\IBookManager.aidl
 */
package com.example.zhouk.testproject.aidl;
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.example.zhouk.testproject.aidl.IBookManager
    {
        private static final java.lang.String DESCRIPTOR = "com.example.zhouk.testproject.aidl.IBookManager";
/** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
/**
 * Cast an IBinder object into an com.example.zhouk.testproject.aidl.IBookManager interface,
 * generating a proxy if needed.
 */
        public static com.example.zhouk.testproject.aidl.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.zhouk.testproject.aidl.IBookManager))) {
               return ((com.example.zhouk.testproject.aidl.IBookManager)iin);
            }
            return new com.example.zhouk.testproject.aidl.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.zhouk.testproject.aidl.Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook:
                {
                data.enforceInterface(descriptor);
                com.example.zhouk.testproject.aidl.Book _arg0;
                if ((0!=data.readInt())) {
                _arg0 = com.example.zhouk.testproject.aidl.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.zhouk.testproject.aidl.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.zhouk.testproject.aidl.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.zhouk.testproject.aidl.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.example.zhouk.testproject.aidl.Book.CREATOR);
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
            @Override public void addBook(com.example.zhouk.testproject.aidl.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);
                }
                mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                _reply.readException();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
        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.zhouk.testproject.aidl.Book> getBookList() throws android.os.RemoteException;
    public void addBook(com.example.zhouk.testproject.aidl.Book book) throws android.os.RemoteException;
}

发布了170 篇原创文章 · 获赞 69 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/qq951127336/article/details/90674879