Android點將臺:金科玉律[-AIDL-]

我的全部文章整理在此篇,將陸續更新收錄:知無涯,行者之路莫言終(個人編程之路)java

零、前言

本文接Android點將臺:絕命暗殺官[-Service-]篇,本文圖例見
本文經過AIDL實現了跨進程間調用Service(即App2調用App1的Service)
本篇未來探索一下AIDL自動生成的類,再從新審視一下ActivityManagerServiceandroid


1、上一篇中AIDL自動生成的IMusicPlayerService分析

1.IMusicPlayerService的類結構

太多了,有點晃眼,打開結構圖來分析一下編程

類結構.png


IMusicPlayerService.png


2.從IInterface開始

IMusicPlayerService是一個接口,而且繼承於IInterface接口,那IInterface是何許人也?
就這兩行代碼,只有一個asBinder方法,返回一個IBinder對象,注意它在的包是android.osbash

package android.os;
public interface IInterface{
    public IBinder asBinder();
}
複製代碼

3.IMusicPlayerService的分析

可見除去Stub,IMusicPlayerService裏只是咱們在IMusicPlayerService.aidl定義的接口
也沒有什麼太多要說明的地方,咱們的終極目標是看一下它的實現類是什麼app

/*
 * This file is auto-generated.  DO NOT MODIFY.
    自動生成的,不要修改
 * Original file: J:\\Java\\Android\\LeverUp\\TolyService\\app\\src\\main\\aidl\\com\\toly1994\\tolyservice\\IMusicPlayerService.aidl
 原始文件在: J:\\Java\\Android\\LeverUp\\TolyService\\app\\src\\main\\aidl\\com\\toly1994\\tolyservice\\IMusicPlayerService.aidl
 */
package com.toly1994.tolyservice;
// Declare any non-default types here with import statements
//在這裏使用import語句聲明任何非默認類型

public interface IMusicPlayerService extends android.os.IInterface {
    //Stub類,暫略...
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
      說明一些在AIDL中能夠用做參數和返回值的基本類型。
     */
    public void stop() throws android.os.RemoteException;
    public void pause() throws android.os.RemoteException;
    public void start() throws android.os.RemoteException;
    public void prev() throws android.os.RemoteException;
    public void next() throws android.os.RemoteException;
    public void release() throws android.os.RemoteException;
    public boolean isPlaying() throws android.os.RemoteException;
    public void seek(int pre_100) throws android.os.RemoteException;
    public void create(java.util.List<java.lang.String> filePaths) throws android.os.RemoteException;
}
複製代碼

4.而後固然是深刻一下,到Stub

英語Stub有存根的意思,看完本篇以後本身意會一下它的含義
它不只繼承Binder,並且實現了IMusicPlayerService,看起來挺牛的,惋惜是個抽象類
它實現了Binder的一些東西,但並無IMusicPlayerService的任何方法,就是掛個頭而已
實現從成員變量來看,每一個方法都對應了一個int常量,從switch來看應該是方法的標識
DESCRIPTOR對應了一個包名.IMusicPlayerService字符串,用於attachInterfaceide

Stub分析.png

public static abstract class Stub extends android.os.Binder implements com.toly1994.tolyservice.IMusicPlayerService {
     private static final java.lang.String DESCRIPTOR = "com.toly1994.tolyservice.IMusicPlayerService";

     /**
      * Construct the stub at attach it to the interface.
        在將關聯到接口時構造stub。----注意使用了DESCRIPTOR字符串
      */
     public Stub() {
         this.attachInterface(this, DESCRIPTOR);
     }

     /**
      * Cast an IBinder object into an com.toly1994.tolyservice.IMusicPlayerService interface,
      * generating a proxy if needed.
      */
     public static com.toly1994.tolyservice.IMusicPlayerService asInterface(android.os.IBinder obj) {
         if ((obj == null)) {
             return null;
         }
         android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
         if (((iin != null) && (iin instanceof com.toly1994.tolyservice.IMusicPlayerService))) {
             return ((com.toly1994.tolyservice.IMusicPlayerService) iin);
         }
         return new com.toly1994.tolyservice.IMusicPlayerService.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_stop: {//暫略...
                 return true;
             }
             case TRANSACTION_pause: {//暫略...
                 return true;
             }
             case TRANSACTION_start: {//暫略...
                 return true;
             }
             case TRANSACTION_prev: {//暫略...
                 return true;
             }
             case TRANSACTION_next: {//暫略...
                 return true;
             }
             case TRANSACTION_release: {//暫略...
                 return true;
             }
             case TRANSACTION_isPlaying: {//暫略...
                 return true;
             }
             case TRANSACTION_seek: {//暫略...
                 return true;
             }
             case TRANSACTION_create: {//暫略...
                 return true;
             }
             default: {
                 return super.onTransact(code, data, reply, flags);
             }
         }
     }
     
     //Proxy類,暫略...
     static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
     static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
     static final int TRANSACTION_start = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
     static final int TRANSACTION_prev = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
     static final int TRANSACTION_next = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
     static final int TRANSACTION_release = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
     static final int TRANSACTION_isPlaying = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
     static final int TRANSACTION_seek = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
     static final int TRANSACTION_create = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
 }
複製代碼

5.如今看最後一層奶油夾心:Proxy

如今把聚光燈打到Stub的內部類Proxy上,Proxy是個敲代碼的都知道是代理的意思
既然是代理,它代理什麼?成員變量有個IBinder mRemote,構造方法要傳一個IBinder,so...
它實現了IMusicPlayerService,而且有所動做,並且動做基本一致函數

Proxy.png

private static class Proxy implements com.toly1994.tolyservice.IMusicPlayerService {
    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 void stop() 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_stop, _data, _reply, 0);
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }

    @Override
    public void pause() throws android.os.RemoteException {//暫略...
    }

    @Override
    public void start() throws android.os.RemoteException {//暫略...
    }

    @Override
    public void prev() throws android.os.RemoteException {//暫略...
    }

    @Override
    public void next() throws android.os.RemoteException {//暫略...
    }

    @Override
    public void release() throws android.os.RemoteException {//暫略...
    }

    @Override
    public boolean isPlaying() throws android.os.RemoteException {//暫略...
    }

    @Override
    public void seek(int pre_100) throws android.os.RemoteException {//暫略...
    }

    @Override
    public void create(java.util.List<java.lang.String> filePaths) throws android.os.RemoteException {//暫略...
    }
}
複製代碼

到如今爲止,它們幾個的關係理清了,下面就來詳細看看哪些//暫略...的方法post


2、Binder和IBinder的個別方法

這裏先列舉出上面使用到的方法ui

binder與Ibinder.png


1.目前IBinder檯面上出現的方法
public interface 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.
     嘗試檢索此綁定器對象的本地接口實現。
     若是返回null,則須要經過transact()方法實例化一個代理類來調用。
     */
    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}.
    code 操做的行爲碼  0x00000001 ~ 0x00ffffff 之間 1~16777215
     * @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.
    data 發送到目標的編組數據。不能爲空。若是您沒有發送任何數據,則必須建立這裏給出的空包。
     * @param reply Marshalled data to be received from the target.  May be null if you are not interested in the return value.
     從目標接收到的編組數據。若是您對返回值不感興趣,則可能爲null。
     * @param flags Additional operation flags.  Either 0 for a normal RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
   flags  額外的操做標誌,對於普通RPC爲0,對於單向RPC爲1{@link #FLAG_ONEWAY}。
    
     * @return Returns the result from {@link Binder#onTransact}. A successful call generally returns true; false generally means the transaction code was not understood.
   return  從Binder.onTransact()返回結果。成功調用一般返回true;false一般表示事務代碼未被理解。
     */
    public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
        throws RemoteException;
    //其餘...略
}
複製代碼

2.目前Binder檯面上出現的方法
---->[Binder]-------------
private IInterface mOwner;
private String mDescriptor;

---->[Binder#attachInterface]-------------
 Convenience method for associating a specific interface with the Binder. 
 After calling, queryLocalInterface() will be implemented for you to return
 the given owner IInterface when the corresponding descriptor is requested.
|--譯:一個將特定接口與Binder關聯的方便方法。調用後,將爲你實現queryLocalInterface(),
|--以便在請求相應的描述符時返回owner (IInterface對象)。
public void attachInterface(@Nullable IInterface owner, @Nullable Stringdescriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}

---->[Binder#queryLocalInterface]-------------
 Use information supplied to attachInterface() to return the associated 
 IInterface if it matches the requested descriptor.
 若是提供的描述符,與經過attachInterface()方法進行關聯的IInterface一致
 返回該IInterface,不然返回null
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
    if (mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

---->[Binder#onTransact]-------------
 * Default implementation is a stub that returns false.  You will want
 * to override this to do the appropriate unmarshalling of transactions.
 * 默認實現是stub返回false。您會想要覆謝它,以便對事務進行適當的反編組。
 * <p>If you want to call this, call transact().
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel
reply,int flags) throws RemoteException {
複製代碼

3.再來看剛纔暫略的方法
3.1:attachInterface

此方法在Stub的構造函數中調用,爲成員變量mOwnermDescriptor賦值this

attachInterface.png

---->[IMusicPlayerService.Stub#Stub]-------------
public Stub() {
    this.attachInterface(this, DESCRIPTOR);
}
|---這裏調用了attachInterface方法,參數是本身和描述符

---->[Binder]-------------
private IInterface mOwner;
private String mDescriptor;

---->[Binder#attachInterface]-------------
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}
複製代碼

3.2:asInterface

傳入一個IBinder對象obj,調用obj的queryLocalInterface方法生成IInterface對象
再進行強轉,若是強轉不成功,纔會建立Proxy代理對象

asInterface.png

---->[IMusicPlayerService.Stub#asInterface]-------------
public static com.toly1994.tolyservice.IMusicPlayerService asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.toly1994.tolyservice.IMusicPlayerService))) {
        return ((com.toly1994.tolyservice.IMusicPlayerService) iin);
    }
    return new com.toly1994.tolyservice.IMusicPlayerService.Stub.Proxy(obj);
}
複製代碼

3.3: asBinder

asBinder是IInterface接口的方法,把本身(Stub繼承自Binder)返回去,沒什麼好說的

---->[IMusicPlayerService.Stub#asInterface]-------------
@Override
public android.os.IBinder asBinder() {
    return this;
}
複製代碼

3.4: onTransact

此方法運行在服務端Binder線程池中,客戶端發起跨進程請求時,遠程請求經過系統底層封裝後交由此方法處理。
處理的邏輯基本上都同樣,經過判斷code來調用方法,這裏看兩個startseek,

onTransact.png

@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 TRANSACTION_start: {
            data.enforceInterface(descriptor);//執行接口
            this.start();//調用start方法
            reply.writeNoException();//將計算結果寫入reply中
            return true;
        }
        case TRANSACTION_seek: {
            data.enforceInterface(descriptor);//執行接口
            int _arg0;
            _arg0 = data.readInt();//獲取數據
            this.seek(_arg0);//調用seek方法
            reply.writeNoException();//將計算結果寫入reply中
            return true;
        }
  //略...
複製代碼

3.5:Proxy中的實現方法

Proxy是代理類,運行在客戶端,也就是Stub#asInterface中iin
沒法強轉成IMusicPlayerService是返回Proxy類對象

---->[IMusicPlayerService.Stub.Proxy#start]--------
@Override
public void start() throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
         //向_data中寫入參數
        _data.writeInterfaceToken(DESCRIPTOR);
        //經過transact方法向服務端傳遞參數,並寫入_reply
        mRemote.transact(Stub.TRANSACTION_start, _data, _reply, 0);
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}

@Override
public void seek(int pre_100) 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.writeInt(pre_100);
        mRemote.transact(Stub.TRANSACTION_seek, _data, _reply, 0);
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}
複製代碼

4.如今再來看咱們在Service中畫的最後一張圖

ServiceConnection的onServiceConnected方法會回調一個IBinder對象service
並經過IMusicPlayerService.Stub.asInterface方法將service變成IMusicPlayerService對象
還記得asInterface裏作了什麼嗎?下面再看一遍,aidl在使用層面的邏輯是否是清晰了一些?

這裏要強調一下:
圖中:藍色區域可在任意app中使用,至關於客戶端:只要鏈接就好了   
其餘區域是服務端的邏輯,爲客戶端提供業務邏輯處理 
複製代碼

aidl綁定服務.png

asInterface.png

至於Binder在底層怎麼跑的,那是後話,那根鑽石級的硬骨頭仍是最後啃吧


5.小結一下:如今回頭再看
1.在一個aidl的服務中,業務邏輯的處理是在哪的?
|--- 這還用問嗎,固然在MusicPlayerStub裏面,否則還能在哪?

2.IMusicPlayerService和Stub有什麼用
|--- IMusicPlayerService是可調用的接口
|--- Stub在臺面上有一個功勞,用asInterface將IBinder對象轉化爲IMusicPlayerService對象

3.Proxy有什麼用?
|---Proxy惟一出現的是在asInterface方法中,在inn沒法強轉成IMusicPlayerService時使用Proxy  

4.何時inn沒法轉成IMusicPlayerService?(見下圖)
|--- 我作了一個實驗,就是分別看一下客戶端和服務端綁定時回調的IBinder對象類型
再調用queryLocalInterface方法獲得inn,看一下它的類型
服務端是:MusicPlayerStub ,它何許人也? Stub之子,Stub實現了IMusicPlayerService,強轉ok  
客戶端是:BinderProxy對象queryLocalInterface後爲null,使用Proxy  
複製代碼

客戶端與服務端綁定服務的區別.png

queryLocalInterface.png


3、ActivityManagerService初探

1.對於系統級跨進程通訊的Service如何分析
當咱們研究源碼時遇到這種代碼應該怎麼分析?(如ActivityManagerNative)
能夠看出不管Stub和Proxy或Binder對代碼的邏輯性的分析並無太大的用處,
他們只是實現類跨進程通訊的機制,這種機制和邏輯相關性不是很是大

IXXXService只是規定接口方法,須要瞭解一下,着重的業務邏輯全在XXXXStub的實現類當中,
通常XXXXStub是做爲XXXXService的內部類,也就是說看到有關aidl的系統服務源碼時,
直接分析XXXXService就好了,邏輯全在那裏
複製代碼

2.AIDL爲什麼而生
|--- 一個字:懶...   
自動生成的那個類,本身敲出來也能跑,既然能自動生成,那就生成唄,AIDL就出來了
這樣就簡化了跨進程間通訊,可是凡事都有兩面性,一旦簡化了,就很難玩花樣
Binder能夠很複雜,IBinder還有不少控制的方法,因此AIDL只是最簡單的跨進程間通訊機制  
就像快速生產的板凳和精心雕刻的板凳,雖然都能坐,但價值是天差地別的
複製代碼

3.ActivityManagerNative分析

還記得第一篇中Activity啓動時出場的ActivityManagerNative嗎?
這就是傳說中的ActivityManagerNative你能夠和最上面的IMusicPlayerService對比一下

ActivityManagerNative分析.png


4.ActivityManagerNative的幕後大佬

通常來講都是調用ActivityManagerNative.getDefault()生成一個IActivityManager對象
而後調用IActivityManager的相應抽象方法,那具體的實現類是誰?
ActivityManagerNative的做用至關於上面的Stub,須要找到一個繼承他的類
這即是ActivityManagerService,注意它並非Service類對象,而是服務的核心邏輯
它的價值也就至關於咱們上面的MusicPlayerStub,不是Service,卻更似服務

ActivityManagerService.png


5.ActivityManagerNative.getDefault()方法說了什麼?

返回一個IActivityManager對象,實際類型爲ActivityManagerService

ActivityManagerNative.getDefalut.png

---->[ActivityManagerNative#getDefault]--------------------
static public IActivityManager對象 getDefault() {
    return gDefault.get();
}

//|--這裏經過gDefault成員變量的get()方法獲取了一個IActivityManager對象
|----如今焦點在gDefault身上,來看一下他是什麼

---->[ActivityManagerNativegetDefault.gDefault]--------------------
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        //經過ServiceManager獲取activity的IBinder對象
        IBinder b = ServiceManager獲取.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        //asInterface方法使用IBinder對象,獲取IActivityManager對象
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

//|--gDefault的數據類型是Singleton<IActivityManager>,有點意思,看一下Singleton類
----單例輔助類啊!create()方法用於穿件對象,get方法獲取單例對象,但它是@hide的,咱們不能用
public abstract class Singleton<T> {
    private T mInstance;
    protected abstract T create();
    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

---->[ActivityManagerNativegetDefault.asInterface]--------------------
static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    //若是obj(即Bundle) queryLocalInterface 不爲空,就使用in
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }
    //不然返回ActivityManagerProxy對象
    return new ActivityManagerProxy(obj);
}

---->[ActivityManagerNativegetDefault$ActivityManagerProxy]--------------------
class ActivityManagerProxy implements IActivityManager{
    public ActivityManagerProxy(IBinder remote){
        mRemote = remote;
    }
    public IBinder asBinder(){
        return mRemote;
    }
    //略...
        public int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle map,
            String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
            boolean sticky, int userId) throws RemoteException
    //略...
    }
複製代碼

這樣使用ActivityManagerNative.getDefault()即可以得到一個IActivityManager對象,
該對象的實現類型爲ActivityManagerService,也就是傳說中的AMS,
因此在看源碼時ActivityManagerNative.getDefault(),就至關於看到了AMS

相關文章
相關標籤/搜索