Binder 框架 -- binder 用户空间框架
来源:互联网 发布:图森未来 知乎 编辑:程序博客网 时间:2024/06/07 11:32
Binder 框架 – binder 用户空间框架
Binder框架 – android AIDL 的使用
Binder框架 – 用户空间和驱动的交互
Binder框架 – Binder 驱动
Binder 框架 – binder 用户空间框架
一 ServiceManager 启动
int main(int argc, char **argv){ struct binder_state *bs; bs = binder_open(128*1024); if (!bs) { ALOGE("failed to open binder driver\n"); return -1; } if (binder_become_context_manager(bs)) { ALOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } ...... binder_loop(bs, svcmgr_handler); return 0;}
1. 打开binder 设备
bs = binder_open(128*1024); 打开binder 设备驱动。相关的信息保存在binder_state 结构中。
struct binder_state{ int fd; binder 设备的fd void *mapped; 映射到用户空间的地址 size_t mapsize; 大小 };struct binder_state *binder_open(size_t mapsize){ struct binder_state *bs; struct binder_version vers; bs = malloc(sizeof(*bs)); if (!bs) { errno = ENOMEM; return NULL; } bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC); if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { ...... } bs->mapsize = mapsize; bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); return bs;}
binder_open 中做的工作主要是打开binder 设备,然后通过mmap 将binder内核空间映射到用户空间。标准的linux 设备访问方法:
- open(“/dev/binder”, O_RDWR | O_CLOEXEC); 打开设备
- ioctl(bs->fd, BINDER_VERSION, &vers) ioctl 命令设置版本号。 在下面对binder 驱动的访问中主要是通过 ioctl 函数,没有用我们常见的 read write, 这个也是binder 驱动设计的一个特点
- mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); 内核空间mapsize大小映射到用户空间,注意映射的空间是只读权限。
- 设备的文件描述符, 用户空间地址, 大小用binder_state结构体保存。
2. binder_become_context_manager 通知binder驱动成为管理者。
int binder_become_context_manager(struct binder_state *bs){ return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);}
注意最后一个参数为0;函数设计上可能是为了表示ServiceManager hander为0.但是在驱动中收到的消息为BINDER_SET_CONTEXT_MGR,已经表示是表示ServiceManager自己,直接把自己的 hander置为0,没有使用这个参数。ServiceManager 本身管理服务的特殊性,没有其它进程负责它的注册,ServiceManager需要自己完成注册,同时自己的handler 为0.
3. binder_loop 进入循环
binder_loop调用的时候同时传入回调函数。
- binder_write(bs, readbuf, sizeof(uint32_t)); 调用 ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 通知binder 驱动进入循环。这次调用没有阻塞。
- 在 for 循环中的 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 阻塞,当有消息来得时候,读出数据,交给binder_parse解析同时指定svcmgr_handler func处理解析数据。
void binder_loop(struct binder_state *bs, binder_handler func){ int res; struct binder_write_read bwr; uint32_t readbuf[32]; bwr.write_size = 0; bwr.write_consumed = 0; bwr.write_buffer = 0; readbuf[0] = ; binder_write(bs, readbuf, sizeof(uint32_t)); for (;;) { bwr.read_size = sizeof(readbuf); bwr.read_consumed = 0; bwr.read_buffer = (uintptr_t) readbuf; res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); if (res < 0) { ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); break; } res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); if (res == 0) { ALOGE("binder_loop: unexpected reply?!\n"); break; } if (res < 0) { ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); break; } }}
4. svcmgr_handler 处理信息
svcmgr_handler func 函数指针指向svcmgr_handler
信息主要有这几个类型:
- SVC_MGR_GET_SERVICE 获取服务
- SVC_MGR_CHECK_SERVICE 检查服务
- SVC_MGR_ADD_SERVICE 添加服务,如mediaservice 添加就会到这里
- SVC_MGR_LIST_SERVICES 主要是 service list 命令使用
int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply){ struct svcinfo *si; uint16_t *s; size_t len; uint32_t handle; uint32_t strict_policy; int allow_isolated; if (txn->target.ptr != BINDER_SERVICE_MANAGER) return -1; if (txn->code == PING_TRANSACTION) return 0; ...... switch(txn->code) { case SVC_MGR_GET_SERVICE: case SVC_MGR_CHECK_SERVICE: s = bio_get_string16(msg, &len); if (s == NULL) { return -1; } handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid); if (!handle) break; bio_put_ref(reply, handle); return 0; case SVC_MGR_ADD_SERVICE: s = bio_get_string16(msg, &len); if (s == NULL) { return -1; } handle = bio_get_ref(msg); allow_isolated = bio_get_uint32(msg) ? 1 : 0; if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, txn->sender_pid)) return -1; break; case SVC_MGR_LIST_SERVICES: { uint32_t n = bio_get_uint32(msg); if (!svc_can_list(txn->sender_pid)) { ALOGE("list_service() uid=%d - PERMISSION DENIED\n", txn->sender_euid); return -1; } si = svclist; while ((n-- > 0) && si) si = si->next; if (si) { bio_put_string16(reply, si->name); return 0; } return -1; } default: ALOGE("unknown code %d\n", txn->code); return -1; } bio_put_uint32(reply, 0); return 0;}
5 servicemanager 是一单线程,
可能因为是工作不太繁忙,不需要多线程加班。
ps -t | grep servicemanager
system 2450 1761 10228 752 ffffffff f7685976 S /system/bin/servicemanager
servicemanager 已经启动,并且在一个while 循环中阻塞,等待唤醒。
ProcessState
ProcessState 是单例模式,每个进程只有一个实例。ProcessState在构造函数中会打开binder 驱动获取文件描述符mDriverFD,设置binder的参数,为进程进行binder 通信准备必要的条件。
sp<ProcessState> ProcessState::self(){ Mutex::Autolock _l(gProcessMutex); if (gProcess != NULL) { return gProcess; } gProcess = new ProcessState; return gProcess;}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) { mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); } }static int open_driver(){ int fd = open("/dev/binder", O_RDWR | O_CLOEXEC); if (fd >= 0) { int vers = 0; status_t result = ioctl(fd, BINDER_VERSION, &vers); size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); } } else { } return fd;}
open_driver 函数和binder_open 差不多,打开设备驱动,设置版本号并检查, 然后设置BINDER_SET_MAX_THREADS ,支持的最大线程数。
- open(“/dev/binder”, O_RDWR | O_CLOEXEC);
- octl(fd, BINDER_VERSION, &vers);
- ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
- 最后在构造函数中mmap。 为什么不在 open_driver 中一起把这个事情给做了呢?从API调用的角度放在一起比较合适吧。
startThreadPool 函数
从名字上看启动一个线程池,创建一个新的线程,spawnPooledThread isMain 参数为true,new了一个PoolThread,然后run函数 启动threadLoop(),在threadLoop 调用 IPCThreadState::self()->joinThreadPool(mIsMain); 对线程调用的封装,具体可以参考线程使用的方法。
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()); sp<Thread> t = new PoolThread(isMain); t->run(name.string()); }}class PoolThread : public Thread{public: PoolThread(bool isMain) : mIsMain(isMain) { }protected: virtual bool threadLoop() { IPCThreadState::self()->joinThreadPool(mIsMain); return false; } const bool mIsMain;};
IPCThreadState
IPCThreadState 是一个线程单例模式
IPCThreadState 是一个看似单例却不是单例的类。主要涉及了线程的局部存储,看下self 的实现:
第一次进来 gHaveTLS == false 所以走下边的代码:
- if (pthread_key_create(&gTLS, threadDestructor) != 0)
创建线程的局部存储然后goto 到 restart; - 调用pthread_getspecific,由于线程的局部key k还没有关联变量这是返回值为空;所以
new IPCThreadState;看到这里很疑惑,创建了线程的局部存储key 却没有变量存储到线程的局部存储里面,直接new 了一个IPCThreadState,和self 函数名也不匹配,搞什么鬼呢。 - 继续看IPCThreadState的构造函数:这下明白了 在构造函数里面IPCThreadState把自己作为线程的局部存储
pthread_setspecific(gTLS, this); - 如果是第二次进来 gHaveTLS == true.直接pthread_getspecific 获取IPCThreadState自身。
IPCThreadState 是一个线程单例模式, 持有两个类型为Parcel 的变量
class IPCThreadState{ ...... private: Parcel mIn; Parcel mOut;}IPCThreadState* IPCThreadState::self(){ if (gHaveTLS) {restart: const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); if (st) return st; return new IPCThreadState; } if (gShutdown) return NULL; pthread_mutex_lock(&gTLSMutex); if (!gHaveTLS) { if (pthread_key_create(&gTLS, threadDestructor) != 0) { pthread_mutex_unlock(&gTLSMutex); return NULL; } gHaveTLS = true; } pthread_mutex_unlock(&gTLSMutex); goto restart;}IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()), mMyThreadId(gettid()), mStrictModePolicy(0), mLastTransactionBinderFlags(0){ pthread_setspecific(gTLS, this); clearCaller(); mIn.setDataCapacity(256); mOut.setDataCapacity(256);}
IPCThreadState::joinThreadPool
在上面的ProcessState::startThreadPool() 中调用了IPCThreadState::joinThreadPool 那这个函数到底干了什么呢。
- 首先根据是否主线程 mOut.writeInt32,注意参数为BC_ENTER_LOOPER 或者BC_REGISTER_LOOPER 这个后边分析。
- 在一个循环中不停的getAndExecuteCommand。
- 在getAndExecuteCommand 首先talkWithDriver, 然后executeCommand,和ServiceManager 类似,在一个循环中不停的读取binder 驱动,然后解析数据。
到这里其实服务端和客户端的交互框架已经建立。在后边的MediaPlayerService中看下具体的细节。
void IPCThreadState::joinThreadPool(bool isMain){ mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); status_t result; do { ...... result = getAndExecuteCommand(); ...... } while (result != -ECONNREFUSED && result != -EBADF); ......}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(); result = executeCommand(cmd); ...... } } return result;}
Binder 通信架构
Android 为了便于使用Binder 通信,提供了一套框架,只要继承这个框架的各个类,就能够实现一个Binder通信服务。主要分为代理端和服务端。代理端和服务端通的通信通过 IInterface BpInterface BnInterface IBinder BpBinder BBinder 这几个模板类进行。
binder 下的相关类类图:
MediaPlayerService 启动
ServiceManager 单独运行在一个进程中,其它的Android系统服务如MediaPlayerService 如何启动和注册呢,在ServiceManager 的启动过程中分析到有一个 SVC_MGR_ADD_SERVICE 处理流程,在while 循环中已经阻塞。在上面分析IPCThreadState::joinThreadPool 的时候也会在循环中阻塞,根据linux 进程间通信的知识,双方应该互相发送数据唤醒对方。在这里就是MediaPlayerService 进程和ServiceManager 相互交互了,MediaPlayerService 对它的Client 来说是一个服务端,但是对ServiceManager 来说是一个客户端。
MediaPlayerService 同样基于上面的Binder通信框架,继承了相关的子类。
看一下MediaPlayerService 的启动代码。
int main(int argc __unused, char** argv){ sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); ALOGI("ServiceManager: %p", sm.get()); AudioFlinger::instantiate(); MediaPlayerService::instantiate(); ResourceManagerService::instantiate(); CameraService::instantiate(); AudioPolicyService::instantiate(); SoundTriggerHwService::instantiate(); RadioService::instantiate(); registerExtensions(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();}
defaultServiceManager
调用 sp sm = defaultServiceManager()获取ServiceManger 的代理; 函数定义在IServiceManager.cpp 中
sp<IServiceManager> defaultServiceManager(){ if (gDefaultServiceManager != NULL) return gDefaultServiceManager; { AutoMutex _l(gDefaultServiceManagerLock); while (gDefaultServiceManager == NULL) { gDefaultServiceManager = interface_cast<IServiceManager>( ProcessState::self()->getContextObject(NULL)); if (gDefaultServiceManager == NULL) sleep(1); } } return gDefaultServiceManager;}
ProcessState::getStrongProxyForHandle
- 依次调用ProcessState 的 getContextObject ->
- getStrongProxyForHandle 函数,参数为0,
首先查表 lookupHandleLocked。注意BpBinder.mHander = 0;
ProcessState 为单例模式,持有一个 VectormHandleToObject对象,进程中所有的Binder 对象都会添加到这个容器中。由于是是第一次查找,mHandleToObject为空,lookupHandleLocked会添加一个未初始化过的handle_entry对象,所以e->binder == NULL。
struct handle_entry { IBinder* binder; RefBase::weakref_type* refs;};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);}sp<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); if (e != NULL) { IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { if (handle == 0) { Parcel data; status_t status = IPCThreadState::self()->transact( 0, IBinder::PING_TRANSACTION, data, NULL, 0); if (status == DEAD_OBJECT) return NULL; } b = new BpBinder(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; } else { result.force_set(b); e->refs->decWeak(this); } } return result;}
e->binder == NULL handle == 0 条件成立,经过下面两步调用
status_t status = IPCThreadState::self()->transact(0, IBinder::PING_TRANSACTION, data, NULL, 0);b = new BpBinder(handle);
变成了
gDefaultServiceManager = interface_cast<IServiceManager>(BpBinder(0));
其中ServiceManager 的hander 为0,
transact 函数第一个参数为0,表示的是传递给 handle 为0 的Service,就是ServiceManager,
interface_cast 以及DECLARE_META_INTERFACE IMPLEMENT_META_INTERFACE
interface_cast 以及DECLARE_META_INTERFACE IMPLEMENT_META_INTERFACE 这几个宏定义在
IInterface.h 中。
template<typename INTERFACE>inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){ return INTERFACE::asInterface(obj);}define DECLARE_META_INTERFACE(INTERFACE) \ static const android::String16 descriptor; \ static android::sp<I##INTERFACE> asInterface( \ const android::sp<android::IBinder>& obj); \ virtual const android::String16& getInterfaceDescriptor() const; \ I##INTERFACE(); \ virtual ~I##INTERFACE(); \define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ const android::String16 I##INTERFACE::descriptor(NAME); \ const android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ } \ android::sp<I##INTERFACE> I##INTERFACE::asInterface( \ const android::sp<android::IBinder>& obj) \ { \ android::sp<I##INTERFACE> intr; \ if (obj != NULL) { \ intr = static_cast<I##INTERFACE*>( \ obj->queryLocalInterface( \ I##INTERFACE::descriptor).get()); \ if (intr == NULL) { \ intr = new Bp##INTERFACE(obj); \ } \ } \ return intr; \ } \ I##INTERFACE::I##INTERFACE() { } \ I##INTERFACE::~I##INTERFACE() { } \
替换掉INTERFACE 变成了, 这段代码变成了:
android::sp<IServiceManager> interface_cast<IServiceManager>(const sp<IBinder>& obj){ return IServiceManager::asInterface(obj);}android::sp<IServiceManager> IServiceManager::asInterface(const android::sp<android::IBinder>& obj){ android::sp<IServiceManager> intr; if (obj != NULL) { intr = static_cast<IServiceManager>(obj->queryLocalInterface(IServiceManager::descriptor).get()); if (intr == NULL) { intr = new BpServiceManager(obj); } } return intr; }
BpBinder(0)->queryLocalInterface, queryLocalInterface 为IBinder 的虚函数,默认返回空值,BpBinder 继承IBinder,并且没有覆盖queryLocalInterface。所以sp sm = defaultServiceManager()实际是这个样子:
sp<IServiceManager> sm = new BpServiceManager(obj);
这段代码就是为了拿到ServiceManager的BpServiceManager. 当中在线程中做了记录,然后对引用计数做了处理,通过transact 通知了ServiceManager 。这样我们就拿到了ServiceManger 的客户端BpServiceManager。代码好绕,有没有看到其他的代码使用这个机制?
MediaPlayerService 注册到 ServiceManger
再回到MediaPlayerService 初始化的代码:
int main(int argc __unused, char** argv){ ...... AudioFlinger::instantiate(); MediaPlayerService::instantiate(); 。。。。。。 ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();}
MediaPlayerService::instantiate
调用 MediaPlayerService::instantiate();
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());}
defaultServiceManager() 返回的结果就是BpServiceManager,所以这段代码变成了:
void MediaPlayerService::instantiate() { BpServiceManager()->addService(String16("media.player"), new MediaPlayerService());}
BpServiceManager()->addService
virtual 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;}
在 remote 就是在new BpServiceManager 中穿进去的BpBinder(0)。
BpBinder 的 transact
BpBinder 的 transact 函数如下:
status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ // Once a binder has died, it will never come back to life. if (mAlive) { status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; } return DEAD_OBJECT;}
IPCThreadState transact 先后调用了writeTransactionData 和 waitForResponse, writeTransactionData中把binder 相关的通信数据写入binder 驱动。然后呢,然后呢,其实在一开始ServiceManger 已经在binder_loop 中阻塞了,现在写入binder 驱动数据,binder_loop会被激活,读出数据 解析,然后ServiceManger 向bindr 驱动注册Service,将结果写入reply 参数。waitForResponse 读取reply 结果。通信完成,MediaPlayService 注册完成。
启动线程池
在最后先后调用了,根据上面的分析,startThreadPool 最后也调用了joinThreadPool。也就是启动了两个线程。
ProcessState::self()->startThreadPool(); //启动子线程 IPCThreadState::self()->joinThreadPool(); //主线程循环
在LoopThread 反复调用 joinThreadPool 函数做如下工作:
result = talkWithDriver(); if (result >= NO_ERROR) { size_t IN = mIn.dataAvail(); if (IN < sizeof(int32_t)) return result; cmd = mIn.readInt32(); result = executeCommand(cmd); ...... } }
有一个疑问,为什么需要两个线程?
总结:
- ProcessState.self() 建立实例
- defaultServiceManager()
- ProcessState::self()->getContextObject(nuLl)->ProcessState::self()->getStrongProxyForHandle(0)-> New BpBinder(0)
- interface_cast(BpBinder(0))->asInterface(BpBinder(0)) -> new BpServiceManager(BpBinder(0));
- 依次调用 BpServiceManger::addService ->BpBinder::transact->IPCThreadState::self()->transact 通知服务端
- IPCThreadState::waitForResponse 等待服务端返回。
- 启动线程池
调用序列图:
为什么需要两个线程,在需要用到回调函数的Binder通信中,在BnClass::doSome 是有callback ,而此时BpClass 进程中只有一个线程,这个线程正在waitRespose,而无法响应callback , 就会造成异常。
参考Binder 调用异常
- Binder 框架 -- binder 用户空间框架
- Binder框架 -- Binder 驱动
- Binder框架 -- 用户空间和驱动的交互
- Binder框架
- Binder 框架(一)
- Android Binder 框架
- binder框架分析
- Binder框架理解
- AIDL的Binder框架
- Camera Service Binder框架
- android的Binder框架
- andriod Binder框架记录
- Android - Binder机制 - Binder框架总结
- Binder 机制详解—Binder 本地框架
- Binder机制学习笔记-Binder框架
- Android - Binder机制 - Binder框架总结
- [Android5.1]Binder机制学习---Binder框架
- Android aidl Binder框架浅析
- java包定义&&访问权限&&import相关定义
- 七牛-资源列举list(c#)
- C++的浅拷贝出现的错误
- redis界面管理工具phpRedisAdmin 安装
- shmget - 共享内存
- Binder 框架 -- binder 用户空间框架
- JavaScript函数调用得四种方式及函数传参
- 用Go写Android程序(3) - Go语言速成
- 暗时间
- Nodejs学习路线图
- python sys.argv[]用法
- poj 2488 A Knight's Journey
- 算法的时间复杂度和空间复杂度
- 杭电ACM 1002大数相加 两种方法