Android记之语言Binder
理解Binder设计
以我的理解,先有Android后有Binder,Binder就像是Android这个世界的语言。Binder目前的设计是为了满足Android的需求,Linux现存的进程间通信机制不满足Android的需求。Android的Binder的进程间通信设计了类似C/S的架构,为了满足这样的结构设计,要定义client端和server端的”通信协议“,所以android中用接口的方式来定义,client和server要分别实现接口的方法。然后要实现两端的通信,那么就要使用binder驱动,Android中使用IBinder来对binder驱动进行抽象,然后client端使用BpBinder来和binder驱动接口通信,server端使用BBinder来和binder通信。以上就是Binder的总体设计,从概念来理解很简单,但是真正实现还是弯弯绕绕,我们就以AudioFlinger为例,按照上面的思路就来看具体设计。
先设计接口(IAudioFlinger)
IAudioFlinger的接口声明如下:
class IAudioFlinger : public IInterface
{
public:
DECLARE_META_INTERFACE(AudioFlinger);
...
virtual status_t setMasterVolume(float value) = 0;
...
}
接口设计为纯虚函数,继承类要实现这些方法,这样接口接定义了C/S两端的接口,Client端调用了setMasterVolume,就相当于调用了Server的setMasterVolume,对于应用开发来说非常方便。
接下来就要为这个接口分别加上C/S的Binder通信接口。
Server端加上通信接口
声明的接口代码看起来也很简单:
class BnAudioFlinger : public BnInterface<IAudioFlinger>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
// Requests media.log to start merging log buffers
virtual void requestLogMerge() = 0;
};
这里透露出来的重要信息有两部分:
- BnInterface:模板类,封装了Binder接口
- onTransact:解析code,然后调用到对应的方法,如:setMasterVolume
BnInterface
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();
};
BBinder和IBinder
class BBinder : public IBinder-----------IBinder就是个接口
{
...
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);-------又看到了onTransact
...
}
onTransact
status_t BnAudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
...
switch (code) {
...
case SET_MASTER_VOLUME: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
reply->writeInt32( setMasterVolume(data.readFloat()) );
return NO_ERROR;
} break;
...
}
...
}
这是onTransact的最终实现,server端肯定有一个循环一直在调用onTransact,那么是在哪里呢,在桥梁那一节我们就可以看到
setMasterVolume最终的实现没有在BnAudioFlinger,而是在AudioFlinger中,继续看
Server端实现接口(AudioFlinger)
实现接口就很简单了,先声明
class AudioFlinger :
public BinderService<AudioFlinger>,
public BnAudioFlinger
{
...
static const char* getServiceName() ANDROID_API { return "media.audio_flinger"; }
...
virtual status_t setMasterVolume(float value);
...
}
具体实现:
status_t AudioFlinger::setMasterVolume(float value)
{
status_t ret = initCheck();
if (ret != NO_ERROR) {
return ret;
}
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
Mutex::Autolock _l(mLock);
mMasterVolume = value;
// Set master volume in the HALs which support it.
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
AutoMutex lock(mHardwareLock);
AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
if (dev->canSetMasterVolume()) {
dev->hwDevice()->setMasterVolume(value);
}
mHardwareStatus = AUDIO_HW_IDLE;
}
// Now set the master volume in each playback thread. Playback threads
// assigned to HALs which do not have master volume support will apply
// master volume during the mix operation. Threads with HALs which do
// support master volume will simply ignore the setting.
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
continue;
}
mPlaybackThreads.valueAt(i)->setMasterVolume(value);
}
return NO_ERROR;
}
Server向ServiceManager注册服务
系统起来后,每个server都会向ServiceManager注册自己,一般都是在main_*.cpp中实现,以audioserver来举例:
int main(int argc __unused, char **argv)
{
...
AudioFlinger::instantiate();--------注册audioflinger服务
AudioPolicyService::instantiate();
...
IPCThreadState::self()->joinThreadPool();---这里实现循环,一直调用onTransact,具体在桥梁一节分析
}
我们来看看AudioFlinger::instantiate的具体实现,还记得上面的BinderService吗,audioflinger继承于它:
template<typename SERVICE>
class BinderService
{
public:
static status_t publish(bool allowIsolated = false,
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
dumpFlags);
}
...
static void instantiate() { publish(); }
}
代码很清晰,通过sm->addService来注册自己"media.audio_flinger"
Client端的实现
IAudioFlinger.cpp
class BpAudioFlinger : public BpInterface<IAudioFlinger>
{
public:
explicit BpAudioFlinger(const sp<IBinder>& impl)---------impl是要传入的BpBinder
: BpInterface<IAudioFlinger>(impl)
{
}
...
virtual status_t setMasterVolume(float value)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeFloat(value);
remote()->transact(SET_MASTER_VOLUME, data, &reply);--------通过remote来进行binder通信
return reply.readInt32();
}
}
上面的Bp也就是Binder Proxy,而Bn就是Bindernative。上面就是Client端的实现,每个用户使用的话都会new BpAudioFlinger,而且要传入一个参数,这个参数就是client端的Binder接口BpBinder,下面两个小节就以这两个疑问展开,在此之前,我们先把BpInterface模板类看完。
BpInterface
IInterface.h
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
explicit BpInterface(const sp<IBinder>& remote);
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
: BpRefBase(remote)----------------------------------------------------impl传入到这里,impl==remote
{
}
Binder.cpp
BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(nullptr), mState(0)----------------------remote传给mRemote
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
if (mRemote) {
mRemote->incStrong(this); // Removed on first IncStrong().
mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
}
}
最终我们得出mRemote就是BpBinder,而且我们看到BpAudioFlinger每个函数里面传输数据都会调用remote()来进行,再来看看BpRefBase的声明:
Binder.h
class BpRefBase : public virtual RefBase
{
...
inline IBinder* remote() { return mRemote; }
inline IBinder* remote() const { return mRemote; }
private:
...
IBinder* const mRemote;
...
};
获取BpBinder
好了,继续聊上面的两个疑问。首先,我们要知道谁会去获取AudioFlinger的client,答案是AudioSystem,有一个封装好的接口:
const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
{
sp<IAudioFlinger> af;
sp<AudioFlingerClient> afc;
{
Mutex::Autolock _l(gLock);
if (gAudioFlinger == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.audio_flinger"));---------从servceManager获取我们要的BpBinder
if (binder != 0)
break;
ALOGW("AudioFlinger not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (gAudioFlingerClient == NULL) {
gAudioFlingerClient = new AudioFlingerClient();
} else {
if (gAudioErrorCallback) {
gAudioErrorCallback(NO_ERROR);
}
}
binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast<IAudioFlinger>(binder);-----------重要的事情来了,创建BpAudioFlinger
LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0);
afc = gAudioFlingerClient;
// Make sure callbacks can be received by gAudioFlingerClient
ProcessState::self()->startThreadPool();
}
af = gAudioFlinger;
}
if (afc != 0) {
int64_t token = IPCThreadState::self()->clearCallingIdentity();
af->registerClient(afc);
IPCThreadState::self()->restoreCallingIdentity(token);
}
return af;
}
new Bp##INTERFACE(new BpAudioFlinger)
从上面知道了一个重要的模板函数interface_cast
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
实例化后就是调用IAudioFlinger::asInterface(obj),又回到了IAudioFlinger,我们再从头看一下这个函数是怎么实现的吧,下面就不得不说两个重要的宏定义了
- DECLARE_META_INTERFACE--------------------------声明
#define DECLARE_META_INTERFACE(INTERFACE) \
public: \
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(); \
static bool setDefaultImpl(std::unique_ptr<I##INTERFACE> impl); \
static const std::unique_ptr<I##INTERFACE>& getDefaultImpl(); \
private: \
static std::unique_ptr<I##INTERFACE> default_impl; \
public: \
这个宏我们在IAudioFlinger接口设计那里已经看到过,这里我们看到了asInterface的声明,INTERFACE在本文就是IAudioFlinger
- IMPLEMENT_META_INTERFACE(android10)-----定义
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)\
const ::android::StaticString16 \
I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\
const ::android::String16 I##INTERFACE::descriptor( \
I##INTERFACE##_descriptor_static_str16); \
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 != nullptr) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == nullptr) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
std::unique_ptr<I##INTERFACE> I##INTERFACE::default_impl; \
bool I##INTERFACE::setDefaultImpl(std::unique_ptr<I##INTERFACE> impl)\
{ \
if (!I##INTERFACE::default_impl && impl) { \
I##INTERFACE::default_impl = std::move(impl); \
return true; \
} \
return false; \
} \
const std::unique_ptr<I##INTERFACE>& I##INTERFACE::getDefaultImpl() \
{ \
return I##INTERFACE::default_impl; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { } \
我们看一下asInterface的宏定义,首先检索对象是否已存在,如果为空,那么我们要找的东西就来了,new Bp##INTERFACE,目标达成。
桥梁(ProcessState/IPCThreadState)
上面分析了那么多,但是我们一直没看到具体操作binder驱动的接口。client通过transact来传输数据,而server端通过onTransact来处理数据,具体这两个接口是如何衔接上的呢。借着这两个问题,我们从BBinder和BpBinder这两个类说起,这两个类都继承于Binder的业务层接口IBinder。Client要传输数据,要调用transact,那么BpBinder的这个函数怎么实现呢?
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实现
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);
...
if ((flags & TF_ONE_WAY) == 0) {
...
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
...
} else {
err = waitForResponse(nullptr, nullptr);
}
return err;
}
- writeTransactionData:用于把数据打包parcel
- waitForResponse:调用binder驱动接口进行数据传输,具体是在函数talkWithDriver中实现
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
...
do {
...
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)-------Binder的ioctl接口实现数据传输
...
} while (err == -EINTR);
...
}
这里看到了binder驱动的文件描述符,这是在另一个类ProcessState创建的时候打开的,IPCThreadState中的mProcess就保存了ProcessState,ProcessState每个进程只有一份,这样就没必要每个线程都去打开驱动
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != nullptr) {
return gProcess;
}
gProcess = new ProcessState(kDefaultDriver);
return gProcess;
}
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver))------------------打开binder驱动
, 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)
{
...
}
这样Client从业务层到驱动的调用顺序我们都清楚了,那么Server肯定也遵循这样的轨迹,通过BBinder的transact来调用IPCThreadState的transact进行数据传输,不过Server要执行一个loop来循环处理每条收到的数据并执行相应的命令来调用对应的函数。以AudioServer为例,在init的时候就会执行,我们来看看main函数的实现
int main(int argc __unused, char **argv)
{
...
pid_t childPid;
if (doLog && (childPid = fork()) != 0) {
...
} else {
...
sp<ProcessState> proc(ProcessState::self());--------------创建ProcessState并打开binder驱动
sp<IServiceManager> sm = defaultServiceManager();---------获得Client ServiveManager
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();------------------------------server AudioFlinger初始化
AudioPolicyService::instantiate();------------------------server AudioPolicy初始化
...
SoundTriggerHwService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();-----------------循环处理
}
}
void IPCThreadState::joinThreadPool(bool isMain)
{
...
do {
...
result = getAndExecuteCommand();循环处理每条命令
...
} while (result != -ECONNREFUSED && result != -EBADF);
...
}
getAndExecuteCommand会调用talkWithDriver,收到数据后进行解析处理,然后调用executeCommand
status_t IPCThreadState::executeCommand(int32_t cmd)
{
...
switch ((uint32_t)cmd) {
case BR_ERROR:
...
case BR_ACQUIRE:
...
case BR_TRANSACTION:
...
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
// safely acquire a strong reference before doing anything else with it.
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
...
}
}
调用BBinder->transact
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:
err = pingBinder();
break;
case EXTENSION_TRANSACTION:
err = reply->writeStrongBinder(getExtension());
break;
case DEBUG_PID_TRANSACTION:
err = reply->writeInt32(getDebugPid());
break;
default:
err = onTransact(code, data, reply, flags);--------------好了,我们找到onTransact了
break;
}
// In case this is being transacted on in the same process.
if (reply != nullptr) {
reply->setDataPosition(0);
}
return err;
}
本文地址:https://blog.csdn.net/l289123557/article/details/107134333
推荐阅读
-
Android笔记之:深入为从右向左语言定义复杂字串的详解
-
Android深入浅出之Binder机制解析
-
21天刷题计划之10.2—牛牛偶像养成记(Java语言描述)
-
用Java语言对QQ进行终极山寨---晴儿QQ诞生记之登录界面 QQJavaSwingJDK
-
用Java语言对QQ进行终极山寨---晴儿QQ诞生记之正在登录界面 QQJavaSwingJDKSUN
-
用Java语言对QQ进行终极山寨---晴儿QQ诞生记之操作主界面 QQJavaSwingSUNJDK
-
用Java语言对QQ进行终极山寨---晴儿QQ诞生记之正在登录界面 QQJavaSwingJDKSUN
-
C语言程序设计练习之2013 蟠桃记
-
android学习之制作title,2条横线夹住标题,切换语言改变使得title自适应d
-
Android的进程间通信(六)之 Binder的客户端发送数据到服务端的流程