Android深入源代码分析理解Aidl总体调用流程(雷惊风)
? ? ? ? 2017年開(kāi)始上班的第一天。老不想工作了,假期感覺(jué)還沒(méi)開(kāi)始就已經(jīng)結(jié)束了,唉,時(shí)間就是這樣,新的一年開(kāi)始了,盡管非常不想干正事,沒(méi)辦法,必須干起來(lái)。由于后邊的路還非常長(zhǎng),距離六十歲還非常遠(yuǎn)。
剛上班也沒(méi)什么事,復(fù)習(xí)一下之前的東西,看了一下Aidl相關(guān)的知識(shí)。細(xì)致瞅了瞅Aidl的調(diào)用流程,這里寫(xiě)篇文章整理一下。幫助大家的同一時(shí)候。自己也加深一下印象。對(duì)Aidl不太了解的童鞋能夠先看一下我之前的一篇文章,
鏈接例如以下:http://blog.csdn.net/liuyonglei1314/article/details/54317902?
案例下載鏈接:http://download.csdn.net/detail/liuyonglei1314/9734165?。
? ?在上篇文章中我們已經(jīng)說(shuō)過(guò)了Android中Aidl的簡(jiǎn)單應(yīng)用及對(duì)象的傳遞方式,還包括了在AS中進(jìn)行Aidl開(kāi)發(fā)會(huì)遇到的一些問(wèn)題及決解方法,本篇文章針對(duì)用法我們不在多說(shuō)。我們將以傳遞對(duì)象為例深入的剖析Aidl的具體調(diào)用流程,繼續(xù)以上文中傳遞Person對(duì)象為例展開(kāi),通過(guò)本片文章的學(xué)習(xí)你會(huì)學(xué)到下面相關(guān)知識(shí):1.Aidl工作調(diào)用流程;2.Aidl傳遞對(duì)象時(shí)修飾符in、out、inout的深入理解。3.對(duì)實(shí)現(xiàn)Parcelable接口對(duì)象中須要實(shí)現(xiàn)方法的深入理解。
? ?首先看一下我們要傳遞對(duì)象的代碼:
public class Person implements Parcelable {private String name;private int age;public Person() {}protected Person(Parcel in) {name = in.readString();age = in.readInt();}public static final Creator<Person> CREATOR = new Creator<Person>() {@Overridepublic Person createFromParcel(Parcel in) {return new Person(in);}@Overridepublic Person[] newArray(int size) {return new Person[size];}};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;}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);dest.writeInt(age);}public void readFromParcel(Parcel dest) {name = dest.readString();age = dest.readInt();}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';} }Person類(lèi)實(shí)現(xiàn)了parcelable接口。有兩個(gè)構(gòu)造方法,有name、age兩個(gè)成員變量。編譯器能夠幫我們生成一個(gè)static、final的CREATOR跟writeToParcel()方法,我們自己寫(xiě)readFromParcel()方法,這里切記順序要與writeToParcel()方法一直。
下邊再看一下我們的.aidl文件代碼:
import com.jason.aidl.aidldemo.Person; interface IMyAidlInterface {String inPerson(in Person p);String outPerson(out Person p);String inOutPerson(inout Person p); }這里須要注意我們的Person也須要寫(xiě)相應(yīng)的Person.aidl文件,并在build.gradle中配置。具體信息就不介紹了。上篇文章中進(jìn)行了具體解說(shuō)。在這里看到了修飾符in、out、inout。后文會(huì)做具體解說(shuō)。
我們繼續(xù)看Aidl文件生成相應(yīng)的.java文件的一個(gè)總體架構(gòu)。縮略代碼例如以下:
public interface IMyAidlInterface extends android.os.IInterface {/*** Local-side IPC implementation stub class.*/public static abstract class Stub extends android.os.Binder implements com.jason.aidl.aidldemo.IMyAidlInterface {private static final java.lang.String DESCRIPTOR = "com.jason.aidl.aidldemo.IMyAidlInterface";/*** Construct the stub at attach it to the interface.*/public Stub() {this.attachInterface(this, DESCRIPTOR);}/*** Cast an IBinder object into an com.jason.aidl.aidldemo.IMyAidlInterface interface,* generating a proxy if needed.*/public static com.jason.aidl.aidldemo.IMyAidlInterface asInterface(android.os.IBinder obj) { //...}@Overridepublic android.os.IBinder asBinder() {return this;}@Overridepublic boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { //...return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.jason.aidl.aidldemo.IMyAidlInterface {private android.os.IBinder mRemote;Proxy(android.os.IBinder remote) {mRemote = remote;}@Overridepublic android.os.IBinder asBinder() {return mRemote;}public java.lang.String getInterfaceDescriptor() {return DESCRIPTOR;}@Overridepublic java.lang.String inPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException {//... return _result;}@Overridepublic java.lang.String outPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException {//...return _result;}@Overridepublic java.lang.String inOutPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException {//...return _result;}}static final int TRANSACTION_inPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_outPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);static final int TRANSACTION_inOutPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);}public java.lang.String inPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException;public java.lang.String outPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException;public java.lang.String inOutPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException; }
大致分為三部分。一個(gè)interface(最外層的類(lèi))兩個(gè)內(nèi)部類(lèi)(Stub、Proxy)。先看interface。它跟我們定義的.aidl文件名稱(chēng)字同樣,繼承了IInterface,它的內(nèi)容分為兩部分:一個(gè)內(nèi)部類(lèi)Stub及我們定義的Person抽象操作方法。每個(gè)都拋出RemoteException。接下來(lái)看他的內(nèi)部類(lèi)Stub,它是一個(gè)抽象類(lèi)。繼承了Binder類(lèi),實(shí)現(xiàn)了外層的Interface,他比較重要的是一個(gè)asInterface()方法和onTransact()方法。它另一個(gè)static的內(nèi)部類(lèi)Proxy。它也實(shí)現(xiàn)了最外層的Interface,另外有一個(gè)須要傳遞Ibinder的構(gòu)造函數(shù),還有就是與我們?cè)?/span>Aidl類(lèi)中定義的方法名稱(chēng)同樣的方法。這就是我們生成的.java文件的一個(gè)大致的架構(gòu)。
由上邊可知最外層Interface是IInterface的子類(lèi),而Stub與Proxy是最外層Interface的實(shí)現(xiàn)類(lèi)。Stub繼承了Binder,他們之間存在這種關(guān)系。以下我們就對(duì)代碼的調(diào)用流程進(jìn)行具體解說(shuō)。
? ?首先我們?cè)趹?yīng)用Aidl時(shí)通過(guò)client綁定的方式來(lái)獲取我們的IMyAidlInterface,并通過(guò)它來(lái)調(diào)用服務(wù)端的方法進(jìn)行通信,例如以下代碼:
private IMyAidlInterface mService;Intent intent = new Intent(); intent.setAction("com.lyl.aidl"); Intent intent1 = new Intent(createExplicitFromImplicitIntent(this, intent));//兼容5.0以后版本號(hào) bindService(intent1, mServiceC, Context.BIND_AUTO_CREATE);ServiceConnection mServiceC = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mService = IMyAidlInterface.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {} }; public void do(View v) {try {Person p1 = new Person();p1.setName("劉大");p1.setAge(3);Person p2 = new Person();p2.setName("趙二");p2.setAge(3);Person p3 = new Person();p3.setName("張三");p3.setAge(3);tv.setText("" + mService.inPerson(p1) + "\n" + mService.outPerson(p2) + "\n" + mService.inOutPerson(p3));} catch (RemoteException e) {e.printStackTrace();} }上邊代碼通過(guò)IMyAidlInterface.Stub.asInterface(service)獲取了我們的IMyAidlInterface,do()方法中通過(guò)它才調(diào)用了我們服務(wù)端的代碼,那我們先看一下這個(gè)asInterface方法中的參數(shù)是什么,我們知道當(dāng)通過(guò)綁定的方式獲取的binder是我們?cè)诜?wù)中的onBind()方法中返回的,看一下我們服務(wù)端的代碼:
public class MyAidlService extends Service {@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i("Log_LYL", "Onstart");return super.onStartCommand(intent, flags, startId);}@Overridepublic IBinder onBind(Intent intent) {return stub;}IMyAidlInterface.Stub stub = new IMyAidlInterface.Stub() {@Overridepublic String inPerson(Person p) throws RemoteException {... }@Overridepublic String outPerson(Person p) throws RemoteException {...}@Overridepublic String inOutPerson(Person p) throws RemoteException {...}}; }通過(guò)以上服務(wù)端代碼能夠知道我們返回的是一個(gè)stub 事例。而它是我們的.aidl文件自己主動(dòng)生成的.java文件里Stub的一個(gè)實(shí)例對(duì)象。如今我們知道IMyAidlInterface.Stub.asInterface(service)中的service是編譯器為我們生成的.java文件的一個(gè)實(shí)例。我們接著看IMyAidlInterface中Stub.asInterface(service)方法,代碼例如以下:
public static com.jason.aidl.aidldemo.IMyAidlInterface asInterface(android.os.IBinder obj) {if ((obj == null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin != null) && (iin instanceof com.jason.aidl.aidldemo.IMyAidlInterface))) {return ((com.jason.aidl.aidldemo.IMyAidlInterface) iin);}return new com.jason.aidl.aidldemo.IMyAidlInterface.Stub.Proxy(obj); }由于我們的Stub類(lèi)繼承了Binder。Binder實(shí)現(xiàn)了Ibinder接口,所以傳遞Stub的實(shí)例在這里沒(méi)問(wèn)題。上述代碼首先推斷了obj是否為空,不為空往下走,第二個(gè)if推斷是在推斷通過(guò)obj獲取的iin是否屬于當(dāng)前程序執(zhí)行的進(jìn)程。假設(shè)是,直接返回,這里也就是說(shuō)我們要調(diào)用的服務(wù)與我們當(dāng)前程序在同一進(jìn)程。不須要遠(yuǎn)程通信,直接調(diào)用即可。假設(shè)不是能夠看見(jiàn)系統(tǒng)新生成了一個(gè)Proxy對(duì)象實(shí)例,并把我們的stub實(shí)例對(duì)象傳遞進(jìn)去。看一下Proxy的構(gòu)造函數(shù),代碼例如以下:
private android.os.IBinder mRemote;Proxy(android.os.IBinder remote) {mRemote = remote; }能夠看到通過(guò)構(gòu)造函數(shù)將Stub實(shí)例重新傳到了Proxy中并賦值給mRemote,mRemote也變成了Stub實(shí)例。
? ?到這里綁定服務(wù)獲取ImyAidlInterface對(duì)象就介紹完了,做一下總結(jié):通過(guò)綁定的方式獲取到了在服務(wù)端的系統(tǒng)生成的.aidl文件相應(yīng)的.java文件里子類(lèi)Stub的一個(gè)實(shí)例,調(diào)用Stub類(lèi)中的asInterface()方法推斷Stub實(shí)例所在進(jìn)程與當(dāng)前進(jìn)程是否為同一個(gè)。是直接能夠操作。不是生成一個(gè)Proxy實(shí)例并將Stub傳入。
? ?以下我們看一下調(diào)用代碼實(shí)現(xiàn):
public void do(View v) {try {Person p1 = new Person();p1.setName("劉大");p1.setAge(3);Person p2 = new Person();p2.setName("趙二");p2.setAge(3);Person p3 = new Person();p3.setName("張三");p3.setAge(3);tv.setText("" + mService.inPerson(p1) + "\n" + mService.outPerson(p2) + "\n" + mService.inOutPerson(p3));} catch (RemoteException e) {e.printStackTrace();} }我們首先分析第一個(gè)inPerson(p1);這種方法我們?cè)诙x時(shí)的修飾符為in,及String inPerson(in Person p);下邊我們看一下它的實(shí)現(xiàn)過(guò)程,通過(guò)上邊的介紹能夠知道mService假設(shè)不是在同一個(gè)進(jìn)程中是返回的Proxy對(duì)象實(shí)例,那么我們就進(jìn)入Proxy中查找相應(yīng)的方法,代碼例如以下:
@Override public java.lang.String inPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);if ((p != null)) {_data.writeInt(1);p.writeToParcel(_data, 0);} else {_data.writeInt(0);}mRemote.transact(Stub.TRANSACTION_inPerson, _data, _reply, 0);_reply.readException();_result = _reply.readString();} finally {_reply.recycle();_data.recycle();}return _result; }能夠看到系統(tǒng)生成了_data、_reply兩個(gè)Parcel類(lèi)型的對(duì)象,然后操作_data。寫(xiě)入Token,推斷假設(shè)傳入的Person對(duì)象不為空寫(xiě)入了一個(gè)1,接下來(lái)調(diào)用了person類(lèi)的writeToParcel()方法,傳入了_data,咦,注意這里。我們就知道了實(shí)現(xiàn)Parcelable接口時(shí)的writeToParcel()方法在這里會(huì)用到。好的,我們跟進(jìn)看一下,代碼例如以下:
@Override public void writeToParcel(Parcel dest, int flags) {dest.writeString(name);dest.writeInt(age); }這一步看來(lái)就是給_data賦值,將我們從開(kāi)始調(diào)用inPerson(com.jason.aidl.aidldemo.Person p)??p實(shí)例中的值以writeString、writeInt的方式保存到_data中,假設(shè)傳入的p為null則寫(xiě)入一個(gè)0。繼續(xù)往下走。我標(biāo)紅的那句是重點(diǎn),也是這句進(jìn)行了binder通信,關(guān)于binder通訊機(jī)制有非常多非常多東西。因?yàn)楸救四芰τ邢拊谶@里就不多講了,感興趣的能夠去了解一下。通過(guò)前邊能夠知道m(xù)Remote為asInterface方法傳入的service,及Stub實(shí)例,而Stub中根本沒(méi)有transact()方法,而它是Binder的子類(lèi),好,我們?nèi)inder中找,還真有:
public final boolean transact(int code, Parcel data, Parcel reply,int flags) throws RemoteException {if (false) Log.v("Binder", "Transact: " + code + " to " + this);if (data != null) {data.setDataPosition(0);}boolean r = onTransact(code, data, reply, flags);if (reply != null) {reply.setDataPosition(0);}return r; }能夠看到。在這里調(diào)用了onTransact(code, data, reply, flags);我們知道在Stub類(lèi)中我們實(shí)現(xiàn)了這種方法,我們看一下Stub類(lèi)中的這種方法:
@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_inPerson: {data.enforceInterface(DESCRIPTOR);com.jason.aidl.aidldemo.Person _arg0;if ((0 != data.readInt())) {_arg0 = com.jason.aidl.aidldemo.Person.CREATOR.createFromParcel(data);} else {_arg0 = null;}java.lang.String _result = this.inPerson(_arg0);reply.writeNoException();reply.writeString(_result);return true;}}return super.onTransact(code, data, reply, flags); }在這里我們僅僅摘取了inPerson()方法相關(guān)內(nèi)容。先了解一下傳入的四個(gè)參數(shù):1.code 每個(gè)方法相應(yīng)一個(gè)code,我們定義了多少方法就會(huì)有多少code,通過(guò)它來(lái)做不同處理;2.data、reply為在proxy相應(yīng)方法中生成的兩個(gè)Parcel對(duì)象。3.flags 一般為1。這個(gè)不用管先。 首先通過(guò)code找到相應(yīng)方法的操作,推斷data中寫(xiě)入的int值是否為0,不為0說(shuō)明之前的p不為null。而且已經(jīng)存入到data中。調(diào)用Person中的CREATOR的createFromParcel()方法,咦。這里又用到了Parcelable的東西。看一下這種方法:
public static final Creator<Person> CREATOR = new Creator<Person>() {@Overridepublic Person createFromParcel(Parcel in) {return new Person(in);}@Overridepublic Person[] newArray(int size) {return new Person[size];} }; protected Person(Parcel in) {name = in.readString();age = in.readInt(); }能夠看到,系統(tǒng)在這里創(chuàng)建了一個(gè)Person實(shí)例。傳入了我們之前的data(保存有person信息),并將data中的信息賦值給新的person對(duì)象。
回到Stub類(lèi)的onTransace()方法中繼續(xù)往下看:
java.lang.String _result = this.inPerson(_arg0); reply.writeNoException(); reply.writeString(_result); return true;
接著系統(tǒng)調(diào)用了this.inPerson(_arg0)方法。_arg0為上邊通過(guò)createFromParcel()方法新生成的person(包括傳遞過(guò)來(lái)的person值)對(duì)象,我們知道Stub為抽象類(lèi)。他實(shí)現(xiàn)了我們外層的Interface類(lèi)。可是沒(méi)有實(shí)現(xiàn)inPerson()方法。那么我們就須要它的子類(lèi)實(shí)現(xiàn),而我們的mRemote.transace()中的mRemote就是服務(wù)端返回的Stub的一個(gè)實(shí)現(xiàn)子類(lèi),也就是說(shuō)這里調(diào)用的this.inPerson(_arg0)方法實(shí)際是調(diào)用了服務(wù)端的那個(gè)Stub實(shí)現(xiàn)類(lèi)里邊的inPerson()方法,看一下我們之前服務(wù)端的inPerson()方法的詳細(xì)實(shí)現(xiàn):
@Override public String inPerson(Person p) throws RemoteException {String old = "name:" + p.getName() + " age:" + p.getAge();Log.d("Log_LYL:iPerson_", old);p.setName("李四");p.setAge(13);return "name:" + p.getName() + " age:" + p.getAge(); }通過(guò)以上分析,大家就知道了這里的?Log.d("Log_LYL:iPerson_", old);?是為什么有值了,由于我們一開(kāi)始就將傳入的person值附到了Parcel類(lèi)型的data中了,然后又通過(guò)createFromParcel()方法將data中的值付給了新的person對(duì)象。
然后回到Stub類(lèi)的onTransace()方法,會(huì)看到調(diào)用了reply.writeNoException();reply.writeString(_result);兩個(gè)方法,將服務(wù)端處理完后返回的信息寫(xiě)入了reply中。最后return。
再回到Proxy類(lèi)中的inPerson()方法中:
mRemote.transact(Stub.TRANSACTION_inPerson, _data, _reply, 0);_reply.readException();_result = _reply.readString(); } finally {_reply.recycle();_data.recycle(); } return _result;將服務(wù)端返回的信息讀出來(lái)并付給_result。最后返回,這樣我們?cè)赼ctivity中就能夠得到服務(wù)端處理后的結(jié)果了。到如今為止。我們就應(yīng)該明確了,通過(guò)in修飾符傳遞person后服務(wù)端生成了新的person對(duì)象。并對(duì)新person對(duì)象進(jìn)行處理,這種話不管服務(wù)端怎樣改動(dòng)person對(duì)象我們client的person對(duì)象是不會(huì)受不論什么影響的,為什么,由于不是一個(gè)對(duì)象。這就是in操作符。
以下我們分析一下out操作符,直接看代碼:
String outPerson(out Person p);//.aidl文件里定義; mService.outPerson(p2)//client調(diào)用;我們?cè)赾lient直接通過(guò)綁定時(shí)返回的Stub實(shí)例調(diào)用outPerson()方法。通過(guò)上邊對(duì)inPerson()方法的介紹我們知道不是同一個(gè)進(jìn)程中的會(huì)終于調(diào)用到Proxy中對(duì)應(yīng)的方法中,那我們直接看Proxy中代碼:
@Override public java.lang.String outPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_outPerson, _data, _reply, 0);_reply.readException();_result = _reply.readString();if ((0 != _reply.readInt())) {p.readFromParcel(_reply);}} finally {_reply.recycle();_data.recycle();}return _result; }有了上邊對(duì)inPerson()方法的了解這個(gè)相對(duì)就簡(jiǎn)單多了,相同生成兩個(gè)Parcel對(duì)象。作用相同,不同的是用out修飾后沒(méi)有對(duì)傳入的p做null推斷,也沒(méi)有取值保存到data中。而是直接調(diào)用了mRemote.transact(Stub.TRANSACTION_outPerson, _data, _reply, 0)方法,那好,通過(guò)前邊我們直接去Stub中找onTransact()方法吧:
case TRANSACTION_outPerson: {data.enforceInterface(DESCRIPTOR);com.jason.aidl.aidldemo.Person _arg0;_arg0 = new com.jason.aidl.aidldemo.Person();java.lang.String _result = this.outPerson(_arg0);reply.writeNoException();reply.writeString(_result);if ((_arg0 != null)) {reply.writeInt(1);_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);} else {reply.writeInt(0);}return true; }我們僅僅要out方法相關(guān)信息,這里系統(tǒng)通過(guò)new Person()的方式創(chuàng)建了一個(gè)person對(duì)象實(shí)例賦值個(gè)_arg0,這個(gè)對(duì)象與我們調(diào)用時(shí)傳進(jìn)來(lái)的對(duì)象沒(méi)有一點(diǎn)關(guān)系,然后直接調(diào)用了this.outPerson()方法,通過(guò)inPerson()的介紹我們就知道這里直接調(diào)用了服務(wù)端outPerson()實(shí)現(xiàn):
@Override public String outPerson(Person p) throws RemoteException {//這里的p是空的,由于在IMyAidlInterface的Stub類(lèi)中onTransact()方法中沒(méi)有寫(xiě)入;// _arg0 = new com.jason.aidl.aidldemo.Person();//java.lang.String _result = this.outPerson(_arg0);String old = "name:" + p.getName() + " age:" + p.getAge();Log.d("Log_LYL:outPerson_", old);p.setName("周六");p.setAge(20);return "name:" + p.getName() + " age:" + p.getAge(); }這里能夠知道old是沒(méi)有賦值的,以下賦值return,回到Stub中:
java.lang.String _result = this.outPerson(_arg0); reply.writeNoException(); reply.writeString(_result); if ((_arg0 != null)) {reply.writeInt(1);_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else {reply.writeInt(0); } return true;
將處理結(jié)果寫(xiě)入reply中。推斷_arg0是否為null,不是,寫(xiě)入1,這里重新用到了writeToParcel()方法,通過(guò)上邊inPerson()方法介紹可知這里是將_arg0的值付給reply。假設(shè)為null,reply中賦值0。回到Proxy中:
try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_outPerson, _data, _reply, 0);_reply.readException();_result = _reply.readString();if ((0 != _reply.readInt())) {p.readFromParcel(_reply);} } finally {_reply.recycle();_data.recycle(); } return _result;運(yùn)行完transact()方法后從_reply中讀出服務(wù)端操作返回結(jié)果,推斷寫(xiě)入的int值,假設(shè)不為0,說(shuō)明_reply中寫(xiě)入了服務(wù)端產(chǎn)生的person信息,則將通過(guò)readFromParcel()方法將新的_reply中保存的服務(wù)端的person信息寫(xiě)入到client傳入的p中,這樣client就收到了服務(wù)端的person信息。
總結(jié)一下out修飾符。即使我們?cè)诜?wù)端將p的值寫(xiě)好。服務(wù)端也不會(huì)接收我們的client信息。能夠說(shuō)服務(wù)端根本不關(guān)系client傳入的信息,服務(wù)端通過(guò)new Person()方式產(chǎn)生新對(duì)象,并返回給client,client的p通過(guò)readFromParcel()方法獲得服務(wù)端值,并沒(méi)有做對(duì)象的交換。
下邊看一下inout修飾符代碼:
相同看一下Proxy中對(duì)應(yīng)方法:
@Override public java.lang.String inOutPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);if ((p != null)) {_data.writeInt(1);p.writeToParcel(_data, 0);} else {_data.writeInt(0);}mRemote.transact(Stub.TRANSACTION_inOutPerson, _data, _reply, 0);_reply.readException();_result = _reply.readString();if ((0 != _reply.readInt())) {p.readFromParcel(_reply);}} finally {_reply.recycle();_data.recycle();}return _result; }case TRANSACTION_inOutPerson: {data.enforceInterface(DESCRIPTOR);com.jason.aidl.aidldemo.Person _arg0;if ((0 != data.readInt())) {_arg0 = com.jason.aidl.aidldemo.Person.CREATOR.createFromParcel(data);} else {_arg0 = null;}java.lang.String _result = this.inOutPerson(_arg0);reply.writeNoException();reply.writeString(_result);if ((_arg0 != null)) {reply.writeInt(1);_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);} else {reply.writeInt(0);}return true; }
能夠看到在inout修飾符時(shí)推斷了傳入的p對(duì)象,也就是說(shuō)服務(wù)端接收了保存了client的p對(duì)象,操作類(lèi)似與in修飾符,也是通過(guò)Person.CREATOR.createFromParcel(data)創(chuàng)建新對(duì)象,在Proxy中相同推斷了_reply中寫(xiě)入的int值,也就是說(shuō),client也能收到服務(wù)端對(duì)對(duì)象的改動(dòng),也就是說(shuō)。inout操作符是int、out操作符的合體。到這里相信大家已經(jīng)明確in、out、inout操作符的差別了。而且連實(shí)現(xiàn)都明確了。
? ?到如今今天要跟大家分享的東西就寫(xiě)完了,相信您看完這篇文章會(huì)對(duì)Android中的Aidl有一個(gè)新的了解。對(duì)in、out、inout修飾也明確了,對(duì)實(shí)現(xiàn)Parcelable接口有了新的認(rèn)識(shí),假設(shè)是這樣,那我這篇文章就沒(méi)白寫(xiě)。謝謝大家。
轉(zhuǎn)載于:https://www.cnblogs.com/blfbuaa/p/7400678.html
總結(jié)
以上是生活随笔為你收集整理的Android深入源代码分析理解Aidl总体调用流程(雷惊风)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何查看、备份电脑隐藏的恢复分区
- 下一篇: tableview的顶部有一部分空白区域