淺析Binder(五)——ServiceManager代理對(duì)象的獲取

大家都知道Binder機(jī)制主要由ServiceManager绰姻,Binder實(shí)體對(duì)象依溯,Binder代理對(duì)象三個(gè)組件,顧我們想要在Java世界實(shí)現(xiàn)Binder機(jī)制也需要事項(xiàng)這個(gè)三個(gè)組件

Service Manager的Java代理對(duì)象的類型為ServiceManagerProxy類型温算,想要獲取這個(gè)對(duì)象需要先在C++層創(chuàng)建一個(gè)句柄值為0的Binder代理對(duì)象胆绊,然后在Java層創(chuàng)建一個(gè)對(duì)應(yīng)的Java服務(wù)代理對(duì)象。

ServiceManager的java代理對(duì)象類圖.jpeg

最終是ServiceManager類獲取到ServiceManagerProxy對(duì)象颜屠,并保存在了sServiceManager成員變量中辰妙,通過(guò)這個(gè)變量我們又可以得到getService(),listService(),checkService(),addService()等操作Java服務(wù)的方法。

//framworks/base/core/java/android/os/ServiceManager.java
 private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }
//framworks/base/core/java/android/os/ServiceManagerNative.java
    static public IServiceManager asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        return new ServiceManagerProxy(obj);
    }

然后大家會(huì)問(wèn)汽纤?Java服務(wù)代理對(duì)象是從哪里獲取的呢上岗?
看到那個(gè)黃色的小框了沒(méi)有,Java服務(wù)對(duì)象就是通過(guò)JNI方法獲取的
getContextObject()方法是JNI方法蕴坪,JNI教程參考,它由android_os_BinderInternal_getContextObject來(lái)實(shí)現(xiàn)

//framworks/base/core/jni/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    return javaObjectForIBinder(env, b);
}

然后我們需要具體解析的javaObjectForIBinder(),看名字就知道他就是將Java對(duì)象轉(zhuǎn)換為IBinder對(duì)象的關(guān)鍵方法

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    if (val->checkSubclass(&gBinderOffsets)) {
        // One of our own!
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }

    // For the rest of the function we will hold this lock, to serialize
    // looking/creation of Java proxies for native Binder proxies.
    AutoMutex _l(mProxyLock);

    // Someone else's...  do we know about it?
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = jniGetReferent(env, object);
        if (res != NULL) {
            ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
            return res;
        }
        LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }

    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);
        // The proxy holds a reference to the native object.
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
        val->incStrong((void*)javaObjectForIBinder);

        // The native object needs to hold a weak reference back to the
        // proxy, so we can retrieve the same proxy if it is still active.
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);

        // Also remember the death recipients registered on this proxy
        sp<DeathRecipientList> drl = new DeathRecipientList;
        drl->incStrong((void*)javaObjectForIBinder);
        env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));

        // Note that a new object reference has been created.
        android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }

    return object;
}

參數(shù)val要么指向一個(gè)Binder代理對(duì)象肴掷,要么指向一個(gè)Binder本地對(duì)象敬锐。當(dāng)它指向一個(gè)Binder本地對(duì)象時(shí),他的類型為JavaBBinder呆瞻,后者繼承BBinder類台夺。

frameworks/base/libs/binder/Binder.cpp
bool IBinder::checkSubclass(const void* /*subclassID*/) const
{
    return false;
}

大家看到checkSubclass是用來(lái)檢測(cè)val指向Binder代理對(duì)象,還是JavaBBinder對(duì)象痴脾,默認(rèn)值返回false颤介。但是JavaBBinder類重寫了其父類BBinder的父類IBinder的成員函數(shù)checkSubclass(),所以只要subclassID指向全局變量gBinderOffsets就返回true赞赖。

  1. 當(dāng)val指向的是一個(gè)JavaBBinder對(duì)象的時(shí)候就返回true滚朵,并通過(guò)成員方法object()獲取Java對(duì)象,mobject指向Java層中的一個(gè)Binder對(duì)象前域。
//framworks/base/core/jni/android_util_Binder.cpp
class JavaBBinder : public BBinder
{
public:
    JavaBBinder(JNIEnv* env, jobject object)
        : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
    {
        ALOGV("Creating JavaBBinder %p\n", this);
        android_atomic_inc(&gNumLocalRefs);
        incRefsCreated(env);
    }

    bool    checkSubclass(const void* subclassID) const
    {
        return subclassID == &gBinderOffsets;
    }

    jobject object() const
    {
        return mObject;
    }
    ......
    private:
      jobject const mObject;
}
  1. 當(dāng)val指向的是一個(gè)句柄值等于0的Binder代理對(duì)象的時(shí)候辕近,它最終返回的是一個(gè)java層的服務(wù)代理對(duì)象,即BinderProxy對(duì)象匿垄。
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = jniGetReferent(env, object);
        if (res != NULL) {
            ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
            return res;
        }
        LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }

這段代碼的功能主要是檢查當(dāng)前進(jìn)程是否已經(jīng)創(chuàng)建BinderProxy對(duì)象移宅。如果是,則返回指向該BinderProxy對(duì)象的WeakRefenrence對(duì)象object椿疗。但是object指向的BinderProxy可能已經(jīng)失效漏峰,因此需要繼續(xù)檢查,并將其升級(jí)為強(qiáng)引用對(duì)象届榄。若object升級(jí)成功則返回BinderProxy對(duì)象浅乔,如果升級(jí)失敗則解除它與無(wú)效的BinderProxy對(duì)象的對(duì)應(yīng)關(guān)系。

如何將Binder代理對(duì)象外部對(duì)象關(guān)聯(lián)痒蓬?
例:函數(shù)javaObjectForBinder在為一個(gè)Binder代理對(duì)象(BpBinder)創(chuàng)建一個(gè)Java服務(wù)對(duì)象(BinderProxy)時(shí)童擎,就會(huì)將創(chuàng)建出來(lái)的Java服務(wù)代理對(duì)象(BinderProxy)保存在Binder代理對(duì)象(BpBinder)的成員變量mObjects中。但是一個(gè)Binder代理對(duì)象(BpBinder)不僅僅是關(guān)聯(lián)一個(gè)外部對(duì)象攻晒,所以需要為每一個(gè)外部對(duì)象設(shè)置一個(gè)參數(shù),而Java服務(wù)代理對(duì)象(BinderPorxy)所使用的參數(shù)就是gBinderProxyOffsets的地址班挖。

ObjectManager 是定義在BpBinder內(nèi)部的一個(gè)類鲁捏。定義了外部對(duì)象操作函數(shù)attach(增),find(查),detach(刪)kill函數(shù)用來(lái)清理與Binder代理對(duì)象管理的外部對(duì)象萧芙。

  class ObjectManager
    {
    public:
                    ObjectManager();
                    ~ObjectManager();

        void        attach( const void* objectID,
                            void* object,
                            void* cleanupCookie,
                            IBinder::object_cleanup_func func);
        void*       find(const void* objectID) const;
        void        detach(const void* objectID);

        void        kill();

    private:
                    ObjectManager(const ObjectManager&);
        ObjectManager& operator=(const ObjectManager&);

        struct entry_t
        {
            void* object; // 指向外部對(duì)象的一個(gè)弱引用對(duì)象
            void* cleanupCookie; //fun所指向的清理函數(shù)的一個(gè)調(diào)用參數(shù)
            IBinder::object_cleanup_func func; // 函數(shù)指針给梅,用來(lái)清理Object指向的外部對(duì)象
        };

        //維護(hù)與一個(gè)Binder代理對(duì)象所關(guān)聯(lián)的外部對(duì)象,這些外部對(duì)象都使用entry_t結(jié)構(gòu)體來(lái)描述
        KeyedVector<const void*, entry_t> mObjects; 
    

相應(yīng)的Binder代理對(duì)象也提供了三個(gè)成員函數(shù)双揪,attchObject动羽,findObject,detachObject用來(lái)增查刪與它關(guān)聯(lián)的外部對(duì)象渔期,具體實(shí)現(xiàn)是調(diào)用內(nèi)部類的成員變量mObjects的成員函數(shù)attach运吓,find渴邦,detach實(shí)現(xiàn)。

void BpBinder::attachObject(
    const void* objectID, void* object, void* cleanupCookie,
    object_cleanup_func func)
{
    AutoMutex _l(mLock);
    ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
    mObjects.attach(objectID, object, cleanupCookie, func);
}

void* BpBinder::findObject(const void* objectID) const
{
    AutoMutex _l(mLock);
    return mObjects.find(objectID);
}

void BpBinder::detachObject(const void* objectID)
{
    AutoMutex _l(mLock);
    mObjects.detach(objectID);
}

參考:
《Android系統(tǒng)源代碼情景分析》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拘哨,一起剝皮案震驚了整個(gè)濱河市谋梭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌倦青,老刑警劉巖瓮床,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異产镐,居然都是意外死亡隘庄,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門癣亚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)峭沦,“玉大人,你說(shuō)我怎么就攤上這事逃糟『鹩悖” “怎么了厌蔽?”我有些...
    開(kāi)封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵祖凫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我酸些,道長(zhǎng)取募,這世上最難降的妖魔是什么琐谤? 我笑而不...
    開(kāi)封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮玩敏,結(jié)果婚禮上斗忌,老公的妹妹穿的比我還像新娘。我一直安慰自己旺聚,他們只是感情好织阳,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著砰粹,像睡著了一般唧躲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碱璃,一...
    開(kāi)封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天弄痹,我揣著相機(jī)與錄音,去河邊找鬼嵌器。 笑死肛真,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的爽航。 我是一名探鬼主播蚓让,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼乾忱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了凭疮?” 一聲冷哼從身側(cè)響起饭耳,我...
    開(kāi)封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎执解,沒(méi)想到半個(gè)月后寞肖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衰腌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年新蟆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片右蕊。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡琼稻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饶囚,到底是詐尸還是另有隱情帕翻,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布萝风,位于F島的核電站嘀掸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏规惰。R本人自食惡果不足惜睬塌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望歇万。 院中可真熱鬧揩晴,春花似錦、人聲如沸贪磺。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缘挽。三九已至瞄崇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間壕曼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工等浊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留腮郊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓筹燕,卻偏偏與公主長(zhǎng)得像轧飞,于是被迫代替她去往敵國(guó)和親衅鹿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容