BInder
Posted 白嫩豆腐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BInder相关的知识,希望对你有一定的参考价值。
前言
Binder是android核心中的核心。Android各种服务都是通过Binder来实现进程间通讯的,我计划分三部分大概剖析一下binder的具体原理。
- Binder的具体使用案例
- 源码分析大概流程
- 实现最简单的binder
正文
binder是分为两部分的,一部分是服务端,通过线程池,等待其他进程通过binder驱动通知服务。另一部分是客户端,主要通过mmap函数,得到内核的内存映射区,写入数据,然后通知服务端。一个最简单的服务端如下:
主要操作流程大概是
- Bnservice向binder驱动注册自己(主要包括名称和线程池)
- 客户端通过defaultServiceManager(binder驱动模块)获取注册的Bpservice。
- 客户端吧需要传输的消息写入到通过map共享的内存中,然后通知binder,唤醒服务端。
- 服务端进程启动,调用onTransact,读取共享缓冲区的内容。做出相应,写会相应。
- 阻塞的客户端得到相应。完成一次通讯。
下面我们先简要介绍一个最简答的HelloWorld的binder程序
首先介绍一下:binder使用的接口:
无论任何一对客户端和服务端的binder通讯对(可以一对多),都需要一个IXXXService,
比如IHelloService
class IHelloService: public IInterface
{
public:
DECLARE_META_INTERFACE(HelloService);
/*
public:
static const ::android::String16 descriptor;
static ::android::sp<IHelloService> asInterface(
const ::android::sp<::android::IBinder>& obj);
virtual const ::android::String16& getInterfaceDescriptor() const;
IHelloService();
virtual ~IHelloService();
static bool setDefaultImpl(std::unique_ptr<IHelloService> impl);
static const std::unique_ptr<IHelloService>& getDefaultImpl();
private:
static std::unique_ptr<IHelloService> default_impl;
public:
*/
virtual int SayHello(char *str) = 0;
virtual char* getHi() = 0;
};
一般开发过程中都直接使用预编译的DECLARE_META_INTERFACE的定义一些公共方法,最终等效于注释部分,主要定义一些函数、和default_impl变量。而IInterface的代码如下:
class IInterface : public virtual RefBase
{
public:
IInterface();
static sp<IBinder> asBinder(const IInterface*);
static sp<IBinder> asBinder(const sp<IInterface>&);
protected:
virtual ~IInterface();
virtual IBinder* onAsBinder() = 0;
};
这个类主要是关于binder的静态方法。
下面我们介绍一下BnService的实现
class HelloService: public BnInterface<IHelloService>
{
public:
static void instantiate(){
defaultServiceManager()->addService(
String16("hello.service"), new HelloService());
};
int SayHello(char *str){
return 1;
}
char* getHi(){
return NULL;
}
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags){
switch (code) {
case SAY_HELLO: {
CHECK_INTERFACE(IHelloService, data, reply);
const char *name = data.readCString();
return NO_ERROR;
}
case GET_REPLAY: {
CHECK_INTERFACE(IHelloService, data, reply);
reply->writeCString("hello");
return NO_ERROR;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
return -1;
}
};
其实代码逻辑比较简单,主要是实现了IHelloService的接口,以及核心收到binder有消息时写入时,被线程池调用的函数onTransact。
BnInterface其实比较简单,主要通过BBinder管理binder。
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
一个最简单的binder服务端代码如下:
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
hello::HelloService::instantiate();
//打开线程池。
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
服务端本质就是一个线程池,阻塞式的调用binder文件的ioctl系统调用,式再rocessState::self()->startThreadPool()中进入一个死循环,当驱动中收到client发送的消息后,阻塞函数会开始调用,进而开始调用onTransact函数。
客户端
客户端代码如下
class BpHelloService: public BpInterface<IHelloService>
{
public:
BpHelloService(const sp<IBinder>& imp);
int SayHello(char *str);
char* getHi();
};
BpHelloService::BpHelloService(const sp<IBinder>& imp) : BpInterface<IHelloService>(imp) {
ALOGV("MediaTranscodingService is created");
}
int BpHelloService::SayHello(char *str) {
// TODO(hkuang): Add implementation.
const char *tmp = str;
ALOGE("---what the fuck---%s",str);
Parcel data, reply;
data.writeInterfaceToken(IHelloService::getInterfaceDescriptor());
data.writeCString(tmp);
status_t status __unused = remote()->transact(SAY_HELLO, data, &reply);
ALOGE("------%s",str);
return 1;
}
char* BpHelloService::getHi() {
Parcel data, reply;
data.writeInterfaceToken(IHelloService::getInterfaceDescriptor());
status_t status __unused = remote()->transact(GET_REPLAY, data, &reply);
const char *rep = reply.readCString();
char *ret = (char*)malloc(10);;
strcpy(ret,rep);
return ret;
}
//IMPLEMENT_META_INTERFACE(HelloService,"hello.world.service");
//下半部分等效与宏定义
const ::android::StaticString16
IHelloService_descriptor_static_str16(__IINTF_CONCAT(u, "hello.world.service"));
const ::android::String16 IHelloService::descriptor(
IHelloService_descriptor_static_str16);
const ::android::String16&
IHelloService::getInterfaceDescriptor() const {
return IHelloService::descriptor;
}
::android::sp<IHelloService> IHelloService::asInterface(
const ::android::sp<::android::IBinder>& obj)
{
::android::sp<IHelloService> intr;
if (obj != nullptr) {
intr = static_cast<IHelloService*>(
obj->queryLocalInterface(
IHelloService::descriptor).get());
if (intr == nullptr) {
intr = new BpHelloService(obj);
}
}
return intr;
}
std::unique_ptr<IHelloService> IHelloService::default_impl;
bool IHelloService::setDefaultImpl(std::unique_ptr<IHelloService> impl)
{
/* Only one user of this interface can use this function */
/* at a time. This is a heuristic to detect if two different */
/* users in the same process use this function. */
assert(!IHelloService::default_impl);
if (impl) {
IHelloService::default_impl = std::move(impl);
return true;
}
return false;
}
const std::unique_ptr<IHelloService>& IHelloService::getDefaultImpl()
{
return IHelloService::default_impl;
}
IHelloService::IHelloService() { }
IHelloService::~IHelloService() { }
这里的核心就是remote()->transact(SAY_HELLO, data, &reply);
原理是
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
......
status_t status = IPCThreadState::self()->transact()
......
return DEAD_OBJECT;
}
就是通过IPCThreadState的transact函数完成任务
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
err = waitForResponse(reply);
return err;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
while (1) {
//把out通过iotl写入到驱动,然后被驱动程序处理,
if ((err=talkWithDriver()) < NO_ERROR) break;
//结果进行处理,返回到之前的函数,
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish;
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
return err;
}
talkWithDriver就是通过ioctl把数据写入到binder中的,代码比较简单
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
return err;
}
后记
binder好复杂啊,整体原理还是比较简单的,但是binder中混入了一个无用的servicemanage以及多线程的支持,让代码晦涩难懂,以后有机会再分析一下。
以上是关于BInder的主要内容,如果未能解决你的问题,请参考以下文章