AIDL oneway 以及in、out、inout參數的理解


oneway

oneway可以用來修飾在interface之前,這樣會造成interface內所有的方法都隱式地帶上oneway;
oneway也可以修飾在interface里的各個方法之前。
被oneway修飾了的方法不可以有返回值,也不可以有帶out或inout的參數。

帶oneway的實現

帶oneway的方法,不會生成局部變量_reply。且Proxy中transact中第四個參數必為android.os.IBinder.FLAG_ONEWAY

//proxy類
    @Override public void testOneway(int pa) throws android.os.RemoteException
    {
        android.os.Parcel _data = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeInt(pa);
            mRemote.transact(Stub.TRANSACTION_testOneway, _data, null, android.os.IBinder.FLAG_ONEWAY);
        }
        finally {
            _data.recycle();
        }
    }
//stub類
	@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
	{
	    case TRANSACTION_testOneway:
	    {
	        data.enforceInterface(descriptor);
	        int _arg0;
	        _arg0 = data.readInt();
	        this.testOneway(_arg0);
	        return true;
	    }
	}

不帶oneway的實現

不帶oneway的方法,會生成局部變量_reply,但當方法返回值為void時,不會生成局部變量_result,這個才是真正的返回值。且Proxy中transact中第四個參數必為0

//proxy類
	@Override public byte SerTestIn(byte[] pa) throws android.os.RemoteException
	{
	    android.os.Parcel _data = android.os.Parcel.obtain();
	    android.os.Parcel _reply = android.os.Parcel.obtain();
	    byte _result;
	    try {
	        _data.writeInterfaceToken(DESCRIPTOR);
	        _data.writeByteArray(pa);
	        mRemote.transact(Stub.TRANSACTION_SerTestIn, _data, _reply, 0);
	        _reply.readException();
	        _result = _reply.readByte();
	    }
	    finally {
	        _reply.recycle();
	        _data.recycle();
	    }
	    return _result;
	}
//stub類
	case TRANSACTION_SerTestIn:
	{
	    data.enforceInterface(descriptor);
	    byte[] _arg0;
	    _arg0 = data.createByteArray();
	    byte _result = this.SerTestIn(_arg0);
	    reply.writeNoException();
	    reply.writeByte(_result);
	    return true;
	}

in、out、inout參數

為了測試,定義了如下AIDL文件:

package com.java.prac;
import com.java.prac.IListener;

interface IService {
    void registerListener(in IListener listener);
    void unregisterListener(in IListener listener);
    byte SerTestIn(in byte[] pa);
    byte SerTestOut(out byte[] pa);
    byte SerTestInout(inout byte[] pa);
}

為了方便起見,把proxy類稱為調用方,stub類稱為實現方。在跨進程調用中,參數和返回值肯定都是會有復制的過程的,由於系統的設計,將內核空間再映射到用戶空間,這樣復制過程只需要一次。下面代碼都是從自動生成的java代碼抽取而來。

in參數

//proxy類
	@Override public byte SerTestIn(byte[] pa) throws android.os.RemoteException
	{
	    android.os.Parcel _data = android.os.Parcel.obtain();
	    android.os.Parcel _reply = android.os.Parcel.obtain();
	    byte _result;
	    try {
	        _data.writeInterfaceToken(DESCRIPTOR);
	        _data.writeByteArray(pa);
	        mRemote.transact(Stub.TRANSACTION_SerTestIn, _data, _reply, 0);
	        _reply.readException();
	        _result = _reply.readByte();
	    }
	    finally {
	        _reply.recycle();
	        _data.recycle();
	    }
	    return _result;
	}
//stub類
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{   
	...
	case TRANSACTION_SerTestIn:
	{
	    data.enforceInterface(descriptor);
	    byte[] _arg0;
	    _arg0 = data.createByteArray();
	    byte _result = this.SerTestIn(_arg0);
	    reply.writeNoException();
	    reply.writeByte(_result);
	    return true;
	}
	...
}
  • proxy調用了_data.writeByteArray(pa);,說明pa這個參數確實傳遞到了服務方。但stub里只有reply.writeByte(_result);,說明服務方對pa參數的任何改變都不會反應到調用方。

out參數

//proxy類
    @Override public byte SerTestOut(byte[] pa) throws android.os.RemoteException
    {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        byte _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            if ((pa==null)) {
                _data.writeInt(-1);
            }
            else {
                _data.writeInt(pa.length);
            }
            mRemote.transact(Stub.TRANSACTION_SerTestOut, _data, _reply, 0);
            _reply.readException();
            _result = _reply.readByte();
            _reply.readByteArray(pa);
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
//stub類
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{   
	...
    case TRANSACTION_SerTestOut:
    {
        data.enforceInterface(descriptor);
        byte[] _arg0;
        int _arg0_length = data.readInt();
        if ((_arg0_length<0)) {
            _arg0 = null;
        }
        else {
            _arg0 = new byte[_arg0_length];
        }
        byte _result = this.SerTestOut(_arg0);
        reply.writeNoException();
        reply.writeByte(_result);
        reply.writeByteArray(_arg0);
        return true;
    }
	...
}
  • proxy類里面,發現讀取參數的時候,僅僅是_data.writeInt(pa.length);讀取一下數組的長度,而不是讀取數組的內容。
  • stub類里面,發現它居然用之前讀取的數組長度新建了一個數組_arg0 = new byte[_arg0_length];,然后把這個新建的同樣長度的數組傳遞給了真正的方法,難道我們pa參數這個數組的內容都不重要嗎,僅僅是為了告訴對方數組的長度嗎?(你眉頭一皺發現事情並不簡單==)事實上,就是這么簡單,pa數組的長度才是有用信息。
  • stub類里面,開始設置返回值時,發現多了一步reply.writeByteArray(_arg0);,其實是服務方對新建的數組賦值了,然后要作為返回值返回。
  • proxy類里面,既然服務方要返回調用方一個數組,那就接受吧,_reply.readByteArray(pa);,然后把pa進行賦值。

inout參數

//proxy類
    @Override public byte SerTestInout(byte[] pa) throws android.os.RemoteException
    {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        byte _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _data.writeByteArray(pa);
            mRemote.transact(Stub.TRANSACTION_SerTestInout, _data, _reply, 0);
            _reply.readException();
            _result = _reply.readByte();
            _reply.readByteArray(pa);
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
//stub類
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{   
	...
    case TRANSACTION_SerTestInout:
    {
        data.enforceInterface(descriptor);
        byte[] _arg0;
        _arg0 = data.createByteArray();
        byte _result = this.SerTestInout(_arg0);
        reply.writeNoException();
        reply.writeByte(_result);
        reply.writeByteArray(_arg0);
        return true;
    }
	...
}
  • 分析和上面類似了。
  • 服務方會完好無損地收到調用方發來的pa數組。
  • 調用方可能會對pa數組進行修改,然后再返回給調用方。

總結

  • in參數使得實參順利傳到服務方,但服務方對實參的任何改變,不會反應回調用方。
  • out參數使得實參不會真正傳到服務方,只是傳一個實參的初始值過去(這里實參只是作為返回值來使用的,這樣除了return那里的返回值,還可以返回另外的東西),但服務方對實參的任何改變,在調用結束后會反應回調用方。
  • inout參數則是上面二者的結合,實參會順利傳到服務方,且服務方對實參的任何改變,在調用結束后會反應回調用方。
  • 其實inout,都是相對於服務方。in參數使得實參傳到了服務方,所以是in進入了服務方;out參數使得實參在調用結束后從服務方傳回給調用方,所以是out從服務方出來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM