Android Binder机制(1501210451 张志康)
本文主要分析native層和Java層的Android binder通信機制。
binder是Android最為常見的進程通信機制之一,其驅動和通信庫是binder的核心,分別由C和C++編寫,應用程序通過JNI同底層庫進行關聯,也就是native層驅動和通信庫通過Java層包裝后被Java層調用。
源代碼網址:http://androidxref.com/4.2_r1/
參考博客:http://blog.csdn.net/coding_glacier/article/details/7520199
一、native層整體通信流程
-
通信流程概要
在探究binder通信流程之前,首先我們需要了解Binder機制的四個組件:Client、Server、Service Manager和Binder驅動程序。關系如圖:
應用程序最終目的是完成Client組件和Server組件之間的通信。ServiceManger對于大家而言是一個公共接入點,0便是ServiceManger的句柄值。
從表面看通信建立的流程便是注冊和獲取的過程: 1、client通過參數(Parcel包)傳遞進行通信請求;
2、在收到通信請求時,Server組件需要通過0這個句柄值訪問ServiceManger,在ServiceManger中注冊一個binder實體。并關聯一個字符串;
3、Client組件通過0這個標識去訪問ServiceManger,通過一個字符去查詢Server組件的引用,此ServiceManger將Server注冊的binder實體的一個引用傳遞給Client端,此時client便可根據這個引用同server進行通信了。
由以上可知,在收到請求時server將一個binder實體傳遞給C進程,而client得到的只是binder的一個引用,進而調用binder實體的函數。BpBinder和BBinder分別代表binder 的引用和實體,它們均繼承自IBinder類。
在描述具體流程之前我們先來了解binder通信中需要用到的三個主要基類:
1.基類IInterface: 為server端提供接口,它的子類聲明了service能夠實現的所有的方法;
2.基類IBinder BBinder與BpBinder均為IBinder的子類,因此可以看出IBinder定義了binder IPC的通信協議,BBinder與BpBinder在這個協議框架內進行的收和發操作,構建了基本的binder IPC機制。
3.基類BpRefBase client端在查詢SM獲得所需的的BpBinder后,BpRefBase負責管理當前獲得的BpBinder實例。
-
ServiceManger
首先我們來了解一下在通信流程中ServiceManger所做的工作。
ServiceManger是一個linux級進程,是一個service管理器(service向SM注冊是,service就是一個client,而ServiceManger便是server),即我們前邊提到的:每一個service被使用之前,均要向ServiceManger注冊,客戶端通過查詢ServiceManger是否存在此服務來獲取service的handle(標識符)。
ServiceManger入口函數為:service_manager.c位于:/frameworks/base/cmds/servicemanager/int main(int argc, char **argv){struct binder_state *bs;void *svcmgr = BINDER_SERVICE_MANAGER;bs = binder_open(128*1024);if (binder_become_context_manager(bs)) {ALOGE("cannot become context manager (%s)\n", strerror(errno));return -1;}svcmgr_handle = svcmgr;binder_loop(bs, svcmgr_handler);return 0;}主要工作:1. 初始化binder,打開/dev/binder設備,在內存中為binder映射128Kb空間。bs = binder_open(128*1024);其中binder_open位于binder.c中,源代碼為:struct binder_state *binder_open(unsigned mapsize){struct binder_state *bs;bs = malloc(sizeof(*bs));if (!bs) {errno = ENOMEM;return 0;}bs->fd = open("/dev/binder", O_RDWR);……return 0;}2. 指定SM對于代理binder的handle為0,即client嘗試同SM通信時創建一個handle為0的代理binder。void *svcmgr = BINDER_SERVICE_MANAGER;svcmgr_handle = svcmgr;其中BINDER_SERVICE_MANAGER在binder.h中被指定為0:#define BINDER_SERVICE_MANAGER ((void*) 0)3. 通知binder driver(BD)使SM成為BD的context manager;if (binder_become_context_manager(bs)) {LOGE("cannot become context manager (%s)/n", strerror(errno));return -1;}binder_become_context_manager(bs)源碼位于binder.c中:int binder_become_context_manager(struct binder_state *bs){return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);}4.進入一個死循環,不斷讀取內核的binder driver,查看是否有對service的操作請求,如果有調用svcmgr_handler來處理請求操作:binder_loop(bs, svcmgr_handler);binder_loop(,)源碼位于binder.c中:void binder_loop(struct binder_state *bs, binder_handler func){int res;struct binder_write_read bwr;unsigned readbuf[32];……}}5.維護一個svclist列表來存儲service的信息。源碼位于service_manager.c:int svcmgr_handler(struct binder_state *bs,struct binder_txn *txn,struct binder_io *msg,struct binder_io *reply){struct svcinfo *si;……} -
ProcessState
ProcessState是每個進程在使用Binder通信時都需要維護的,用來描述當前進程的binder狀態。
ProcessState主要完成兩個功能:
1.創建一個thread負責與內核中的binder模塊進行通信(Poolthread)。
在Binder IPC中,所有進程均會啟動一個thread來負責與binder來直接通信,也就是不斷讀寫binder,這個線程主體是一個IPCThreadState對象(具體介紹見第4節)。
Poolthread啟動方式:ProcessState::self()->startThreadPool();/frameworks/native/libs/binder/ProcessState.cpp136void ProcessState::startThreadPool(){AutoMutex _l(mLock);` if (!mThreadPoolStarted) {mThreadPoolStarted = true;spawnPooledThread(true);}}2.為知道的handle創建一個BpBinder對象,并管理進程中所有的BpBinder對象。
BpBinder在第一節已經提到,其主要功能是負責client向BD發送調用請求的數據,是client端binder通信的核心,通過調用transact向BD發送調用請求的數據。
ProcessState通過如下函數獲取BpBinder對象:
/frameworks/native/libs/binder/ProcessState.cppsp<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);……return result;}ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle){const size_t N=mHandleToObject.size();if (N <= (size_t)handle) {handle_entry e;e.binder = NULL;e.refs = NULL;status_t err = mHandleToObject.insertAt(e, N, handle+1-N);if (err < NO_ERROR) return NULL;}return &mHandleToObject.editItemAt(handle);}在獲取BpBinder對象的過程中,ProcessState會維護一個BpBinder的vecto:mHandleToObject(具體調用過程見上述源代碼)。
創建一個BpBinder實例時,回去查詢mHandleToObject,如果對應的handler以及有binder指針,就不再創建,否則創建并插入到mHandlerToObject中(具體代碼見上述的lookupHandleLocked)。
BpBinder構造函數位于/frameworks/native/libs/binder/BpBinder.cpp:
BpBinder::BpBinder(int32_t handle): mHandle(handle), mAlive(1), mObitsSent(0), mObituaries(NULL){ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);extendObjectLifetime(OBJECT_LIFETIME_WEAK);IPCThreadState::self()->incWeakHandle(handle);}通過此構造函數我們可以發現:BpBinder會將通信中server的handle記錄下來。當有數據發送時,會把數據的發送目標通知BD。
-
IPCThreadState
IPCThreadState也是一個單例模式,由上邊我們已知每個進程維護一個ProcessState實例,且ProcessState只啟動一個Pool thread,因此一個進程之后啟動一個Pool thread。
IPCThreadState實際內容為:
void IPCThreadState::joinThreadPool(bool isMain){LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); set_sched_policy(mMyThreadId, SP_FOREGROUND); status_t result;do {int32_t cmd;if (mIn.dataPosition() >= mIn.dataSize()) {size_t numPending = mPendingWeakDerefs.size();if (numPending > 0) {for (size_t i = 0; i < numPending; i++) {RefBase::weakref_type* refs = mPendingWeakDerefs[i];refs->decWeak(mProcess.get());}mPendingWeakDerefs.clear();}numPending = mPendingStrongDerefs.size();if (numPending > 0) {for (size_t i = 0; i < numPending; i++) {BBinder* obj = mPendingStrongDerefs[i];obj->decStrong(mProcess.get());}mPendingStrongDerefs.clear();}}result = talkWithDriver();if (result >= NO_ERROR) {size_t IN = mIn.dataAvail();if (IN < sizeof(int32_t)) continue;cmd = mIn.readInt32();IF_LOG_COMMANDS() {alog << "Processing top-level Command: "<< getReturnString(cmd) << endl;}result = executeCommand(cmd);}if(result == TIMED_OUT && !isMain) {break;}} while (result != -ECONNREFUSED && result != -EBADF);LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",(void*)pthread_self(), getpid(), (void*)result);mOut.writeInt32(BC_EXIT_LOOPER);talkWithDriver(false);}ProcessState中有2個Parcel成員(mIn和mOut),由以上代碼可見,Pool Thread會不斷查詢BD中是否有數據可讀,若有,則保存在mIn;不停檢查mOut是否有數據需要向BD發送,若有,則寫入BD。
根據第三節提到的:BpBinder通過調用transact向BD發送調用請求的數據,也就是說ProcessState中生成的BpBinder實例通過調用IPCThreadState的transact函數來向mOut中寫入數據,這樣的話這個binder IPC過程的client端的調用請求的發送過程就講述完畢。
IPCThreadState有兩個重要的函數,talkWithDriver函數負責從BD讀寫數據,executeCommand函數負責解析并執行mIn中的數據。
-
兩個接口類
1.BpINTERFACE
client在獲得server端service時,server端向client提供一個接口,client在這個接口基礎上創建一個BpINTERFACE,使用此對象,client端的應用能夠像本地調用一樣直接調用server端的方法,而不必關系binder IPC實現。
BpINTERFACE原型如下:/frameworks/native/include/binder/IInterface.h template<typename INTERFACE>class BpInterface : public INTERFACE, public BpRefBase{public:BpInterface(const sp<IBinder>& remote);protected:virtual IBinder* onAsBinder();};可見,BpINTERFACE繼承自INTERFACE、BpRefBase。
BpINTERFACE既實現了service中各方法的本地操作,將每個方法的參數以Parcel的形式發送給BD。同時又將BpBinder作為了自己的成員來管理,將BpBinder存儲在mRemote中,BpServiceManager通過調用BpRefBase的remote()來獲得BpBinder指針。
2.BnINTERFACE
由代碼可知,BnInterface繼承自INTERFACE、BBinder。
class BBinder : public
IBinder,由此可見,server端的binder操作及狀態維護是通過BBinder來實現的。BBinder即為binder的本質。
3.接口類總結
由上節的描述及剛才對于兩個接口類源代碼分析可知:BpBinder是client端用于創建消息發送的機制,而BBinder是server端用于接口消息的通道。
BpBinder是client創建的用于消息發送的代理,其transact函數用于向IPCThreadState發送消息,通知其有消息要發送給BD,部分源代碼如下:
/frameworks/native/libs/binder/BpBinder.cpp status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {if (mAlive) {status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);if (status == DEAD_OBJECT) mAlive = 0;return status;}return DEAD_OBJECT;}default:return UNKNOWN_TRANSACTION;} }由BBinder的源碼可知,其作用是當IPCThreadState收到BD消息時,通過transact方法將其傳遞給它的子類BnSERVICE的onTransact函數執行server端的操作。部分源碼如下:
/frameworks/native/libs/binder/Binder.cppstatus_t BBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){data.setDataPosition(0); status_t err = NO_ERROR;switch (code) {case PING_TRANSACTION:reply->writeInt32(pingBinder());break;default:err = onTransact(code, data, reply, flags);break;}if (reply != NULL) {reply->setDataPosition(0);}return err;}由上述可知,BpINTERFACE,BnINTERFACE均來自同一接口類IINTERFACE,由此保證了service方法在C/S兩端的一致性。
- writeStrongBinder和readStrongBinder
writeStrongBinder是client將一個binder傳送給server時需要調用的函數。
具體源碼如下:status_t Parcel::writeStrongBinder(const sp<IBinder>& val){return flatten_binder(ProcessState::self(), val, this);}flatten_binder為:status_t flatten_binder(const sp<ProcessState>& proc,const sp<IBinder>& binder, Parcel* out){flat_binder_object obj;obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;if (binder != NULL) {IBinder *local = binder->localBinder();if (!local) {BpBinder *proxy = binder->remoteBinder();if (proxy == NULL) {LOGE("null proxy");}const int32_t handle = proxy ? proxy->handle() : 0;obj.type = BINDER_TYPE_HANDLE;obj.handle = handle;obj.cookie = NULL;} else {obj.type = BINDER_TYPE_BINDER;obj.binder = local->getWeakRefs();obj.cookie = local;}} else {obj.type = BINDER_TYPE_BINDER;obj.binder = NULL;obj.cookie = NULL;} return finish_flatten_binder(binder, obj, out);}下邊舉例說明,addService源碼為:
/frameworks/native/libs/binder/IServiceManager.cppvirtual status_t addService(const String16& name, const sp<IBinder>& service,bool allowIsolated){Parcel data, reply;data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());data.writeString16(name);data.writeStrongBinder(service);data.writeInt32(allowIsolated ? 1 : 0);status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);return err == NO_ERROR ? reply.readExceptionCode() : err;}由上述代碼塊可知,寫入到parcel的binder類型為BINDER_TYPE_BINDER,然而SM收到的Service的binder類型必須為BINDER_TYPE_HANDLE才會將其添加到svclist中,因此說,addService開始傳遞的binder類型為BINDER_TYPE_BINDER然而SM收到的binder類型為BINDER_TYPE_HANDLE,中間經歷了一個改變,代碼如下:
drivers/staging/android/Binder.cstatic void binder_transaction(struct binder_proc *proc,struct binder_thread *thread,struct binder_transaction_data *tr, int reply){……if (fp->type == BINDER_TYPE_BINDER)fp->type = BINDER_TYPE_HANDLE;elsefp->type = BINDER_TYPE_WEAK_HANDLE;fp->handle = ref->desc;……}由以上函數可知,SM只保存了Service binder的handle和name,當client需要和Service通信時,如何才能獲得Service得binder呢?需要由readStrongBinder來完成。
readStrongBinder
Client向server請求時,server向BD發送一個binder返回給SM(保存handle和name),當IPCThreadState收到由返回的parcel時,client通過這一函數將這個server返回給SM的binder讀出。
源碼為:/frameworks/native/libs/binder/Parcel.cppsp<IBinder> Parcel::readStrongBinder() const{sp<IBinder> val;unflatten_binder(ProcessState::self(), *this, &val);return val;}unflatten_binder為:status_t unflatten_binder(const sp<ProcessState>& proc,const Parcel& in, sp<IBinder>* out){const flat_binder_object* flat = in.readObject(false);if (flat) {switch (flat->type) {case BINDER_TYPE_BINDER:*out = static_cast<IBinder*>(flat->cookie);return finish_unflatten_binder(NULL, *flat, in);case BINDER_TYPE_HANDLE:*out = proc->getStrongProxyForHandle(flat->handle);return finish_unflatten_binder(static_cast<BpBinder*>(out->get()), *flat, in);}}return BAD_TYPE;}由如上源碼可知:發現如果server返回的binder類型為BINDER_TYPE_BINDER的話,直接獲取這個binder;如果server返回的binder類型為BINDER_TYPE_HANDLE時,那么需要重新創建一個BpBinder返回給client。Client通過獲得SMhandle來重新構建代理binder與server進行通信。
至此,native通信機制已構建完畢。
二、Java層的binder機制
下邊來解析一下java層對于binder的封裝過程,分四部分來進行介紹:Java層ServiceManager的結構、如何注冊一個Service、如何得到一個Service、Service代理對象方法的過程。
*ServiceManager的結構:
在Java層,ServiceManager的函數源碼為:/frameworks/base/core/java/android/os/ServiceManager.javapublic final class ServiceManager {} public static IBinder getService(String name) {}public static void addService(String name, IBinder service) {}public static void addService(String name, IBinder service, boolean allowIsolated) {}public static IBinder checkService(String name) {}public static String[] listServices() throws RemoteException {}public static void initServiceCache(Map<String, IBinder> cache) {}由源碼可知,ServiceManager沒有繼承其他類,下邊我們來分析ServiceManager管理binder通信的流程。
-
在Java層注冊Service:
通過ServiceManager的addService()可注冊自己,其傳輸了兩個參數:String name, IBinder service,分別為name和BBinder的子類對象,跟native層ServiceManager中Service的注冊方法相一致。
具體源碼如下:public static void addService(String name, IBinder service) {try {getIServiceManager().addService(name, service, false);} catch (RemoteException e) {Log.e(TAG, "error in addService", e);}}getIServiceManager().addService表明將此操作請求轉發給了getIServiceManager(),返回一個IServiceManger類型的sServiceManager對象,源碼如下:
private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());return sServiceManager;}BinderInternal.getContextObject在native層得到BpBinder對象。
ServiceManagerNative.asInterface 將BpBinder封裝為Java層可用的ServiceManagerProxy對象。
下面來通過源碼具體分析BpBinder封裝為ServiceManagerProxy的過程:
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);}由源碼可知,通過asInterface的轉換,BpBinder對象生成了ServiceManagerProxy對象。也就是說getIServiceManager()得到的是一個ServiceManagerProxy對象,那么ServiceManagerProxy又是什么,下邊來具體分析一下。
class ServiceManagerProxy implements IServiceManager {public ServiceManagerProxy(IBinder remote) {mRemote = remote;}public IBinder asBinder() {return mRemote;}public IBinder getService(String name) throws RemoteException {}public IBinder checkService(String name) throws RemoteException {}public void addService(String name, IBinder service, boolean allowIsolated)throws RemoteException {}public String[] listServices() throws RemoteException {}public void setPermissionController(IPermissionController controller)throws RemoteException {}private IBinder mRemote;}由源碼可知,ServiceManagerProxy繼承自IServiceManager,提供add、get、list、check等方法。由以上分析可知,通過getIServiceManager的便可得到ServiceManagerProxy對象,調用其addService方法便可進行注冊,addService源碼如下:
public void addService(String name, IBinder service, boolean allowIsolated)throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IServiceManager.descriptor);data.writeString(name);data.writeStrongBinder(service);data.writeInt(allowIsolated ? 1 : 0);mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);reply.recycle();data.recycle();}可知,將name和Service對象封裝到Parcel中,調用transact()方法送出,并將當前操作標記為ADD_SERVICE_TRANSACTION,根據上一章提到的內容,transact()便會調用到BpBinder中,此時便進入到native層的使用,這部分內容已經在上一章節分析完畢,具體流程圖如下:?
-
客戶端得到一個Service:
主要流程如下:通過Java層的ServerManager得到相應的Service,然后通過asInterface()將得到的對象轉為客戶端可直接調用的代理對象,然后調用代理對象的updateAdnRecordsEfBySearch()方法。
具體分析如下:首先,通過ServerManager得到相應的BpBinder對象。源碼位于ServerManager.java中public static IBinder getService(String name) {try {IBinder service = sCache.get(name);if (service != null) {return service;} else {return getIServiceManager().getService(name);}} catch (RemoteException e) {Log.e(TAG, "error in getService", e);}return null;}可見,調用getIServiceManager()對象的getService()方法,代碼如下。private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());return sServiceManager;}
可知通過IServiceManager得到的是一個ServiceManager在Java層的代理對象,下邊來分析此代理對象的getService( )方法。
/frameworks/base/core/java/android/os/ServiceManagerNative.javapublic IBinder getService(String name) throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IServiceManager.descriptor);data.writeString(name);mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);IBinder binder = reply.readStrongBinder();reply.recycle();data.recycle();return binder;}可見,getService請求被轉交給native層,由上一章分析可知,native層得到請求后會將目標Service的BpBinder返回給客戶端,得到BpBinder對象后,通過asInterface()得到一個Proxy對象,客戶端便通過這個代理類調用服務端定義的各種方法。具體客戶端得到Service的流程圖如下:?
三、總結
Binder通信整體流程圖如下:
原文地址:https://mobile100.gitbooks.io/android/content/paper/android_binderji_523628_1501210451_zhang_zhi_5eb72.html
總結
以上是生活随笔為你收集整理的Android Binder机制(1501210451 张志康)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Binder Proce
- 下一篇: 应用层的AIDL用法(原)