关于Binder的 FrameWork 相关的代码逻辑,我在我的简书FrameWork专栏 中有总结过,但是在学习 android native 的过程中发现Binder 仍然是非常重要的一部分,那么就先分析一下 binder native 的源码逻辑 由于我最近在看音视频相关的,所以这里就分析一下 main_mediaserver.cpp 的流程
所有源码均来自 Android 11
C++ main_mediaserver.cpp
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
// 获取一个 ProcessState 这个过程非常重要
sp<ProcessState> proc(ProcessState::self());
// 获取一个 ServiceManager 0 这个级别就代表的是 ServiceManager
sp<IServiceManager> sm(defaultServiceManager());
ALOGI("ServiceManager: %p", sm.get());
AIcu_initializeIcuOrDie();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
::android::hardware::configureRpcThreadpool(16, false);
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
::android::hardware::joinRpcThreadpool();
}
可以看到这里先是通过 ProcessState::self() 获取了一个 ProcessState ,我们来看看这个里面做了什么
sp<ProcessState> ProcessState::self()
{
// 析构同步锁来获取一个单利 ProcessState
Mutex::Autolock _l(gProcessMutex);
if (gProcess != nullptr) {
return gProcess;
}
gProcess = new ProcessState(kDefaultDriver);
return gProcess;
}
这里利用同步锁获取一个单利的 ProcessState,继续跟踪 new ProcessState
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
// 打开驱动文件 重要逻辑
, mDriverFD(open_driver(driver))
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mBinderContextCheckFunc(nullptr)
, mBinderContextUserData(nullptr)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)
{
if (mDriverFD >= 0) {
//重要逻辑
//调用mmap接口向Binder驱动中申请内核空间的内存
// mmap the binder, providing a chunk of virtual address space to receive transactions.
//也就是binder 的底层原来是通过 mmap 来实现的,mVMStart记录的就是共享内存的开始节点
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
}
#ifdef __ANDROID__
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened. Terminating.", driver);
#endif
}
在 ProcessState 的初始化代码中看到了一段注释,就是利用mmap向内核空间申请内存,传入的就是 mDriverFD ,那么证明 在给 mDriverFD 赋值的操作就是非常重要的一步,继续跟踪一下 open_driver(driver),参数 driver 是一个常量
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif
static int open_driver(const char *driver)
{
//打开binder驱动
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
//验证binder版本
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
close(fd);
fd = -1;
}
//设置binder最大线程数
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 '%s' failed: %s\n", driver, strerror(errno));
}
return fd;
}
这里面使用了是C语言中的打开一个文件的方式来打开一个驱动,同时调用 ioctl 这个方法, 没有找到这个源码在哪里,同时也没有什么思路,但是百度了一下关于 ioctl 方面的东西, 这里有一篇文章 他这里说明了 ioctl 的作用,我这里摘抄一下 ioctl功能简介 open、write函数的功能无非就是为了进行用户空间和内核空间的数据交换,而ioctl呢? 大部分驱动除了需要具备读写设备的能力之外,还需要对设备具有控制能力,比如要求设备报告错误信息,弹出介质,设置波特率等。很明显我们这里就是验证版本号的功能,同时给binder 设置了 最大线程数 15 个,我个人猜测这里应该是最多有15个线程同时访问这个驱动文件,而不是线程只能有15个线程访问这个文件,并将这个数量通过 ioctl 方式写入的 binder文件中,在面试过程中有被问到过 Binder 线程数超量而引起的崩溃问题,那么解释就在这里了
到了这里我们就了解了 ProcessState::self() 的整个过程,首先通过同步锁获取了一个单利的 ProcessState ,如果存在就返回,不存在就 new 一个出来,在new 的过程中打开了 /dev/binder 这个驱动文件,验证了版本号,同时还写入了最大线程数,最后在打开驱动文件成功后,通过 mmap 的方式申请内核空间的内存,并将这段空间的开始位置交给 mVMStart
说道 mmap 就让我想起了 mmkv 中的用法,以及 mmap 配合 ProtoBuf 高效的文件映射,想了解的同学可以自行搜索一下,关于这些问题现在只是了解这个概念,还没有深入的研究
我们重新看一下 main_mediaserver.cpp
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
ALOGI("ServiceManager: %p", sm.get());
AIcu_initializeIcuOrDie();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
::android::hardware::configureRpcThreadpool(16, false);
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
::android::hardware::joinRpcThreadpool();
}
我们来看看 defaultServiceManager 这个方法是如何获取到 IServiceManager 这个对象的
sp<IServiceManager> defaultServiceManager()
{
std::call_once(gSmOnce, []() {
sp<AidlServiceManager> sm = nullptr;
while (sm == nullptr) {
//sm 就是
sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
if (sm == nullptr) {
ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());
sleep(1);
}
}
gDefaultServiceManager = new ServiceManagerShim(sm);
});
return gDefaultServiceManager;
}
这里也使用了一个C++的同步机制, 来循环的调用 ProcessState::self()->getContextObject(nullptr));在上面我们已经分析过了 ProcessState::self() 的流程,下面分析一下 getContextObject(nullptr))
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
//handle句柄0代表的就是 ServiceManager,所以这里调用getStrongProxyForHandle函数的参数为0
sp<IBinder> context = getStrongProxyForHandle(0);
if (context == nullptr) {
ALOGW("Not able to get context object on %s.", mDriverName.c_str());
}
// The root object is special since we get it directly from the driver, it is never
// written by Parcell::writeStrongBinder.
internal::Stability::tryMarkCompilationUnit(context.get());
return context;
}
这里就是调用了一下 getStrongProxyForHandle 这个方法,注意的是 这里传入的参数是 0 ,0 代表的就是 ServiceManager,至于是为什么 ,我们接着分析
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//查找或建立handle对应的handle_entry
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. The
// attemptIncWeak() is safe because we know the BpBinder destructor will always
// call expungeHandle(), which acquires the same lock we are holding now.
// We need to do this because there is a race condition between someone
// releasing a reference on this BpBinder, and a new reference on its handle
// arriving from the driver.
IBinder* b = e->binder;
// 如果binder 为空 ,另一个参数在Binder 创建时 添加的
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
// 下面这段注释就是说明为什么 0 是 ServiceManager
// Special case for context manager...
// The context manager is the only object for which we create
// a BpBinder proxy without already holding a reference.
// Perform a dummy transaction to ensure the context manager
// is registered before we create the first local reference
// to it (which will occur when creating the BpBinder).
// If a local reference is created for the BpBinder when the
// context manager is not present, the driver will fail to
// provide a reference to the context manager, but the
// driver API does not return status.
//
// Note that this is not race-free if the context manager
// dies while this code runs.
//
// TODO: add a driver API to wait for context manager, or
// stop special casing handle 0 for context manager and add
// a driver API to get a handle to the context manager with
// proper reference counting.
//当handle为ServiceManager的特殊情况
//需要确保在创建Binder引用之前,context manager已经被binder注册
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, nullptr, 0);
if (status == DEAD_OBJECT)
return nullptr;
}
//创建BpBinder并保存下来以便后面再次查找
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
这里的注释比较多,但是我一句也没有删掉,原因是通过注释可以让你了解这么调用的意义,他在这段代码当中先是调用了 lookupHandleLocked 这个方法 来获取一个 handle_entry 指针, 我们来看一下
//方法用于查找本进程中是否已经创建过要获取的 IBinder,如果没有获取到,就创建一个
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = nullptr;
e.refs = nullptr;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return nullptr;
}
return &mHandleToObject.editItemAt(handle);
}
显示获取当前的 handle_obj 的大小,如果传入的 handle 大于 这个size ,证明需要创建 并插入 ,最后获取在获取一下,通过代码也能看到这里缓存的是 binder
我们再继续分析剩余的代码 那就是如果获取的 handle_entry 中的binder 为空,并且 handle 是0 的话,也就是需要初始化 ServiceManager ,就需要调用 IPCThreadState::self()->transact( 0, IBinder::PING_TRANSACTION, data, nullptr, 0); 这个方法,来确保一下 context manager的状态,这里同样到了系统级别指令的读写操作了,感兴趣的同学可以百度一下 IPCThreadState::transact , 我看了一下相应的文章,这里就不过多的纠结了,
接下来就到了重头戏 创建 BpBinder 了 BpBinder::create(handle); 我们来跟踪一下这个create 的过程
BpBinder* BpBinder::create(int32_t handle) {
int32_t trackedUid = -1;
if (sCountByUidEnabled) {
trackedUid = IPCThreadState::self()->getCallingUid();
AutoMutex _l(sTrackingLock);
uint32_t trackedValue = sTrackingMap[trackedUid];
if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) {
if (sBinderProxyThrottleCreate) {
return nullptr;
}
} else {
if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
getuid(), trackedUid, trackedValue);
sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
if (sLimitCallback) sLimitCallback(trackedUid);
if (sBinderProxyThrottleCreate) {
ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
" count drops below %d",
trackedUid, getuid(), sBinderProxyCountLowWatermark);
return nullptr;
}
}
}
sTrackingMap[trackedUid]++;
}
return new BpBinder(handle, trackedUid);
}
这里又查找了另一个 id ,通过这两个id 来创建 BpBinder
BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
: mHandle(handle)
, mStability(0)
, mAlive(1)
, mObitsSent(0)
, mObituaries(nullptr)
, mTrackedUid(trackedUid)
{
ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
// 这个对象就是 getStrongProxyForHandle 方法中 判断 binder 为空的另一个条件
IPCThreadState::self()->incWeakHandle(handle, this);
}
先来看看 IPCThreadState::self() 方法干了什么
IPCThreadState* IPCThreadState::self()
{
if (gHaveTLS.load(std::memory_order_acquire)) {
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState;
}
// Racey, heuristic test for simultaneous shutdown.
if (gShutdown.load(std::memory_order_relaxed)) {
return nullptr;
}
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS.load(std::memory_order_relaxed)) {
int key_create_value = pthread_key_create(&gTLS, threadDestructor);
if (key_create_value != 0) {
pthread_mutex_unlock(&gTLSMutex);
ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",
strerror(key_create_value));
return nullptr;
}
gHaveTLS.store(true, std::memory_order_release);
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
}
这里的逻辑确实有点绕,我们这里重点关注第一个if 里面的操作,显示获取 gTLS ,然后在 利用这个 从 specific 中获取了一个 IPCThreadState,如果不为null 则返回,反之则创建,至于剩下的逻辑需要结合后面的代码一起分析才可以,这里先不用管, gTLS 是什么 specific 又从哪里获取的,继续分析 IPCThreadState 构造方法
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mServingStackPointer(nullptr),
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0),
mCallRestriction(mProcess->mCallRestriction)
{
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
关于 tls 就是 Thread-Local Storage ,关于他的介绍我在网上看到一个比较不错的文章,传送门 , 如果让我用 java 的思路来说就是一个 threadLocal与 threadLoaclMap 的关系,这个数据只有当前线程能访问到
那么我们再回来捋一下 IPCThreadState 创建的流程就是 在创建 IPCThreadState 的过程中,需要先调用 ProcessState::self(),同时向 specific 中添加 gTLS,
到了这里创建 ServiceManager 的BpBinder 的流程就完成了, 我先再来回顾一下整个过程 首先调用 defaultServiceManager 来获取一个 IServiceManager ,在通过 ProcessState::self()->getContextObject(nullptr) 来获取, 通过这个 handle 句柄先去 handle_entry 中查找,如果没有就创建 BpBinder , 在创建 BpBinder 的同时还将 handle 句柄与 他自身使用 incWeakHandle 缓存起来