binder
Binder 是什么?看了很多的文章,总是不出意外的陷入源码地狱,跳来跳去就迷失其中了。但是binder作为一种ipc机制应该是可以独立于这些源码之中的。那本菜鸟就将binder代码提纯,来领略清纯Binder的风采。
可参考的binder代码,但是这里的代码是针对6.0 版本的
从使用说明开始
这是张很经典的图,我们就从这张图开始说起。
第一步,注册服务
1
2
| // 获取ServiceManager,然后添加服务,服务名称为demo
defaultServiceManager()->addService(String16("Demo"), new Demo(), false);
|
1
2
3
4
5
6
7
| // 服务详情
class Demo : public BnDemo {
virtual int32_t add(int32_t v1, int32_t v2) {
INFO("Demo::add(%i, %i)", v1, v2);
return v1 + v2;
}
};
|
第二步,获取服务
1
2
3
4
5
6
| // 获取ServiceManager
sp<IServiceManager> sm = defaultServiceManager();
// 根据名称获取服务
sp<IBinder> binder = sm->getService(String16("Demo"));
// 强制转化 为 IDemo 的 binder对象
sp<IDemo> demo = interface_cast<IDemo>(binder);
|
第三步,使用服务
1
2
| // 调用远程服务
int32_t sum = demo->add(3, 5);
|
是不是很简单,接下来我们就来一步一步的分享其中的奥秘。
如何获取到的ServiceManager?
IServiceManager.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
// 加锁
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
// interface_cast 强制转化
// ProcessState::self() 打开binder设备
// getContextObject(NULL) 获取handle为0的binder对象 也就是ServiceManager
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
|
这里留下两个疑问:
ProcessState::self()
内部打开Binder设备的具体逻辑?getContextObject(NULL)
如何就能获取到ServiceManager?
我们稍后分析。
不过,我们还是可以总结一下: 如何获取到的ServiceManager?
打开binder设备的0号服务,这个服务就是ServiceManager。
形象的比喻就是ip 为 8.8.8.8
的服务器 他就是Google的dns服务器,写死了的!你可以在代码里hardcode的那种。
在我们的binder机制里,binder驱动就是浏览器,ip
为0 他就是servicemanager,写死了的!google已经hardcode了的那种。
如何注册服务?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // frameworks/native/libs/binder/IServiceManager.cpp#139
virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
// name 就是 demo,相当于我们的服务的域名
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;
}
|
这里我们有留下了两个疑问:
IServiceManager::getInterfaceDescriptor()
这是个啥?remote()
如何就是 service manager的binder对象了?
不过,我们还是可以总结一下: 如何添加服务?
将我们的服务binder写入Parcel,然后传输给 ServiceManager进程。
再形象的比喻一下,ServiceManager这就是相当于阿里云,你在后台弄了一台云服务器,将这台服务器绑上域名,ip具体多少无所谓了,只有阿里云才会关心ip。
域名
就是我们的namedemo
。
服务器内容
就是我们的Demo()
。
ip
servicemanager内部的handle,who care。
如何获取服务?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| // frameworks/native/libs/binder/IServiceManager.cpp#162
virtual sp<IBinder> getService(const String16& name) const
{
// 循环五遍去检查服务?先跳过。
unsigned n;
for (n = 0; n < 5; n++){
if (n > 0) {
ALOGI("Waiting for service %s...", String8(name).string());
sleep(1);
}
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
}
return NULL;
}
virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
// CHECK_SERVICE_TRANSACTION 检查服务,然后大脑服务器
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
|
来吧!开始形象的比喻,这里就是用域名demo
找serverManager 要我们的具体服务内容。然后SM给我们回了一个binder,就是我们的服务的远程代理。
如何使用服务?
如何使用服务?不用说,mote()->transact
对吧?不信你看!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| virtual int32_t add(int32_t v1, int32_t v2) {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(v1);
data.writeInt32(v2);
aout << "BpDemo::add parcel to be sent:\n";
data.print(PLOG); endl(PLOG);
remote()->transact(ADD, data, &reply);
ALOGD("BpDemo::add transact reply");
reply.print(PLOG); endl(PLOG);
int32_t res;
status_t status = reply.readInt32(&res);
ALOGD("BpDemo::add(%i, %i) = %i (status: %i)", v1, v2, res, status);
return res;
}
|
remote()
,remote()
,又是 remote()
!看来不看下remote
里面是个啥是不行了!
remote()->transact
1
2
3
4
5
6
7
8
9
| // frameworks/native/include/binder/Binder.h#mRemote
class BpRefBase : public virtual RefBase
{
protected:
inline IBinder* remote() { return mRemote; }
inline IBinder* remote() const { return mRemote; }
private:
IBinder* const mRemote;
};
|
研究进入深水区,怎么就出现一个BpRefBase?
1
2
3
4
5
6
7
8
9
10
11
| // frameworks/native/libs/binder/Binder.cpp#264
// 看构造函数,mRemote 就是传入的 sp<IBinder> 去get获取到的。
// 回到我们的demo。不卖关子关键就在这里 sp<IDemo> demo = interface_cast<IDemo>(binder);
BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(NULL), mState(0)
{
if (mRemote) {
mRemote->incStrong(this); // Removed on first IncStrong().
mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
}
}
|
sp<IDemo> demo = interface_cast<IDemo>(binder);
remote 就是这个binder,而这个binder就是 servicemanager的bidner对象。
那么大的来了,
1
| remote()->transact(ADD, data, &reply);
|
这里面是怎么处理的?
从上面我们已知,remote()
=> BnInterface<IDemo>
=> BBinder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // frameworks/native/libs/binder/Binder.cpp#115
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;
}
|
只是简单的将值传过来了,在我们的例子中 就是走到了这。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
status_t BnDemo::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
ALOGD("BnDemo::onTransact(%i) %i", code, flags);
data.checkInterface(this);
data.print(PLOG); endl(PLOG);
switch(code) {
case ADD: {
int32_t inV1 = data.readInt32();
int32_t inV2 = data.readInt32();
int32_t sum = add(inV1, inV2);
ALOGD("BnDemo::onTransact add(%i, %i) = %i", inV1, inV2, sum);
ASSERT(reply != 0);
reply->print(PLOG); endl(PLOG);
reply->writeInt32(sum);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
|
整体流程已经走完,那么就要追求一些细节。
接下来两步最关键:
ProcessState::self()
源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| // frameworks/native/libs/binder/ProcessState.cpp
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)
, mStarvationStartTimeMs(0)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
// 打开binder驱动,失败了 mDriverFD 设置为-1
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
// 映射一块地址,映射失败?gg
// 但是这里我崩出了一个疑问,客户端不是将内容拷贝到内科空间嘛,为什么要mmap?留下这个疑惑!之后再讨论。
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
}
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
|
mDriverFD(open_driver())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| static int open_driver()
{
// 打开binder这个驱动,大于等于0 成功,小于0 gg。
int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
// 获取binder版本号,如果获取不到说明binder不通,gg
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;
}
// 版本号不对,也gg
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -1;
}
// 设置服务端最大线程数 DEFAULT_MAX_BINDER_THREADS 为15
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;
}
|
mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
官方解释
这里是映射一段虚拟地址和物理地址。
getContextObject(NULL)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| // frameworks/native/libs/binder/ProcessState.cpp
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
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// 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. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
// 这是特殊处理的逻辑,如果handle为0,说明这是sm。需要ping一下binder 是不是通
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
// 根据handler 保证一个bpbinder
b = new BpBinder(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;
}
|
客户端不是将内容拷贝到内科空间嘛,为什么要mmap?
参考资料