日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android Binder机制(1501210451 张志康)

發(fā)布時間:2025/3/15 Android 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android Binder机制(1501210451 张志康) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文主要分析native層和Java層的Android binder通信機制。

binder是Android最為常見的進程通信機制之一,其驅(qū)動和通信庫是binder的核心,分別由C和C++編寫,應用程序通過JNI同底層庫進行關(guān)聯(lián),也就是native層驅(qū)動和通信庫通過Java層包裝后被Java層調(diào)用。

源代碼網(wǎng)址:http://androidxref.com/4.2_r1/

參考博客:http://blog.csdn.net/coding_glacier/article/details/7520199

一、native層整體通信流程

  • 通信流程概要

    在探究binder通信流程之前,首先我們需要了解Binder機制的四個組件:Client、Server、Service Manager和Binder驅(qū)動程序。關(guān)系如圖:

    應用程序最終目的是完成Client組件和Server組件之間的通信。ServiceManger對于大家而言是一個公共接入點,0便是ServiceManger的句柄值。

    從表面看通信建立的流程便是注冊和獲取的過程: 1、client通過參數(shù)(Parcel包)傳遞進行通信請求;

    2、在收到通信請求時,Server組件需要通過0這個句柄值訪問ServiceManger,在ServiceManger中注冊一個binder實體。并關(guān)聯(lián)一個字符串;

    3、Client組件通過0這個標識去訪問ServiceManger,通過一個字符去查詢Server組件的引用,此ServiceManger將Server注冊的binder實體的一個引用傳遞給Client端,此時client便可根據(jù)這個引用同server進行通信了。

    由以上可知,在收到請求時server將一個binder實體傳遞給C進程,而client得到的只是binder的一個引用,進而調(diào)用binder實體的函數(shù)。BpBinder和BBinder分別代表binder 的引用和實體,它們均繼承自IBinder類。

    在描述具體流程之前我們先來了解binder通信中需要用到的三個主要基類:

    1.基類IInterface: 為server端提供接口,它的子類聲明了service能夠?qū)崿F(xiàn)的所有的方法;

    2.基類IBinder BBinder與BpBinder均為IBinder的子類,因此可以看出IBinder定義了binder IPC的通信協(xié)議,BBinder與BpBinder在這個協(xié)議框架內(nèi)進行的收和發(fā)操作,構(gòu)建了基本的binder IPC機制。

    3.基類BpRefBase client端在查詢SM獲得所需的的BpBinder后,BpRefBase負責管理當前獲得的BpBinder實例。

  • ServiceManger

    首先我們來了解一下在通信流程中ServiceManger所做的工作。

    ServiceManger是一個linux級進程,是一個service管理器(service向SM注冊是,service就是一個client,而ServiceManger便是server),即我們前邊提到的:每一個service被使用之前,均要向ServiceManger注冊,客戶端通過查詢ServiceManger是否存在此服務(wù)來獲取service的handle(標識符)。

    ServiceManger入口函數(shù)為: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設(shè)備,在內(nèi)存中為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通信時創(chuàng)建一個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.進入一個死循環(huán),不斷讀取內(nèi)核的binder driver,查看是否有對service的操作請求,如果有調(diào)用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狀態(tài)。

    ProcessState主要完成兩個功能:

    1.創(chuàng)建一個thread負責與內(nèi)核中的binder模塊進行通信(Poolthread)。

    在Binder IPC中,所有進程均會啟動一個thread來負責與binder來直接通信,也就是不斷讀寫binder,這個線程主體是一個IPCThreadState對象(具體介紹見第4節(jié))。

    Poolthread啟動方式:ProcessState::self()->startThreadPool();/frameworks/native/libs/binder/ProcessState.cpp136void ProcessState::startThreadPool(){AutoMutex _l(mLock);` if (!mThreadPoolStarted) {mThreadPoolStarted = true;spawnPooledThread(true);}}

    2.為知道的handle創(chuàng)建一個BpBinder對象,并管理進程中所有的BpBinder對象。

    BpBinder在第一節(jié)已經(jīng)提到,其主要功能是負責client向BD發(fā)送調(diào)用請求的數(shù)據(jù),是client端binder通信的核心,通過調(diào)用transact向BD發(fā)送調(diào)用請求的數(shù)據(jù)。

    ProcessState通過如下函數(shù)獲取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(具體調(diào)用過程見上述源代碼)。

    創(chuàng)建一個BpBinder實例時,回去查詢mHandleToObject,如果對應的handler以及有binder指針,就不再創(chuàng)建,否則創(chuàng)建并插入到mHandlerToObject中(具體代碼見上述的lookupHandleLocked)。

    BpBinder構(gòu)造函數(shù)位于/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);}

    通過此構(gòu)造函數(shù)我們可以發(fā)現(xiàn):BpBinder會將通信中server的handle記錄下來。當有數(shù)據(jù)發(fā)送時,會把數(shù)據(jù)的發(fā)送目標通知BD。

  • IPCThreadState

    IPCThreadState也是一個單例模式,由上邊我們已知每個進程維護一個ProcessState實例,且ProcessState只啟動一個Pool thread,因此一個進程之后啟動一個Pool thread。

    IPCThreadState實際內(nèi)容為:

    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中是否有數(shù)據(jù)可讀,若有,則保存在mIn;不停檢查mOut是否有數(shù)據(jù)需要向BD發(fā)送,若有,則寫入BD。

    根據(jù)第三節(jié)提到的:BpBinder通過調(diào)用transact向BD發(fā)送調(diào)用請求的數(shù)據(jù),也就是說ProcessState中生成的BpBinder實例通過調(diào)用IPCThreadState的transact函數(shù)來向mOut中寫入數(shù)據(jù),這樣的話這個binder IPC過程的client端的調(diào)用請求的發(fā)送過程就講述完畢。

    IPCThreadState有兩個重要的函數(shù),talkWithDriver函數(shù)負責從BD讀寫數(shù)據(jù),executeCommand函數(shù)負責解析并執(zhí)行mIn中的數(shù)據(jù)。

  • 兩個接口類

    1.BpINTERFACE

    client在獲得server端service時,server端向client提供一個接口,client在這個接口基礎(chǔ)上創(chuàng)建一個BpINTERFACE,使用此對象,client端的應用能夠像本地調(diào)用一樣直接調(diào)用server端的方法,而不必關(guān)系binder IPC實現(xiàn)。

    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既實現(xiàn)了service中各方法的本地操作,將每個方法的參數(shù)以Parcel的形式發(fā)送給BD。同時又將BpBinder作為了自己的成員來管理,將BpBinder存儲在mRemote中,BpServiceManager通過調(diào)用BpRefBase的remote()來獲得BpBinder指針。

    2.BnINTERFACE

同樣位于/frameworks/native/include/binder/IInterface.h template<typename INTERFACE>class BnInterface : public INTERFACE, public BBinder{public:virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);virtual const String16& getInterfaceDescriptor() const;protected:virtual IBinder* onAsBinder();};

由代碼可知,BnInterface繼承自INTERFACE、BBinder。

class BBinder : public

IBinder,由此可見,server端的binder操作及狀態(tài)維護是通過BBinder來實現(xiàn)的。BBinder即為binder的本質(zhì)。

3.接口類總結(jié)

由上節(jié)的描述及剛才對于兩個接口類源代碼分析可知:BpBinder是client端用于創(chuàng)建消息發(fā)送的機制,而BBinder是server端用于接口消息的通道。

BpBinder是client創(chuàng)建的用于消息發(fā)送的代理,其transact函數(shù)用于向IPCThreadState發(fā)送消息,通知其有消息要發(fā)送給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函數(shù)執(zhí)行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時需要調(diào)用的函數(shù)。

    具體源碼如下: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,中間經(jīng)歷了一個改變,代碼如下:

    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;……}

    由以上函數(shù)可知,SM只保存了Service binder的handle和name,當client需要和Service通信時,如何才能獲得Service得binder呢?需要由readStrongBinder來完成。

  • readStrongBinder

    Client向server請求時,server向BD發(fā)送一個binder返回給SM(保存handle和name),當IPCThreadState收到由返回的parcel時,client通過這一函數(shù)將這個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;}

    由如上源碼可知:發(fā)現(xiàn)如果server返回的binder類型為BINDER_TYPE_BINDER的話,直接獲取這個binder;如果server返回的binder類型為BINDER_TYPE_HANDLE時,那么需要重新創(chuàng)建一個BpBinder返回給client。Client通過獲得SMhandle來重新構(gòu)建代理binder與server進行通信。

  • 至此,native通信機制已構(gòu)建完畢。

    二、Java層的binder機制

    下邊來解析一下java層對于binder的封裝過程,分四部分來進行介紹:Java層ServiceManager的結(jié)構(gòu)、如何注冊一個Service、如何得到一個Service、Service代理對象方法的過程。

    *ServiceManager的結(jié)構(gòu):

    在Java層,ServiceManager的函數(shù)源碼為:/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()可注冊自己,其傳輸了兩個參數(shù):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表明將此操作請求轉(zhuǎn)發(fā)給了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的轉(zhuǎn)換,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對象,調(diào)用其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中,調(diào)用transact()方法送出,并將當前操作標記為ADD_SERVICE_TRANSACTION,根據(jù)上一章提到的內(nèi)容,transact()便會調(diào)用到BpBinder中,此時便進入到native層的使用,這部分內(nèi)容已經(jīng)在上一章節(jié)分析完畢,具體流程圖如下:?

    • 客戶端得到一個Service:

      主要流程如下:通過Java層的ServerManager得到相應的Service,然后通過asInterface()將得到的對象轉(zhuǎn)為客戶端可直接調(diào)用的代理對象,然后調(diào)用代理對象的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;}可見,調(diào)用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請求被轉(zhuǎn)交給native層,由上一章分析可知,native層得到請求后會將目標Service的BpBinder返回給客戶端,得到BpBinder對象后,通過asInterface()得到一個Proxy對象,客戶端便通過這個代理類調(diào)用服務(wù)端定義的各種方法。具體客戶端得到Service的流程圖如下:?

    三、總結(jié)

    Binder通信整體流程圖如下:


    原文地址:https://mobile100.gitbooks.io/android/content/paper/android_binderji_523628_1501210451_zhang_zhi_5eb72.html

    總結(jié)

    以上是生活随笔為你收集整理的Android Binder机制(1501210451 张志康)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。