二、Android中的IPC方式:AIDL

AIDL相关的重要类和接口

1.IInterface
2.IBinder
3.Binder
4.BinderProxy

IInterface

public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.
     */
    public IBinder asBinder();
}

IBinder

    /**
     * Attempt to retrieve a local implementation of an interface
     * for this Binder object.  If null is returned, you will need
     * to instantiate a proxy class to marshall calls through
     * the transact() method.
     */
    public @Nullable IInterface queryLocalInterface(@NonNull String descriptor);

    /**
     * Perform a generic operation with the object.
     * 
     * @param code The action to perform.  This should
     * be a number between {@link #FIRST_CALL_TRANSACTION} and
     * {@link #LAST_CALL_TRANSACTION}.
     * @param data Marshalled data to send to the target.  Must not be null.
     * If you are not sending any data, you must create an empty Parcel
     * that is given here.
     * @param reply Marshalled data to be received from the target.  May be
     * null if you are not interested in the return value.
     * @param flags Additional operation flags.  Either 0 for a normal
     * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
     *
     * @return Returns the result from {@link Binder#onTransact}.  A successful call
     * generally returns true; false generally means the transaction code was not
     * understood.
     */
    public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
        throws RemoteException;

    /**
     * Interface for receiving a callback when the process hosting an IBinder
     * has gone away.
     * 
     * @see #linkToDeath
     */
    public interface DeathRecipient {
        public void binderDied();
    }

    public void linkToDeath(@NonNull DeathRecipient recipient, int flags)
            throws RemoteException;

    public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags);

Binder

private IInterface mOwner;
private String mDescriptor;

public class Binder implements IBinder {
   ...
   public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }

   public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
        if (mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }
   ...
}

BinderProxy

    /**
     * Retrieve a local interface - always null in case of a proxy
     */
    public IInterface queryLocalInterface(String descriptor) {
        return null;
    }

IMusicService.aidl 的定义

interface IMusicService {

    void updateMusicList(in List<SongInfo> musicFileList);

    void getPlayList(out List<SongInfo> musicFileList);

    boolean play(int position);

    boolean pause();

    boolean stop();

}

void updateMusicList(in List<SongInfo> musicFileList);
void getPlayList(out List<SongInfo> musicFileList);中的in和out表示数据走向的方向标记。in表示走向Remote服务,out表示走向客户端。它们之间的细节差别表现:

in_out数据走向01.png
in_out数据走向02.png

IMusicService 的类结构

IMusicService 有一个抽象的子类Stub, Stub继承自Binder,实现了IMusicService接口。Stub里面定义了一个Proxy类,Stub.Proxy直接实现了IMusicService接口。

public interface IMusicService extends android.os.IInterface {

    public static abstract class Stub extends android.os.Binder implements com.chiang.chnplayer.aidl.IMusicService {
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        private static class Proxy implements com.chiang.chnplayer.aidl.IMusicService {
            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }
        }

        public static com.chiang.chnplayer.aidl.IMusicService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.chiang.chnplayer.aidl.IMusicService))) {
                return ((com.chiang.chnplayer.aidl.IMusicService) iin);
            }
            return new com.chiang.chnplayer.aidl.IMusicService.Stub.Proxy(obj);
        }

    }

    public void updateMusicList(java.util.List<com.chiang.chnplayer.aidl.SongInfo> musicFileList) throws android.os.RemoteException;

    public void getPlayList(java.util.List<com.chiang.chnplayer.aidl.SongInfo> musicFileList) throws android.os.RemoteException;

    public boolean play(int position) throws android.os.RemoteException;

    public boolean pause() throws android.os.RemoteException;

    public boolean stop() throws android.os.RemoteException;
}
AIDL_IMusicService02_类结构.png

IMusicService 的具体实现

public interface IMusicService extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.chiang.chnplayer.aidl.IMusicService {
        private static final java.lang.String DESCRIPTOR = "com.chiang.chnplayer.aidl.IMusicService";

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

        /**
         * Cast an IBinder object into an com.chiang.chnplayer.aidl.IMusicService interface,
         * generating a proxy if needed.
         */
        public static com.chiang.chnplayer.aidl.IMusicService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.chiang.chnplayer.aidl.IMusicService))) {
                return ((com.chiang.chnplayer.aidl.IMusicService) iin);
            }
            return new com.chiang.chnplayer.aidl.IMusicService.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_updateMusicList: {
                    //验证Binder标识
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<com.chiang.chnplayer.aidl.SongInfo> _arg0;
                    _arg0 = data.createTypedArrayList(com.chiang.chnplayer.aidl.SongInfo.CREATOR);
                    this.updateMusicList(_arg0);//这调用的是继承IMusicService.Stub后实现的方法
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getPlayList: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<com.chiang.chnplayer.aidl.SongInfo> _arg0;
                    _arg0 = new java.util.ArrayList<com.chiang.chnplayer.aidl.SongInfo>();
                    this.getPlayList(_arg0);
                    reply.writeNoException();
                    reply.writeTypedList(_arg0);
                    return true;
                }
                case TRANSACTION_play: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    boolean _result = this.play(_arg0);
                    reply.writeNoException();
                    reply.writeInt(((_result) ? (1) : (0)));
                    return true;
                }
                case TRANSACTION_pause: {
                    data.enforceInterface(DESCRIPTOR);
                    boolean _result = this.pause();
                    reply.writeNoException();
                    reply.writeInt(((_result) ? (1) : (0)));
                    return true;
                }
                case TRANSACTION_stop: {
                    data.enforceInterface(DESCRIPTOR);
                    boolean _result = this.stop();
                    reply.writeNoException();
                    reply.writeInt(((_result) ? (1) : (0)));
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.chiang.chnplayer.aidl.IMusicService {
            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 void updateMusicList(java.util.List<com.chiang.chnplayer.aidl.SongInfo> musicFileList) 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.writeTypedList(musicFileList);
                    mRemote.transact(Stub.TRANSACTION_updateMusicList, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public void getPlayList(java.util.List<com.chiang.chnplayer.aidl.SongInfo> musicFileList) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPlayList, _data, _reply, 0);
                    _reply.readException();
                    _reply.readTypedList(musicFileList, com.chiang.chnplayer.aidl.SongInfo.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public boolean play(int position) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(position);
                    mRemote.transact(Stub.TRANSACTION_play, _data, _reply, 0);
                    _reply.readException();
                    _result = (0 != _reply.readInt());
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public boolean pause() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_pause, _data, _reply, 0);
                    _reply.readException();
                    _result = (0 != _reply.readInt());
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public boolean stop() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0);
                    _reply.readException();
                    _result = (0 != _reply.readInt());
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_updateMusicList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getPlayList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_play = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
        static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
    }

    public void updateMusicList(java.util.List<com.chiang.chnplayer.aidl.SongInfo> musicFileList) throws android.os.RemoteException;

    public void getPlayList(java.util.List<com.chiang.chnplayer.aidl.SongInfo> musicFileList) throws android.os.RemoteException;

    public boolean play(int position) throws android.os.RemoteException;

    public boolean pause() throws android.os.RemoteException;

    public boolean stop() throws android.os.RemoteException;
}

data.enforceInterface(DESCRIPTOR);//验证Binder标识

IMusicService.Stub的实现类(这里是匿名实现类)

private IMusicService.Stub mBinder=new IMusicService.Stub() {
        
        @Override
        public boolean stop() throws RemoteException {
            
            return mMusicPlayer.stop();
        }

        @Override
        public void updateMusicList(List<SongInfo> musicFileList)
                throws RemoteException {
            mMusicPlayer.updateMusicList(musicFileList);
        }
        
        @Override
        public boolean play(int position) throws RemoteException {
            
            return mMusicPlayer.play(position);
        }
        
        @Override
        public boolean pause() throws RemoteException {
            
            return mMusicPlayer.pause();
        }

        @Override
        public void getPlayList(List<SongInfo> musicFileList)
                throws RemoteException {
            List<SongInfo> tmp = mMusicPlayer.getFileList();
            int count = tmp.size();
            for(int i = 0; i < count; i++)
            {
                musicFileList.add(tmp.get(i));
            }
        }
    
    };

ServiceConnection中onServiceConnected参数 IBinder service的来源?

class MServiceConnetion implements ServiceConnection{
        @Override
        public void onServiceConnected(ComponentName name, IBinder service){ 
            mIMusicService=IMusicService.Stub.asInterface(service);
            
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            
        }
        
    }

关于在同一进程绑定Service和跨进程绑定Service后,ServiceConnection返回的IBinder对象和X.Stub.asInterface返回的对象。

    private IPayService mIPayService;

    class PayServiceConn implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mIPayService = IPayService.Stub.asInterface(service);
            mIPayService.toString();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
    public static com.fmtech.aidl_payservice.IPayService asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.fmtech.aidl_payservice.IPayService))) {
            return ((com.fmtech.aidl_payservice.IPayService) iin);
        }
        return new com.fmtech.aidl_payservice.IPayService.Stub.Proxy(obj);
    }

public class PayService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
    }

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

    private void pay(){
        ...
    }

    class PayServiceStub extends IPayService.Stub{
        @Override
        public void callMethodInService() throws RemoteException {
            pay();
        }
    }
}

1.同一进程绑定Service
ServiceConnection#onServiceConnected返回的对象是PayService在onBind中直接返回的PayServiceStub实例;IPayService.Stub.asInterface方法返回的也是PayServiceStub实例。所以,当MainActivity中mIPayService调用callMethodInService时,直接调用的是Payservice中的callMethodInService方法。不需要走其他流程。


onServiceConnected返回的IBinder对象01.png

2.跨进程绑定Service
ServiceConnection#onServiceConnected返回的对象是BinderProxy实例;IPayService.Stub.asInterface方法返回的是IPayService.Stub.Proxy实例。所以,当MainActivity中mIPayService调用callMethodInService时流程如下:
-->IPayService.Stub.Proxy#callMethodInService()-->BinderProxy#transact()

BinderProxy#queryLocalInterface()

    public IInterface queryLocalInterface(String descriptor) {
        return null;
    }

当onServiceConnected返回的对象是BinderProxy时,asInterface()方法中queryLocalInterface()返回的是null,所以asInterface()方法会返回*.Stub.Proxy

        public static com.chiang.chnplayer.aidl.IMusicService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.chiang.chnplayer.aidl.IMusicService))) {
                return ((com.chiang.chnplayer.aidl.IMusicService) iin);
            }
            return new com.chiang.chnplayer.aidl.IMusicService.Stub.Proxy(obj);
        }
    @Override
    public void callMethodInService() throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(IPayService.Stub.TRANSACTION_callMethodInService, _data, _reply, 0);//mRemote即是BinderProxy实例
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }
    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        ...
       return transactNative(code, data, reply, flags);
    }

public native boolean transactNative(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;

BinderProxy.transact后会调用native方法,由native层进行处理;最后,再由native层回调IPayService.Stub.onTransact()方法,进而调用callMethodInService()方法。

onServiceConnected返回的IBinder对象02.png

为什么跨进程绑定Service时,ServiceConnection#onServiceConnected返回的对象是BinderProxy实例?

........

【相关源码】MusicService

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容