从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 图形系统开篇