您好,登錄后才能下訂單哦!
該文章是一個(gè)系列文章,是本人在Android開發(fā)的漫漫長途上的一點(diǎn)感想和記錄,我會(huì)盡量按照先易后難的順序進(jìn)行編寫該系列。該系列引用了《Android開發(fā)藝術(shù)探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相關(guān)知識,另外也借鑒了其他的優(yōu)質(zhì)博客,在此向各位大神表示感謝,膜拜?。?!另外,本系列文章知識可能需要有一定Android開發(fā)基礎(chǔ)和項(xiàng)目經(jīng)驗(yàn)的同學(xué)才能更好理解,也就是說該系列文章面向的是Android中高級開發(fā)工程師。
前言
上一次還不如不說去面試了呢,估計(jì)是掛了,數(shù)據(jù)結(jié)構(gòu)與算法方面雖然面試前突擊了一波,但是時(shí)間太短,當(dāng)時(shí)學(xué)的也不好。另外Android的一些知識也不是很了解。不過這也加大了我寫博客的動(dòng)力。許多知識總覺得自己掌握的還挺好,不過一問到比較細(xì)節(jié)的方面就不太清楚了。所以寫這整個(gè)博客的目的也是加深自己的知識,培養(yǎng)自己的溝通能力,和大家一起學(xué)習(xí)吧。
好了,閑話少說,我們這一篇先解決上一篇中遺留的問題,之后有時(shí)間的話,我把這次的面試經(jīng)歷單寫一篇博客,和大家共勉。
本篇我們來看一下ServiceManager。上一篇中沒怎么說它,ServiceManager作為Android系統(tǒng)服務(wù)的大管家。我們還是有必要來看一下它的。
ServiceManager概述
ServiceManager是Android世界中所有重要系統(tǒng)服務(wù)的大管家。像前文提到的AMS(ActivityManagerService),還有許多以后可能分析到的PackageManagerService等等服務(wù)都需要像ServiceManager中注冊。那么為何需要一個(gè)ServiceManager呢,其重要作用何在呢?私認(rèn)為有以下幾點(diǎn):
ServiceManager能集中管理系統(tǒng)內(nèi)的所有服務(wù),它能施加權(quán)限控制,并不是任何進(jìn)程都能注冊服務(wù)的。 ServiceManager支持通過字符串名稱來查找對應(yīng)的Service。這個(gè)功能很像DNS。由于各種原因的影響,Server進(jìn)程可能生死無常。 如果讓每個(gè)Client都去檢測,壓力實(shí)在太大了。 現(xiàn)在有了統(tǒng)一的管理機(jī)構(gòu),Client只需要查詢ServiceManager,就能把握動(dòng)向,得到最新信息。
ServiceManager
[SystemServer.java]
public void setSystemProcess() { try { //注冊服務(wù),第二個(gè)參數(shù)為this,這里假設(shè)SystemServer通過“socket”與SM交互 ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true); .......... } catch (PackageManager.NameNotFoundException e) { ........ } }
我們SystemServer進(jìn)程中的AMS通過SM的代理與SM進(jìn)程交互(讀者也可以把這個(gè)過程想象為你所能理解的進(jìn)程間通信方式,例如管道、Socket等),并把自己注冊在SM中。這個(gè)情況下,我們使用ServiceManager的代理與SM進(jìn)程交互,既然有代理,那么也得有對應(yīng)的服務(wù)端。那么根據(jù)我們之前博客的思路分析的話,就是如下的流程:
ServiceManager是如何啟動(dòng)的?
按照我們之前博客的思路,我們在SystemServer端有了個(gè)ServiceManager的代理,那么Android系統(tǒng)中應(yīng)該提供類似AMS這樣的繼承或間接繼承自java層Binder然后重寫onTransact方法以處理請求。但是并沒有,ServiceManager并沒有使用如AMS這樣復(fù)雜的Binder類結(jié)構(gòu)。而是直接與Binder驅(qū)動(dòng)設(shè)備打交道。所以我們上一篇說了ServiceManager不一樣。我們來看具體看一下。
ServiceManager在init.rc配置文件中配置啟動(dòng),是一個(gè)以c/c++語言編寫的程序。init進(jìn)程、SM進(jìn)程等關(guān)系如下圖
我們來看它的main方法。
int main(int argc, char **argv) { struct binder_state *bs; //①應(yīng)該是打開binder設(shè)備吧? 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; } ...... //③處理客戶端發(fā)過來的請求 binder_loop(bs, svcmgr_handler); return 0; }
①打開Binder設(shè)備
[binder.c]
struct binder_state*binder_open(unsigned mapsize) { struct binder_state*bs; bs=malloc(sizeof(*bs)); ...... //打開Binder設(shè)備 bs->fd=open("/dev/binder",O_RDWR); ...... bs->mapsize=mapsize; //進(jìn)行內(nèi)存映射 bs->mapped=mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs-> fd,0); }
這一步的目的是把內(nèi)核層的binder驅(qū)動(dòng)映射到用戶空間。我們知道進(jìn)程之間是獨(dú)立的,進(jìn)程呢運(yùn)行在用戶空間內(nèi),內(nèi)核層的Binder驅(qū)動(dòng)可以看成是一個(gè)文件(實(shí)際上它也是,Linux上都是文件)。這一步呢,可以看成把一個(gè)文件映射到用戶空間,我們的進(jìn)程呢通過這個(gè)文件進(jìn)行交互。
②成為manager
[Binder.c]
int binder_become_context_manager(struct binder_state*bs) { //實(shí)現(xiàn)太簡單了!這個(gè)有個(gè)0,什么鬼? return ioctl(bs->fd,BINDER_SET_CONTEXT_MGR,0); }
③處理客戶端發(fā)過來的請求
[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 (;;) {//果然是循環(huán) 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,最終會(huì)調(diào)用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; } } }
上面?zhèn)魅雈unc的是svcmgr_ handler函數(shù)指針,所以會(huì)在svcmgr_handler中進(jìn)行集中處理客戶端的請求。
[service_manager.c]
ServiceManager的代理是如何獲得的?
我們來回到最初的調(diào)用
[SystemServer.java]
public void setSystemProcess() { try { //注冊服務(wù),第二個(gè)參數(shù)為this,這里假設(shè)SystemServer通過“socket”與SM交互 ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true); .......... } catch (PackageManager.NameNotFoundException e) { ........ } }
上面的請求最終是通過SM服務(wù)代理發(fā)送的,那這個(gè)代理是怎么來的呢?我們來看
[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; } // 是這里,沒錯(cuò)了 sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); return sServiceManager; }
我們先來看BinderInternal.getContextObject()
[BinderInternal.java]
//好吧,它還是個(gè)native函數(shù) public static final native IBinder getContextObject();
跟進(jìn)[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); }
跟進(jìn)[ProcessState.cpp]
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/) { return getStrongProxyForHandle(0); } /*這個(gè)函數(shù)是不是我們之前見過*/ 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對應(yīng)的BpBinder第一次創(chuàng)建時(shí) //會(huì)執(zhí)行一次虛擬的事務(wù)請求,以確保ServiceManager已經(jīng)注冊 status_t status = IPCThreadState::self()->transact( 0, IBinder::PING_TRANSACTION, data, NULL, 0); if (status == DEAD_OBJECT) return NULL;//如果ServiceManager沒有注冊,直接返回 } //這里還是以handle參數(shù)創(chuàng)建了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); } /*這個(gè)函數(shù)我們上一篇是不是也見過*/ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) { if (val == NULL) return NULL; //如果val是Binder對象,進(jìn)入下面分支,此時(shí)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; } ......... //調(diào)用BpBinder的findObject函數(shù) //在Native層的BpBinder中有一個(gè)ObjectManager,它用來管理在Native BpBinder上創(chuàng)建的Java BinderProxy對象 //findObject用于判斷gBinderProxyOffsets中,是否存儲(chǔ)了已經(jīng)被ObjectManager管理的Java BinderProxy對象 jobject object = (jobject)val->findObject(&gBinderProxyOffsets); if (object != NULL) { jobject res = jniGetReferent(env, object); ............ //如果該Java BinderProxy已經(jīng)被管理,則刪除這個(gè)舊的BinderProxy android_atomic_dec(&gNumProxyRefs); val->detachObject(&gBinderProxyOffsets); env->DeleteGlobalRef(object); } //創(chuàng)建一個(gè)新的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)); //新創(chuàng)建的BinderProxy對象注冊到BpBinder的ObjectManager中,同時(shí)注冊一個(gè)回收函數(shù)proxy_cleanup //當(dāng)BinderProxy對象detach時(shí),proxy_cleanup函數(shù)將被調(diào)用,以釋放一些資源 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聯(lián)系起來 env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get())); // Note that a new object reference has been created. android_atomic_inc(&gNumProxyRefs); //垃圾回收相關(guān);利用gNumRefsCreated記錄創(chuàng)建出的BinderProxy數(shù)量 //當(dāng)創(chuàng)建出的BinderProxy數(shù)量大于200時(shí),該函數(shù)將利用BinderInternal的ForceGc函數(shù)進(jìn)行一個(gè)垃圾回收 incRefsCreated(env); return object; } }
接著返回到[ServiceManager.java]
private static IServiceManager getIServiceManager() { if (sServiceManager != null) { return sServiceManager; } // 是這里,沒錯(cuò)了BinderInternal.getContextObject()是BinderProxy對象 sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); return sServiceManager; }
跟進(jìn)[[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); }
跟進(jìn)[Binder.java]
final class BinderProxy implements IBinder { public IInterface queryLocalInterface(String descriptor) { return null; } }
跟進(jìn)[ServiceManagerNative.java]
class ServiceManagerProxy implements IServiceManager { public ServiceManagerProxy(IBinder remote) { //這里的mRemote指向了BinderProxy,與我們上一篇博客中講述的遙相呼應(yīng) mRemote = remote; } }
本節(jié)小結(jié)
我們詳盡講述了SM進(jìn)程的啟動(dòng)以及它作為服務(wù)大管家的意義。結(jié)合上一篇的內(nèi)容我們總算是把Binder講述的比較清楚了。
Binder補(bǔ)充說明 AIDL
經(jīng)過上面的介紹,你應(yīng)該明白Java層Binder的架構(gòu)中,Bp端可以通過BinderProxy的transact()方法與Bn端發(fā)送請求,而Bn端通過集成Binder重寫onTransact()接收并處理來自Bp端的請求。這個(gè)結(jié)構(gòu)非常清晰簡單,在Android6.0,我們可以處處看到這樣的設(shè)計(jì),比如我們的ActivityManagerNavtive這個(gè)類,涉及到Binder通信的基本上都是這種設(shè)計(jì)。不過如果我們想要自己來定義一些遠(yuǎn)程服務(wù)。那這樣的寫法就比較繁瑣,還好Android提供了AIDL,并且在Android8.0之后,我們可以看到與ActivityManagerNavtive相似的許多類已經(jīng)被標(biāo)注過時(shí),因?yàn)锳ndroid系統(tǒng)也使用AIDL了。
AIDL的簡單例子
AIDL的語法與定義一個(gè)java接口非常類似。下面我就定以一個(gè)非常簡單的aidl
IMyAidlInterface.aidl
interface IMyAidlInterface { int getTest(); }
然后基本上就行了,我們重新build之后會(huì)得到一個(gè)
IMyAidlInterface.java文件,這個(gè)文件由aidl工具生成,我們現(xiàn)在使用的基本是AndroidStudio,即使你使用的是Eclipse也沒關(guān)系,這個(gè)文件會(huì)自動(dòng)生成,不需要你操心。但是我們還是得來看看我們生成的這個(gè)文件
public interface IMyAidlInterface extends android.os.IInterface { //抽象的Stub類,繼承自Binder并實(shí)現(xiàn)我們定義的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); } /*這個(gè)Proxy不用說肯定是代理了,其內(nèi)部還有個(gè)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的本質(zhì)與XXXNative之類的類并沒有什么本質(zhì)的不同,不過他的出現(xiàn)使得構(gòu)建一個(gè)Binder服務(wù)的工作大大簡化了。
AIDL的使用詳解
上面用一個(gè)非常簡單的小例子來解密AIDL的本質(zhì),但是在實(shí)際使用AIDL的時(shí)候還有許多地方需要注意。
AIDL支持的數(shù)據(jù)類型 基本數(shù)據(jù)類型(int,long,charmboolean,double等) String和CharSequence List:只支持ArrrayList,并且里面每個(gè)元素的類型必須是AIDL支持的 Map:只支持HashMap,t,并且里面每個(gè)元素的類型必須是AIDL支持的 Parcelable:所有實(shí)現(xiàn)Parcelable接口的對象 AIDL:所有的AIDL接口本身也可以在AIDL文件中使用
以上6種數(shù)據(jù)類型就是AIDL所支持的所有類型,其中自定義的Parcel對象和AIDL對象必須要顯示import進(jìn)來,不管他們是否和當(dāng)前的AIDL文件位于同一個(gè)包內(nèi)。
另外一個(gè)需要注意的地方是如果我們在AIDL中使用了自定義的Parcelable接口的對象,那么我們必須新建一個(gè)和它同名的AIDL文件,并在其中聲明它為Parcelable類型。
如下例
[IBookManager.aidl]
package com.ryg.chapter_2.aidl; /*這里顯示import*/ import com.ryg.chapter_2.aidl.Book; interface IBookManager { //這里我們使用了自定義的Parcelable對象 List<Book> getBookList(); void addBook(in Book book); }
這里我們新建一個(gè)與Book同名的AIDL文件并聲明
[Book.aidl]
package com.ryg.chapter_2.aidl; parcelable Book;
定向tag
定向tag:這是一個(gè)極易被忽略的點(diǎn)——這里的“被忽略”指的不是大家都不知道,而是很少人會(huì)正確的使用它。
AIDL中的定向 tag 表示了在跨進(jìn)程通信中數(shù)據(jù)的流向,其中 in 表示數(shù)據(jù)只能由客戶端流向服務(wù)端, out 表示數(shù)據(jù)只能由服務(wù)端流向客戶端,而 inout 則表示數(shù)據(jù)可在服務(wù)端與客戶端之間雙向流通。其中,數(shù)據(jù)流向是針對在客戶端中的那個(gè)傳入方法的對象而言的。in 為定向 tag 的話表現(xiàn)為服務(wù)端將會(huì)接收到一個(gè)那個(gè)對象的完整數(shù)據(jù),但是客戶端的那個(gè)對象不會(huì)因?yàn)榉?wù)端對傳參的修改而發(fā)生變動(dòng);out 的話表現(xiàn)為服務(wù)端將會(huì)接收到那個(gè)對象的的空對象,但是在服務(wù)端對接收到的空對象有任何修改之后客戶端將會(huì)同步變動(dòng);inout 為定向 tag 的情況下,服務(wù)端將會(huì)接收到客戶端傳來對象的完整信息,并且客戶端將會(huì)同步服務(wù)端對該對象的任何變動(dòng)。
另外,Java 中的基本類型和 String ,CharSequence 的定向 tag 默認(rèn)且只能是 in 。還有,請注意,請不要濫用定向 tag ,而是要根據(jù)需要選取合適的——要是不管三七二十一,全都一上來就用 inout ,等工程大了系統(tǒng)的開銷就會(huì)大很多——因?yàn)榕帕姓韰?shù)的開銷是很昂貴的。
所有的非基本參數(shù)都需要一個(gè)定向tag來指出數(shù)據(jù)的流向,不管是 in , out , 還是 inout 。基本參數(shù)的定向tag默認(rèn)是并且只能是 in 。
本篇總結(jié)
我們本篇詳細(xì)分析了ServiceManager,ServiceManager并沒有使用復(fù)雜的類結(jié)構(gòu),他直接與Binder驅(qū)動(dòng)設(shè)備交互達(dá)到IPC通信的目的。感謝你對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。