標籤:off ctf == 函數指標 sub final flags tom errno
該文章是一個系列文章,是本人在Android開發的漫漫長途上的一點感想和記錄,我會盡量按照先易後難的順序進行編寫該系列。該系列引用了《Android開發藝術探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相關知識,另外也借鑒了其他的優質部落格,在此向各位大神表示感謝,膜拜!!!另外,本系列文章知識可能需要有一定Android開發基礎和項目經驗的同學才能更好理解,也就是說該系列文章面向的是Android中進階開發工程師。
前言
上一次還不如不說去面試了呢,估計是掛了,資料結構與演算法方面雖然面試前突擊了一波,但是時間太短,當時學的也不好。另外Android的一些知識也不是很瞭解。不過這也加大了我寫部落格的動力。許多知識總覺得自己掌握的還挺好,不過一問到比較細節的方面就不太清楚了。所以寫這整個部落格的目的也是加深自己的知識,培養自己的溝通能力,和大家一起學習吧。
好了,閑話少說,我們這一篇先解決上一篇中遺留的問題,之後有時間的話,我把這次的面試經曆單寫一篇部落格,和大家共勉。
本篇我們來看一下ServiceManager。上一篇中沒怎麼說它,ServiceManager作為Android系統服務的大管家。我們還是有必要來看一下它的。
ServiceManager概述
ServiceManager是Android世界中所有重要系統服務的大管家。像前文提到的AMS(ActivityManagerService),還有許多以後可能分析到的PackageManagerService等等服務都需要像ServiceManager中註冊。那麼為何需要一個ServiceManager呢,其重要作用何在呢?私認為有以下幾點:
- ServiceManager能集中管理系統內的所有服務,它能施加許可權控制,並不是任何進程都能註冊服務的。
- 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