Android開發之漫漫長途 IX——徹底掌握Binder

來源:互聯網
上載者:User

標籤:off   ctf   ==   函數指標   sub   final   flags   tom   errno   

該文章是一個系列文章,是本人在Android開發的漫漫長途上的一點感想和記錄,我會盡量按照先易後難的順序進行編寫該系列。該系列引用了《Android開發藝術探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相關知識,另外也借鑒了其他的優質部落格,在此向各位大神表示感謝,膜拜!!!另外,本系列文章知識可能需要有一定Android開發基礎和項目經驗的同學才能更好理解,也就是說該系列文章面向的是Android中進階開發工程師。

前言

上一次還不如不說去面試了呢,估計是掛了,資料結構與演算法方面雖然面試前突擊了一波,但是時間太短,當時學的也不好。另外Android的一些知識也不是很瞭解。不過這也加大了我寫部落格的動力。許多知識總覺得自己掌握的還挺好,不過一問到比較細節的方面就不太清楚了。所以寫這整個部落格的目的也是加深自己的知識,培養自己的溝通能力,和大家一起學習吧。
好了,閑話少說,我們這一篇先解決上一篇中遺留的問題,之後有時間的話,我把這次的面試經曆單寫一篇部落格,和大家共勉。
本篇我們來看一下ServiceManager。上一篇中沒怎麼說它,ServiceManager作為Android系統服務的大管家。我們還是有必要來看一下它的。

ServiceManager概述

ServiceManager是Android世界中所有重要系統服務的大管家。像前文提到的AMS(ActivityManagerService),還有許多以後可能分析到的PackageManagerService等等服務都需要像ServiceManager中註冊。那麼為何需要一個ServiceManager呢,其重要作用何在呢?私認為有以下幾點:

  1. ServiceManager能集中管理系統內的所有服務,它能施加許可權控制,並不是任何進程都能註冊服務的。
  2. ServiceManager支援通過字串名稱來尋找對應的Service。這個功能很像DNS。由於各種原因的影響,Server進程可能生死無常。 如果讓每個Client都去檢測,壓力實在太大了。 現在有了統一的管理機構,Client只需要查詢ServiceManager,就能把握動向,得到最新資訊。
ServiceManager

[SystemServer.java]

public void setSystemProcess() {    try {        //註冊服務,第二個參數為this,這裡假設SystemServer通過“socket”與SM互動        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);        ..........    } catch (PackageManager.NameNotFoundException e) {        ........    }}

我們SystemServer進程中的AMS通過SM的代理與SM進程互動(讀者也可以把這個過程想象為你所能理解的處理序間通訊方式,例如管道、Socket等),並把自己註冊在SM中。這個情況下,我們使用ServiceManager的代理與SM進程互動,既然有代理,那麼也得有對應的服務端。那麼根據我們之前部落格的思路分析的話,就是如下的流程:

ServiceManager是如何啟動的?

按照我們之前部落格的思路,我們在SystemServer端有了個ServiceManager的代理,那麼Android系統中應該提供類似AMS這樣的繼承或間接繼承自java層Binder然後重寫onTransact方法以處理請求。但是並沒有,ServiceManager並沒有使用如AMS這樣複雜的Binder類結構。而是直接與Binder驅動裝置打交道。所以我們上一篇說了ServiceManager不一樣。我們來看具體看一下。

ServiceManager在init.rc設定檔中配置啟動,是一個以c/c++語言編寫的程式。init進程、SM進程等關係如


我們來看它的main方法。

int main(int argc, char **argv){    struct binder_state *bs;    //①應該是開啟binder裝置吧?    bs = binder_open(128*1024);    if (!bs) {        ALOGE("failed to open binder driver\n");        return -1;    }    //②成為manager    if (binder_become_context_manager(bs)) {        ALOGE("cannot become context manager (%s)\n", strerror(errno));        return -1;    }   ......        //③處理用戶端發過來的請求    binder_loop(bs, svcmgr_handler);    return 0;}
①開啟Binder裝置

[binder.c]

struct binder_state*binder_open(unsigned mapsize){    struct binder_state*bs;    bs=malloc(sizeof(*bs));    ......    //開啟Binder裝置    bs->fd=open("/dev/binder",O_RDWR);    ......    bs->mapsize=mapsize;    //進行記憶體映射    bs->mapped=mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs->    fd,0);}

這一步的目的是把核心層的binder驅動映射到使用者空間。我們知道進程之間是獨立的,進程呢運行在使用者空間內,核心層的Binder驅動可以看成是一個檔案(實際上它也是,Linux上都是檔案)。這一步呢,可以看成把一個檔案對應到使用者空間,我們的進程呢通過這個檔案進行互動。

②成為manager

[Binder.c]

int binder_become_context_manager(struct binder_state*bs){    //實現太簡單了!這個有個0,什麼鬼?    return ioctl(bs->fd,BINDER_SET_CONTEXT_MGR,0);}
③處理用戶端發過來的請求

[Binder.c]

void binder_loop(struct binder_state *bs, binder_handler func){    int res;    struct binder_write_read bwr;    uint32_t readbuf[32];    bwr.write_size = 0;    bwr.write_consumed = 0;    bwr.write_buffer = 0;    readbuf[0] = BC_ENTER_LOOPER;    binder_write(bs, readbuf, sizeof(uint32_t));    for (;;) {//果然是迴圈        bwr.read_size = sizeof(readbuf);        bwr.read_consumed = 0;        bwr.read_buffer = (uintptr_t) readbuf;        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);        if (res < 0) {            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));            break;        }        //接收到請求交給binder_parse,最終會調用func來處理這些請求        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);        if (res == 0) {            ALOGE("binder_loop: unexpected reply?!\n");            break;        }        if (res < 0) {            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));            break;        }    }}

上面傳入func的是svcmgr_ handler函數指標,所以會在svcmgr_handler中進行集中處理用戶端的請求。

[service_manager.c]

int svcmgr_handler(struct binder_state *bs,                   struct binder_transaction_data *txn,                   struct binder_io *msg,                   struct binder_io *reply){    struct svcinfo *si;    uint16_t *s;    size_t len;    uint32_t handle;    uint32_t strict_policy;    int allow_isolated;        if (txn->target.ptr != BINDER_SERVICE_MANAGER)        return -1;    if (txn->code == PING_TRANSACTION)        return 0;       strict_policy = bio_get_uint32(msg);    s = bio_get_string16(msg, &len);    if (s == NULL) {        return -1;    }    if ((len != (sizeof(svcmgr_id) / 2)) ||        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {        fprintf(stderr,"invalid id %s\n", str8(s, len));        return -1;    }    if (sehandle && selinux_status_updated() > 0) {        struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();        if (tmp_sehandle) {            selabel_close(sehandle);            sehandle = tmp_sehandle;        }    }    switch(txn->code) {    case SVC_MGR_GET_SERVICE://得到某個service的資訊,service用字串表示。    case SVC_MGR_CHECK_SERVICE:        s = bio_get_string16(msg, &len);//s是字串表示的service名稱。        if (s == NULL) {            return -1;        }        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);        if (!handle)            break;        bio_put_ref(reply, handle);        return 0;    case SVC_MGR_ADD_SERVICE://對應addService請求。        s = bio_get_string16(msg, &len);        if (s == NULL) {            return -1;        }        handle = bio_get_ref(msg);        allow_isolated = bio_get_uint32(msg) ? 1 : 0;        if (do_add_service(bs, s, len, handle, txn->sender_euid,            allow_isolated, txn->sender_pid))            return -1;        break;    case SVC_MGR_LIST_SERVICES: {//得到當前系統已經註冊的所有service的名字。        uint32_t n = bio_get_uint32(msg);        if (!svc_can_list(txn->sender_pid)) {            ALOGE("list_service() uid=%d - PERMISSION DENIED\n",                    txn->sender_euid);            return -1;        }        si = svclist;        while ((n-- > 0) && si)            si = si->next;        if (si) {            bio_put_string16(reply, si->name);            return 0;        }        return -1;    }    default:        ALOGE("unknown code %d\n", txn->code);        return -1;    }    bio_put_uint32(reply, 0);    return 0;}
ServiceManager的代理是如何獲得的?

我們來回到最初的調用

[SystemServer.java]

public void setSystemProcess() {    try {        //註冊服務,第二個參數為this,這裡假設SystemServer通過“socket”與SM互動        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);        ..........    } catch (PackageManager.NameNotFoundException e) {        ........    }}

上面的請求最終是通過SM服務代理髮送的,那這個代理是怎麼來的呢?我們來看

[ServiceManager.java]

public static void addService(String name, IBinder service) {    try {        getIServiceManager().addService(name, service, false);    } catch (RemoteException e) {        Log.e(TAG, "error in addService", e);    }}private static IServiceManager getIServiceManager() {    if (sServiceManager != null) {        return sServiceManager;    }    // 是這裡,沒錯了    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());    return sServiceManager;}

我們先來看BinderInternal.getContextObject()

[BinderInternal.java]

//好吧,它還是個native函數public static final native IBinder getContextObject();

跟進[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);}

跟進[ProcessState.cpp]

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/){    return getStrongProxyForHandle(0);}/*這個函數是不是我們之前見過*/sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle){    sp<IBinder> result;    AutoMutex _l(mLock);    handle_entry* e = lookupHandleLocked(handle);    if (e != NULL) {             IBinder* b = e->binder;        if (b == NULL || !e->refs->attemptIncWeak(this)) {            if (handle == 0) {//這裡我們的handle為0                                Parcel data;            //在handle對應的BpBinder第一次建立時            //會執行一次虛擬事務請求,以確保ServiceManager已經註冊                status_t status = IPCThreadState::self()->transact(                        0, IBinder::PING_TRANSACTION, data, NULL, 0);                if (status == DEAD_OBJECT)                   return NULL;//如果ServiceManager沒有註冊,直接返回            }            //這裡還是以handle參數建立了BpBinder            b = new BpBinder(handle);             e->binder = b;            if (b) e->refs = b->getWeakRefs();            result = b;        } else {                       result.force_set(b);            e->refs->decWeak(this);        }    }    return result;}

我們再一步步返回
[android_ util_Binder.cpp]

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);    //這裡的b = new BpBinder(0);    return javaObjectForIBinder(env, b);}/*這個函數我們上一篇是不是也見過*/jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) {    if (val == NULL) return NULL;    //如果val是Binder對象,進入下面分支,此時val是BpBinder    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;    }    .........    //調用BpBinder的findObject函數    //在Native層的BpBinder中有一個ObjectManager,它用來管理在Native BpBinder上建立的Java BinderProxy對象    //findObject用於判斷gBinderProxyOffsets中,是否儲存了已經被ObjectManager管理的Java BinderProxy對象    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);    if (object != NULL) {        jobject res = jniGetReferent(env, object);        ............        //如果該Java BinderProxy已經被管理,則刪除這箇舊的BinderProxy        android_atomic_dec(&gNumProxyRefs);        val->detachObject(&gBinderProxyOffsets);        env->DeleteGlobalRef(object);    }    //建立一個新的BinderProxy對象    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);    if (object != NULL) {                env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());        val->incStrong((void*)javaObjectForIBinder);               jobject refObject = env->NewGlobalRef(                env->GetObjectField(object, gBinderProxyOffsets.mSelf));        //新建立的BinderProxy對象註冊到BpBinder的ObjectManager中,同時註冊一個回收函數proxy_cleanup        //當BinderProxy對象detach時,proxy_cleanup函數將被調用,以釋放一些資源        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);        //將死亡通知list和BinderProxy聯絡起來        env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));        // Note that a new object reference has been created.        android_atomic_inc(&gNumProxyRefs);        //記憶體回收相關;利用gNumRefsCreated記錄建立出的BinderProxy數量        //當建立出的BinderProxy數量大於200時,該函數將利用BinderInternal的ForceGc函數進行一個記憶體回收        incRefsCreated(env);        return object;    }}

接著返回到[ServiceManager.java]

private static IServiceManager getIServiceManager() {    if (sServiceManager != null) {        return sServiceManager;    }    // 是這裡,沒錯了BinderInternal.getContextObject()是BinderProxy對象    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());    return sServiceManager;}

跟進[[ServiceManagerNative.java]]

static public IServiceManager asInterface(IBinder obj){    if (obj == null) {        return null;    }    我們知道這裡的obj指向的是BinderProxy對象    IServiceManager in =        (IServiceManager)obj.queryLocalInterface(descriptor);    if (in != null) {        return in;    }        return new ServiceManagerProxy(obj);}

跟進[Binder.java]

final class BinderProxy implements IBinder {       public IInterface queryLocalInterface(String descriptor) {        return null;    }}

跟進[ServiceManagerNative.java]

class ServiceManagerProxy implements IServiceManager {    public ServiceManagerProxy(IBinder remote) {        //這裡的mRemote指向了BinderProxy,與我們上一篇部落格中講述的遙相呼應        mRemote = remote;    }}
本節小結

我們詳盡講述了SM進程的啟動以及它作為服務大管家的意義。結合上一篇的內容我們總算是把Binder講述的比較清楚了。

Binder補充說明AIDL

經過上面的介紹,你應該明白Java層Binder的架構中,Bp端可以通過BinderProxy的transact()方法與Bn端發送請求,而Bn端通過整合Binder重寫onTransact()接收並處理來自Bp端的請求。這個結構非常清晰簡單,在Android6.0,我們可以處處看到這樣的設計,比如我們的ActivityManagerNavtive這個類,涉及到Binder通訊的基本上都是這種設計。不過如果我們想要自己來定義一些遠程服務。那這樣的寫法就比較繁瑣,還好Android提供了AIDL,並且在Android8.0之後,我們可以看到與ActivityManagerNavtive相似的許多類已經被標註過時,因為Android系統也使用AIDL了。
AIDL的文法與定義一個java介面非常類似。下面我就定以一個非常簡單的aidl

IMyAidlInterface.aidl

interface IMyAidlInterface {    int getTest();}

然後基本上就行了,我們重新build之後會得到一個
IMyAidlInterface.java檔案,這個檔案由aidl工具產生,我們現在使用的基本是AndroidStudio,即使你使用的是Eclipse也沒關係,這個檔案會自動產生,不需要你操心。但是我們還是得來看看我們產生的這個檔案

public interface IMyAidlInterface extends android.os.IInterface {    //抽象的Stub類,繼承自Binder並實現我們定義的IMyAidlInterface介面    //繼承自Binder,重寫onTransact方法,是不是感覺跟我們的XXXNative很像    public static abstract class Stub extends android.os.Binder implements com.mafeibiao.testapplication.IMyAidlInterface {        private static final java.lang.String DESCRIPTOR = "com.mafeibiao.testapplication.IMyAidlInterface";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.mafeibiao.testapplication.IMyAidlInterface interface,         * generating a proxy if needed.         */        public static com.mafeibiao.testapplication.IMyAidlInterface asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.mafeibiao.testapplication.IMyAidlInterface))) {                return ((com.mafeibiao.testapplication.IMyAidlInterface) iin);            }            return new com.mafeibiao.testapplication.IMyAidlInterface.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 {            switch (code) {                case INTERFACE_TRANSACTION: {                    reply.writeString(DESCRIPTOR);                    return true;                }                case TRANSACTION_getTest: {                    data.enforceInterface(DESCRIPTOR);                    int _result = this.getTest();                    reply.writeNoException();                    reply.writeInt(_result);                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }                /*這個Proxy不用說肯定是代理了,其內部還有個mRemote對象*/        private static class Proxy implements com.mafeibiao.testapplication.IMyAidlInterface {            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;            }            @Override            public int getTest() throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                int _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getTest, _data, _reply, 0);                    _reply.readException();                    _result = _reply.readInt();                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }        static final int TRANSACTION_getTest = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    }    public int getTest() throws android.os.RemoteException;}

可見,AIDL的本質與XXXNative之類的類並沒有什麼本質的不同,不過他的出現使得構建一個Binder服務的工作大大簡化了。

本篇總結

我們本篇詳細分析了ServiceManager,ServiceManager並沒有使用複雜的類結構,他直接與Binder驅動裝置互動達到IPC通訊的目的。(欠下的債終於補上了)

下篇預告

下篇我們來講一下Android序列化相關知識。

此致,敬禮

Android開發之漫漫長途 IX——徹底掌握Binder

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.