之前幾篇博客我們介紹了傳統Binder的使用方法,包括c層和java層,這篇博客我們主要介紹下ProcessState和IPCThreadState類的相關方法。
一、正常demon binder調用流程
在一個傳統的demon中,如果我們要使用Binder通信,代碼大致如下:
[cpp]?view plaincopy
int?main(int?argc,?char**?argv)???? ?{???? ?????sp<ProcessState>?proc(ProcessState::self());?? ?????MediaPlayerService::instantiate();???? ?????ProcessState::self()->startThreadPool();???? ?????IPCThreadState::self()->joinThreadPool();???? ?}????
1.1 ProcessState::self函數
上面先調用了ProcessState的self方法,
[cpp]?view plaincopy
sp<ProcessState>?ProcessState::self()?? {?? ????Mutex::Autolock?_l(gProcessMutex);?? ????if?(gProcess?!=?NULL)?{?? ????????return?gProcess;?? ????}?? ????gProcess?=?new?ProcessState;?? ????return?gProcess;?? }??
典型的單例模式,我們先來看看ProcessState的構造函數
[cpp]?view plaincopy
ProcessState::ProcessState()?? ????:?mDriverFD(open_driver())?? ????,?mVMStart(MAP_FAILED)?? ????,?mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)?? ????,?mThreadCountDecrement(PTHREAD_COND_INITIALIZER)?? ????,?mExecutingThreadsCount(0)?? ????,?mMaxThreads(DEFAULT_MAX_BINDER_THREADS)?? ????,?mManagesContexts(false)?? ????,?mBinderContextCheckFunc(NULL)?? ????,?mBinderContextUserData(NULL)?? ????,?mThreadPoolStarted(false)?? ????,?mThreadPoolSeq(1)?? {?? ????if?(mDriverFD?>=?0)?{?? ?????????? ?????????? ?????????? #if?!defined(HAVE_WIN32_IPC)?? ?????????? ????????mVMStart?=?mmap(0,?BINDER_VM_SIZE,?PROT_READ,?MAP_PRIVATE?|?MAP_NORESERVE,?mDriverFD,?0);?? ????????if?(mVMStart?==?MAP_FAILED)?{?? ?????????????? ????????????ALOGE("Using?/dev/binder?failed:?unable?to?mmap?transaction?memory.\n");?? ????????????close(mDriverFD);?? ????????????mDriverFD?=?-1;?? ????????}?? #else?? ????????mDriverFD?=?-1;?? #endif?? ????}?? ?? ????LOG_ALWAYS_FATAL_IF(mDriverFD?<?0,?"Binder?driver?could?not?be?opened.??Terminating.");?? }??
我們在賦值的時候有如下函數 mDriverFD(open_driver())
[cpp]?view plaincopy
static?int?open_driver()?? {?? ????int?fd?=?open("/dev/binder",?O_RDWR);?? ????if?(fd?>=?0)?{?? ????????fcntl(fd,?F_SETFD,?FD_CLOEXEC);?? ????????int?vers?=?0;?? ????????status_t?result?=?ioctl(fd,?BINDER_VERSION,?&vers);?? ????????if?(result?==?-1)?{?? ????????????ALOGE("Binder?ioctl?to?obtain?version?failed:?%s",?strerror(errno));?? ????????????close(fd);?? ????????????fd?=?-1;?? ????????}?? ????????if?(result?!=?0?||?vers?!=?BINDER_CURRENT_PROTOCOL_VERSION)?{?? ????????????ALOGE("Binder?driver?protocol?does?not?match?user?space?protocol!");?? ????????????close(fd);?? ????????????fd?=?-1;?? ????????}?? ????????size_t?maxThreads?=?DEFAULT_MAX_BINDER_THREADS;?? ????????result?=?ioctl(fd,?BINDER_SET_MAX_THREADS,?&maxThreads);?? ????????if?(result?==?-1)?{?? ????????????ALOGE("Binder?ioctl?to?set?max?threads?failed:?%s",?strerror(errno));?? ????????}?? ????}?else?{?? ????????ALOGW("Opening?'/dev/binder'?failed:?%s\n",?strerror(errno));?? ????}?? ????return?fd;?? }??
上面這個函數打開了binder驅動節點,然后設置了binder線程數量。binder驅動打開的fd保存在mDriverFD 中。
具體關閉Binder中線程的問題,可以參考Binder通信過程中的用戶空間線程池的管理?這篇博文。
上面函數中還通過mmap來把設備文件/dev/binder映射到內存中。
1.2 instantiate函數
而instantiate函數一般是將service注冊到serviceManager中去。
[cpp]?view plaincopy
void?MediaPlayerService::instantiate()?{???? ?????defaultServiceManager()->addService(???? ?????????????String16("media.player"),?new?MediaPlayerService());???? ?}????
1.3 ProcessState::startThreadPool函數
我們再來看startThreadPool函數
[cpp]?view plaincopy
void?ProcessState::startThreadPool()?? {?? ????AutoMutex?_l(mLock);?? ????if?(!mThreadPoolStarted)?{?? ????????mThreadPoolStarted?=?true;?? ????????spawnPooledThread(true);?? ????}?? }??
而在spawnPooledThread函數中,先建了一個線程PoolThread
[cpp]?view plaincopy
void?ProcessState::spawnPooledThread(bool?isMain)?? {?? ????if?(mThreadPoolStarted)?{?? ????????String8?name?=?makeBinderThreadName();?? ????????ALOGV("Spawning?new?pooled?thread,?name=%s\n",?name.string());?? ????????sp<Thread>?t?=?new?PoolThread(isMain);?? ????????t->run(name.string());?? ????}?? }??
我們看下這個PoolThread線程,最后還是調用了IPCThreadState::self()->joinThreadPool(mIsMain);
[cpp]?view plaincopy
class?PoolThread?:?public?Thread?? {?? public:?? ????PoolThread(bool?isMain)?? ????????:?mIsMain(isMain)?? ????{?? ????}?? ?????? protected:?? ????virtual?bool?threadLoop()?? ????{?? ????????IPCThreadState::self()->joinThreadPool(mIsMain);?? ????????return?false;?? ????}?? ?????? ????const?bool?mIsMain;?? };??
我們再來看看IPCThreadState的joinThreadPool函數,先看看其定義,參數默認是true。
[cpp]?view plaincopy
void????????????????joinThreadPool(bool?isMain?=?true);??
也就是在main函數中
???? ProcessState::self()->startThreadPool();??
???? IPCThreadState::self()->joinThreadPool();
這兩個函數都是調用了joinThreadPool函數且參數都是true,只是上面的函數新建了一個thread。
1.4 IPCThreadState::joinThreadPool函數
我們再來看看這個函數 joinThreadPool:
[cpp]?view plaincopy
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?{?? ????????processPendingDerefs();?? ?????????? ????????result?=?getAndExecuteCommand();?? ?? ????????if?(result?<?NO_ERROR?&&?result?!=?TIMED_OUT?&&?result?!=?-ECONNREFUSED?&&?result?!=?-EBADF)?{?? ????????????ALOGE("getAndExecuteCommand(fd=%d)?returned?unexpected?error?%d,?aborting",?? ??????????????????mProcess->mDriverFD,?result);?? ????????????abort();?? ????????}?? ?????????? ?????????? ?????????? ????????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);?? }??
這個函數就是一個死循環,不斷從驅動獲取數據,我們來看getAndExecuteCommand函數:
[cpp]?view plaincopy
status_t?IPCThreadState::getAndExecuteCommand()?? {?? ????status_t?result;?? ????int32_t?cmd;?? ?? ????result?=?talkWithDriver();?? ????if?(result?>=?NO_ERROR)?{?? ????????size_t?IN?=?mIn.dataAvail();?? ????????if?(IN?<?sizeof(int32_t))?return?result;?? ????????cmd?=?mIn.readInt32();?? ????????IF_LOG_COMMANDS()?{?? ????????????alog?<<?"Processing?top-level?Command:?"?? ?????????????????<<?getReturnString(cmd)?<<?endl;?? ????????}?? ?? ????????pthread_mutex_lock(&mProcess->mThreadCountLock);?? ????????mProcess->mExecutingThreadsCount++;?? ????????pthread_mutex_unlock(&mProcess->mThreadCountLock);?? ?? ????????result?=?executeCommand(cmd);?? ?? ????????pthread_mutex_lock(&mProcess->mThreadCountLock);?? ????????mProcess->mExecutingThreadsCount--;?? ????????pthread_cond_broadcast(&mProcess->mThreadCountDecrement);?? ????????pthread_mutex_unlock(&mProcess->mThreadCountLock);?? ?? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ????????set_sched_policy(mMyThreadId,?SP_FOREGROUND);?? ????}?? ?? ????return?result;?? }??
getAndExecuteCommand函數中先調用talkWithDriver就是從binder驅動獲取數據,然后調用executeCommand執行命令
[cpp]?view plaincopy
status_t?IPCThreadState::executeCommand(int32_t?cmd)?? {?? ????BBinder*?obj;?? ????RefBase::weakref_type*?refs;?? ????status_t?result?=?NO_ERROR;?? ?????? ????switch?((uint32_t)cmd)?{?? ????case?BR_ERROR:?? ????????result?=?mIn.readInt32();?? ????????break;?? ?????????? ????case?BR_OK:?? ????????break;?? ?????????? ......?? ?????? ????case?BR_TRANSACTION:?? ????????{?? ????????????binder_transaction_data?tr;?? ????????????result?=?mIn.read(&tr,?sizeof(tr));?? ????????????ALOG_ASSERT(result?==?NO_ERROR,?? ????????????????"Not?enough?command?data?for?brTRANSACTION");?? ????????????if?(result?!=?NO_ERROR)?break;?? ?????????????? ????????????Parcel?buffer;?? ????????????buffer.ipcSetDataReference(?? ????????????????reinterpret_cast<const?uint8_t*>(tr.data.ptr.buffer),?? ????????????????tr.data_size,?? ????????????????reinterpret_cast<const?binder_size_t*>(tr.data.ptr.offsets),?? ????????????????tr.offsets_size/sizeof(binder_size_t),?freeBuffer,?this);?? ?????????????? ????????????const?pid_t?origPid?=?mCallingPid;?? ????????????const?uid_t?origUid?=?mCallingUid;?? ????????????const?int32_t?origStrictModePolicy?=?mStrictModePolicy;?? ????????????const?int32_t?origTransactionBinderFlags?=?mLastTransactionBinderFlags;?? ?? ????????????mCallingPid?=?tr.sender_pid;?? ????????????mCallingUid?=?tr.sender_euid;?? ????????????mLastTransactionBinderFlags?=?tr.flags;?? ?? ????????????int?curPrio?=?getpriority(PRIO_PROCESS,?mMyThreadId);?? ????????????if?(gDisableBackgroundScheduling)?{?? ????????????????if?(curPrio?>?ANDROID_PRIORITY_NORMAL)?{?? ?????????????????????? ?????????????????????? ?????????????????????? ?????????????????????? ????????????????????setpriority(PRIO_PROCESS,?mMyThreadId,?ANDROID_PRIORITY_NORMAL);?? ????????????????}?? ????????????}?else?{?? ????????????????if?(curPrio?>=?ANDROID_PRIORITY_BACKGROUND)?{?? ?????????????????????? ?????????????????????? ?????????????????????? ?????????????????????? ?????????????????????? ????????????????????set_sched_policy(mMyThreadId,?SP_BACKGROUND);?? ????????????????}?? ????????????}?? ?? ?????????????? ?? ????????????Parcel?reply;?? ????????????status_t?error;?? ????????????IF_LOG_TRANSACTIONS()?{?? ????????????????TextOutput::Bundle?_b(alog);?? ????????????????alog?<<?"BR_TRANSACTION?thr?"?<<?(void*)pthread_self()?? ????????????????????<<?"?/?obj?"?<<?tr.target.ptr?<<?"?/?code?"?? ????????????????????<<?TypeCode(tr.code)?<<?":?"?<<?indent?<<?buffer?? ????????????????????<<?dedent?<<?endl?? ????????????????????<<?"Data?addr?=?"?? ????????????????????<<?reinterpret_cast<const?uint8_t*>(tr.data.ptr.buffer)?? ????????????????????<<?",?offsets?addr="?? ????????????????????<<?reinterpret_cast<const?size_t*>(tr.data.ptr.offsets)?<<?endl;?? ????????????}?? ????????????if?(tr.target.ptr)?{?? ????????????????sp<BBinder>?b((BBinder*)tr.cookie);?? ????????????????error?=?b->transact(tr.code,?buffer,?&reply,?tr.flags);?? ?? ????????????}?else?{?? ????????????????error?=?the_context_object->transact(tr.code,?buffer,?&reply,?tr.flags);?? ????????????}?? ?? ?????????????? ?????????????? ?????????????? ????????????if?((tr.flags?&?TF_ONE_WAY)?==?0)?{?? ????????????????LOG_ONEWAY("Sending?reply?to?%d!",?mCallingPid);?? ????????????????if?(error?<?NO_ERROR)?reply.setError(error);?? ????????????????sendReply(reply,?0);?? ????????????}?else?{?? ????????????????LOG_ONEWAY("NOT?sending?reply?to?%d!",?mCallingPid);?? ????????????}?? ?????????????? ????????????mCallingPid?=?origPid;?? ????????????mCallingUid?=?origUid;?? ????????????mStrictModePolicy?=?origStrictModePolicy;?? ????????????mLastTransactionBinderFlags?=?origTransactionBinderFlags;?? ?? ????????????IF_LOG_TRANSACTIONS()?{?? ????????????????TextOutput::Bundle?_b(alog);?? ????????????????alog?<<?"BC_REPLY?thr?"?<<?(void*)pthread_self()?<<?"?/?obj?"?? ????????????????????<<?tr.target.ptr?<<?":?"?<<?indent?<<?reply?<<?dedent?<<?endl;?? ????????????}?? ?????????????? ????????}?? ????????break;?? ......?? }?????????
上面就是處理各種命令,最后BR_TRANSACTION命令的時候會調用BBinder的transact,最后調用service中的onTransact函數。
[cpp]?view plaincopy
status_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;?? }??
二、不使用Binder線程
還記得在healthd中,我們沒有使用Binder線程,我們看看代碼是怎么寫的。
[cpp]?view plaincopy
static?void?binder_event(uint32_t?)?{?? ????IPCThreadState::self()->handlePolledCommands();?? }?? ?? void?healthd_mode_android_init(struct?healthd_config*?)?{?? ????ProcessState::self()->setThreadPoolMaxThreadCount(0);?? ????IPCThreadState::self()->disableBackgroundScheduling(true);?? ????IPCThreadState::self()->setupPolling(&gBinderFd);?? ?? ????if?(gBinderFd?>=?0)?{?? ????????if?(healthd_register_event(gBinderFd,?binder_event))?? ????????????KLOG_ERROR(LOG_TAG,?? ???????????????????????"Register?for?binder?events?failed\n");?? ????}?? ?? ????gBatteryPropertiesRegistrar?=?new?BatteryPropertiesRegistrar();?? ????gBatteryPropertiesRegistrar->publish();?? }??
具體是調用healthd_mode_android_init函數,在這個函數先調用Binder接口,然后將fd 注冊到epoll中去,處理函數就是binder_event函數。
2.1 ProcessState::setThreadPoolMaxThreadCount函數
先來看設置Binder最大線程數的函數:
[cpp]?view plaincopy
status_t?ProcessState::setThreadPoolMaxThreadCount(size_t?maxThreads)?{?? ????status_t?result?=?NO_ERROR;?? ????if?(ioctl(mDriverFD,?BINDER_SET_MAX_THREADS,?&maxThreads)?!=?-1)?{?? ????????mMaxThreads?=?maxThreads;?? ????}?else?{?? ????????result?=?-errno;?? ????????ALOGE("Binder?ioctl?to?set?max?threads?failed:?%s",?strerror(-result));?? ????}?? ????return?result;?? }??
最后是通過ioctl設置最大線程數。
2.2 IPCThreadState::disableBackgroundScheduling函數
下面我們再來看disableBackgroundScheduling函數,應該是禁止后臺線程的意思
[cpp]?view plaincopy
void?IPCThreadState::disableBackgroundScheduling(bool?disable)?? {?? ????gDisableBackgroundScheduling?=?disable;?? }??
我們再來看看在哪里使用了gDisableBackgroundScheduling 這個變量, 還是在executeCommand函數中處理BR_TRANSACTION命令時有下面這段代碼
[cpp]?view plaincopy
case?BR_TRANSACTION:?? ????{?? ????????binder_transaction_data?tr;?? ????????result?=?mIn.read(&tr,?sizeof(tr));?? ????????ALOG_ASSERT(result?==?NO_ERROR,?? ????????????"Not?enough?command?data?for?brTRANSACTION");?? ????????if?(result?!=?NO_ERROR)?break;?? ?????????? ????????Parcel?buffer;?? ????????buffer.ipcSetDataReference(?? ????????????reinterpret_cast<const?uint8_t*>(tr.data.ptr.buffer),?? ????????????tr.data_size,?? ????????????reinterpret_cast<const?binder_size_t*>(tr.data.ptr.offsets),?? ????????????tr.offsets_size/sizeof(binder_size_t),?freeBuffer,?this);?? ?????????? ????????const?pid_t?origPid?=?mCallingPid;?? ????????const?uid_t?origUid?=?mCallingUid;?? ????????const?int32_t?origStrictModePolicy?=?mStrictModePolicy;?? ????????const?int32_t?origTransactionBinderFlags?=?mLastTransactionBinderFlags;?? ?? ????????mCallingPid?=?tr.sender_pid;?? ????????mCallingUid?=?tr.sender_euid;?? ????????mLastTransactionBinderFlags?=?tr.flags;?? ?? ????????int?curPrio?=?getpriority(PRIO_PROCESS,?mMyThreadId);?? ????????if?(gDisableBackgroundScheduling)?{?? ????????????if?(curPrio?>?ANDROID_PRIORITY_NORMAL)?{?? ?????????????????? ?????????????????? ?????????????????? ?????????????????? ????????????????setpriority(PRIO_PROCESS,?mMyThreadId,?ANDROID_PRIORITY_NORMAL);?? ????????????}?? ????????}?else?{?? ????????????if?(curPrio?>=?ANDROID_PRIORITY_BACKGROUND)?{?? ?????????????????? ?????????????????? ?????????????????? ?????????????????? ?????????????????? ????????????????set_sched_policy(mMyThreadId,?SP_BACKGROUND);?? ????????????}?? ????????}??
2.3 IPCThreadState::setupPolling
下面我們再來看看setupPolling函數
[cpp]?view plaincopy
int?IPCThreadState::setupPolling(int*?fd)?? {?? ????if?(mProcess->mDriverFD?<=?0)?{?? ????????return?-EBADF;?? ????}?? ?? ????mOut.writeInt32(BC_ENTER_LOOPER);?? ????*fd?=?mProcess->mDriverFD;?? ????return?0;?? }??
我們看代碼這個函數只是獲取Binder驅動的fd
2.4 Binder驅動 有數據
然后我們把fd加入主線程的epoll進行監聽,當Binder驅動有數據的時候,就會調用binder_event函數
[cpp]?view plaincopy
static?void?binder_event(uint32_t?)?{?? ????IPCThreadState::self()->handlePolledCommands();?? }??
我們來看下handlePolledCommands函數:
[cpp]?view plaincopy
status_t?IPCThreadState::handlePolledCommands()?? {?? ????status_t?result;?? ?? ????do?{?? ????????result?=?getAndExecuteCommand();?? ????}?while?(mIn.dataPosition()?<?mIn.dataSize());?? ?? ????processPendingDerefs();?? ????flushCommands();?? ????return?result;?? }??
getAndExecuteCommand函數之前我們分析過,這里再來看下:
[cpp]?view plaincopy
status_t?IPCThreadState::getAndExecuteCommand()?? {?? ????status_t?result;?? ????int32_t?cmd;?? ?? ????result?=?talkWithDriver();?? ????if?(result?>=?NO_ERROR)?{?? ????????size_t?IN?=?mIn.dataAvail();?? ????????if?(IN?<?sizeof(int32_t))?return?result;?? ????????cmd?=?mIn.readInt32();?? ????????IF_LOG_COMMANDS()?{?? ????????????alog?<<?"Processing?top-level?Command:?"?? ?????????????????<<?getReturnString(cmd)?<<?endl;?? ????????}?? ?? ????????pthread_mutex_lock(&mProcess->mThreadCountLock);?? ????????mProcess->mExecutingThreadsCount++;?? ????????pthread_mutex_unlock(&mProcess->mThreadCountLock);?? ?? ????????result?=?executeCommand(cmd);?? ?? ????????pthread_mutex_lock(&mProcess->mThreadCountLock);?? ????????mProcess->mExecutingThreadsCount--;?? ????????pthread_cond_broadcast(&mProcess->mThreadCountDecrement);?? ????????pthread_mutex_unlock(&mProcess->mThreadCountLock);?? ?? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ?????????? ????????set_sched_policy(mMyThreadId,?SP_FOREGROUND);?? ????}?? ?? ????return?result;?? }??
先獲取binder驅動數據,然后再執行executeCommand函數,和之前一樣執行到BR_TRANSACTION命令會調用BBinder的transact,最終執行到service的onTransact函數中。
當然這些數據的處理都是在healthd的主線程中,是epoll在binder驅動有數據的時候執行的。
2.5 處理完數據后 清理工作
我們繼續看handlePolledCommands函數
[cpp]?view plaincopy
status_t?IPCThreadState::handlePolledCommands()?? {?? ????status_t?result;?? ?? ????do?{?? ????????result?=?getAndExecuteCommand();?? ????}?while?(mIn.dataPosition()?<?mIn.dataSize());?? ?? ????processPendingDerefs();?? ????flushCommands();?? ????return?result;?? }??
最后做一些清理工作,在flushCommands函數中將和binder驅動的交互關閉。
[cpp]?view plaincopy
void?IPCThreadState::flushCommands()?? {?? ????if?(mProcess->mDriverFD?<=?0)?? ????????return;?? ????talkWithDriver(false);?? }??
三、總結
這篇博客我們主要講了使用binder的demon的binder調用流程,以及不使用binder線程的代碼調用方法,舉例了healthd中的一個例子。
原始地址: http://blog.csdn.net/kc58236582/article/details/51744398
總結
以上是生活随笔為你收集整理的Android Binder ProcessState IPCThreadState相关介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。