從MediaServer看Binder的使用方式(二)
theme: channing-cyan
一 概述
```cpp
[main_mediaserver.cpp]
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
//1 獲得一個ProcessState的實例
sp
上一篇我們説完了步驟 1 到步驟 3,並且到了 IPCThreadState 在和 Binder 交互時,會調用 waitForResponse,然後在 waitForResponse 中調用 talkWithDriver 和 Binder 進行交互,讀出 mIn 中的數據,然後通過 executeCommand 執行,接下來,我們再看看具體的細節
源碼目錄
frameworks/native/libs/binder/IPCThreadState.cpp
frameworks/native/libs/binder/ProcessState.cpp
frameworks/native/libs/binder/IPCThreadState.cpp
二 talkWithDriver
```cpp [IPCThreadState.cpp]
status_t IPCThreadState::talkWithDriver(bool doReceive) { //這個就是我們在open_device時拿到的fd if (mProcess->mDriverFD <= 0) { return -EBADF; }
//binder_write_read是用來和binder設備交換數據的結構
binder_write_read bwr;
// 讀
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
//如果還需要讀,就先讀,不寫
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
//我們將讀到的數據
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
//日誌
...
// 讀和寫都結束了
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
if defined(ANDROID)
//通過ioctl的方式交互
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
else
err = INVALID_OPERATION;
endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
//日誌
...
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
//日誌
...
return NO_ERROR;
}
return err;
} ```
三 startThreadPool
因為 registerExtensions 默認為空,所以我們接下來看 startThreadPool 的相關邏輯,相比於之前的邏輯,這個簡單很多
```cpp [ProcessState.cpp]
void ProcessState::startThreadPool() { AutoMutex _l(mLock); if (!mThreadPoolStarted) { mThreadPoolStarted = true; spawnPooledThread(true); } }
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
//傳入的參數是true
sp
class PoolThread : public Thread { public: explicit PoolThread(bool isMain) : mIsMain(isMain) { }
protected: virtual bool threadLoop() { IPCThreadState::self()->joinThreadPool(mIsMain); return false; }
const bool mIsMain;
}; ```
四 joinThreadPool
接下來就是最後一步 joinThreadPool 了,它是定義在 IPCThreadState.cpp 中的函數
```cpp [IPCThreadState.cpp]
void IPCThreadState::joinThreadPool(bool isMain) {
//如果isMain是true,則需要寫入一個BC_ENTER_LOOPER
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
//處理已經死亡的BBinder對象
processPendingDerefs();
// 獲取下一條命令
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
}
// 不是主線程就不需要一直循環
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
//退出Looper
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
} ```
4.1 getAndExecuteCommand
在 joinThreadPool 也有一個和之前很像的函數 getAndExecuteCommand,它也是 talkWithDriver 和 executeCommand,因為之前已經説過,所以這裏就不重複了
```cpp [IPCThreadState.cpp]
status_t IPCThreadState::getAndExecuteCommand() { status_t result; int32_t cmd; //和Binder驅動交互 result = talkWithDriver(); if (result >= NO_ERROR) { //取出數據 size_t IN = mIn.dataAvail(); if (IN < sizeof(int32_t)) return result; cmd = mIn.readInt32();
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;
if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs == 0) {
mProcess->mStarvationStartTimeMs = uptimeMillis();
}
pthread_mutex_unlock(&mProcess->mThreadCountLock);
//執行cmd
result = executeCommand(cmd);
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;
if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs != 0) {
int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
if (starvationTimeMs > 100) {
ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
mProcess->mMaxThreads, starvationTimeMs);
}
mProcess->mStarvationStartTimeMs = 0;
}
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
return result;
} ```
五 總結
終於,一個關於 MediaServer 系統 Server 使用 Binder 的過程,就讓我們整理完畢了
- 在使用 Binder 之前,需要獲得一個 ProcessState 實例,這個對象是一個單例
- 然後需要拿到一個 defaultServiceManager 對象,這是一個 IServiceManager,它是一個 IBinder 對象,其實就是 BpBinder
- 我們如果想要給其他進程提供 Binder 服務,那麼我們需要將自己的服務註冊到 ServiceManager 中,這個註冊流程就是一個 Binder 通信的過程
- 註冊完畢後通過 ProcessState::self()->startThreadPool 啟動一個線程進行 Binder 事件的接收處理,這個線程不會退出
- 將 MediaServer 的主線程,通過 IPCThreadState::self()->joinThreadPool 也加入 loop 循環,接收 Binder 事件
當然,這兩篇關於 Binder 的介紹,也只是很簡單的説明了 Binder 通信時,native 層參與的類以及這些通信的流程,對於更細節的東西,這裏並沒有提到,接下來我們就看看 Java 層的 Binder 機制,以及這些操作中的細節
- Activity啟動源碼解析(Android12)
- 從MediaServer看Binder的使用方式(一)
- 從MediaServer看Binder的使用方式(二)
- [Android禪修之路] 解讀Layer
- [Android禪修之路] Android圖形系統,從Activity到Surface
- [Android禪修之路] 解讀 GraphicBuffer 之 Framework 層
- [Android禪修之路] 解讀SurfaceFlinger中的BufferQueue
- [Android禪修之路] SurfaceFlinger 合成中的工作
- [Android禪修之路] SurfaceFlinger 中的一些對象
- [Android禪修之路] SurfaceFlinger 合成前的預處理
- [Android禪修之路] SurfaceFlinger合成總覽
- [Android禪修之路] SurfaceFlinger的啟動過程
- [Android禪修之路] Android 圖形系統開篇