Android C++層使用Binder通訊的方法

bossanovo發表於2019-01-18

本文以Audio系統為例,基於Android 7.1

1. 規範制定者 IInterface.h

IInterface.h是C++層Binder通訊的規範定製者, 客戶端和服務端都要包含該標頭檔案。
IInterface.h中提供了C++層Binder通訊必要的工具。

1. 客戶端規範

客戶端需要繼承BpInterface 和IInterface,這個是個模板類,作用其實是使客戶端物件繼承自模板物件,如下:

//frameworks/native/include/binder/IInterface.h

//IInterface 中定義了對Binder的轉換操作
class IInterface : public virtual RefBase
{
public:
            IInterface();
            static sp<IBinder>  asBinder(const IInterface*);
            static sp<IBinder>  asBinder(const sp<IInterface>&);

protected:
    virtual                     ~IInterface();
    virtual IBinder*            onAsBinder() = 0;
};

//BpInterface 
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase //**BpRefBase 中有個remote()函式,
                                                      //直接指向服務端Bind而物件
{
public:
                                //remote使服務端Binder物件
                                BpInterface(const sp<IBinder>& remote);

protected:
    virtual IBinder*            onAsBinder();
};

BpRefBase

BpRefBase 繼承自RefBase,所以在首次引用的時候會呼叫onFirstRef方法

//frameworks/native/include/binder/Binder.h
class BpRefBase : public virtual RefBase
{
protected:
                            BpRefBase(const sp<IBinder>& o);
    virtual                 ~BpRefBase();
    virtual void            onFirstRef();
    virtual void            onLastStrongRef(const void* id);
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);

                            //remote()函式直接使用,就是代表了服務端物件
    inline  IBinder*        remote()                { return mRemote; }
    inline  IBinder*        remote() const          { return mRemote; }

private:
                            BpRefBase(const BpRefBase& o);
    BpRefBase&              operator=(const BpRefBase& o);

    IBinder* const          mRemote;
    RefBase::weakref_type*  mRefs;
    std::atomic<int32_t>    mState;
};

//構造實現
BpRefBase::BpRefBase(const sp<IBinder>& o)
    //mRemote來自子類的傳遞
    : mRemote(o.get()), mRefs(NULL), mState(0)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    if (mRemote) {
        mRemote->incStrong(this);           // Removed on first IncStrong().
        mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.
    }
}

2. 服務端規範

服務端要繼承BnInterface ,這個是個模板類,作用其實是使服務端物件繼承自模板物件,如下:

//frameworks/native/include/binder/IInterface.h
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;

protected:
    virtual IBinder*            onAsBinder();
};

3. 兩個重要的巨集

Android提供的這兩個巨集是方便Binder介面的統一實現
需要以‘I’開頭加上傳入的介面變數來做宣告/實現

  1. DECLARE_META_INTERFACE: 宣告介面構造
#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const android::String16 descriptor;                          \
    static android::sp<I##INTERFACE> asInterface(                       \
            const android::sp<android::IBinder>& obj);                  \
    virtual const android::String16& getInterfaceDescriptor() const;    \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \
  1. IMPLEMENT_META_INTERFACE:
    實現介面構造(和DECLARE_META_INTERFACE宣告對應,實現其宣告的介面構造和變數)
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    //descriptor是客戶端和服務端的對接識別符號,以傳入的NAME作為初始化內容
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    //服務端的Binder物件是通過介面的asInterface傳入的,所以在找服務端介面的時候,可以使用
    //I##INTERFACE::asInterface來查詢
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {                                                                   \
        android::sp<I##INTERFACE> intr;                                 \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                //建立客戶端物件,傳入服務端Binder物件
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \
    
    ---------------------------------------------------------------------------------------
	//一個方便的函式,將Binder物件轉換為對應的客戶端介面
	template<typename INTERFACE>
	inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
	{
	    return INTERFACE::asInterface(obj);//也是呼叫對應模板的asInterface方法的
	}

2. 以AudioFlinger為例

1. 客戶端 IAudioFlinger

//frameworks/av/include/media/IAudioFlinger.h
class IAudioFlinger : public IInterface
{
public:
    DECLARE_META_INTERFACE(AudioFlinger);//宣告巨集
}

//服務端實現介面的規範
class BnAudioFlinger : public BnInterface<IAudioFlinger>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};
//frameworks/av/media/libmedia/IAudioFlinger.cpp
class BpAudioFlinger : public BpInterface<IAudioFlinger>
{
public:
    BpAudioFlinger(const sp<IBinder>& impl)
        : BpInterface<IAudioFlinger>(impl)//這裡的構造中的Binder物件是在上面的
                                         //IMPLEMENT_META_INTERFACE巨集中傳入的
    {
    }
    IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
}

獲取IAudioFlinger服務端的例子:

//frameworks/av/media/libmedia/AudioSystem.cpp
const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
{
    sp<IAudioFlinger> af;
    sp<AudioFlingerClient> afc;
    {
        Mutex::Autolock _l(gLock);
        if (gAudioFlinger == 0) {
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder;
            do {
               //獲取AudioFlinger Binder物件
                binder = sm->getService(String16("media.audio_flinger"));
                if (binder != 0)
                    break;
                ...
            } while (true);
            ...
            //轉化為IAudioFlinger 介面,作為服務端代理
            gAudioFlinger = interface_cast<IAudioFlinger>(binder);
            ...
        }
        af = gAudioFlinger;
    }
    ...
    return af;
}

客戶端資訊總結:

  • 客戶端介面: IAudioFlinger
  • 客戶端d代理物件: BpAudioFlinger
  • descriptor: android.media.IAudioFlinger
  • 服務端: AudioFlinger
  • remote() : 即服務端 AudioFlinger

2. 服務端 AudioFlinger

//frameworks/av/services/audioflinger/AudioFlinger.h
class AudioFlinger :
    public BinderService<AudioFlinger>, //這個介面會將AudioFlinger 註冊到ServiceManager中
    public BnAudioFlinger //繼承自BnInterface
{
    friend class BinderService<AudioFlinger>;   // for AudioFlinger()
public:
    //服務端在ServiceManager註冊的時候的服務賬號,客戶端用這個賬號從ServiceManager中獲取服務端Binder物件。
    static const char* getServiceName() ANDROID_API { return "media.audio_flinger"; }
}

服務端資訊總結

  • 服務端介面: IAudioFlinger (和客戶端對應,這樣才轉換為客戶端介面IAudioFlinger)
  • 服務端物件:AudioFlinger
  • 服務註冊賬號: media.audio_flinger

3. 總結

  • 客戶端檔案需要Include IInterface.h 檔案, 客戶端需要繼承自IInterface介面,這個介面主要規定了一些對Binder的轉換操作;
  • 客戶端中的remote()函式指的是服務端在客戶端的介面代理(I##INTERFACE),呼叫直接到服務端的onTransact()函式中;
  • 客戶端繼承規則: public Bp##INTERFACE : public I##INTERFACE : public IInterface
  • 服務端繼承規則: (INTERFACE : ) public Bn##INTERFACE: public I##INTERFACE : public IInterface
  • 服務端需要繼承自Bn##INTERFACE介面,在獲取服務端之後使用inerface_cast介面或者I##INTERFACE::asInterface轉換為客戶端介面I##INTERFACE,在客戶端直接使用的體現是remote()函式

相關文章