所有源码均基于android M
本篇从情景化角度出发分析Binder的通信逻辑。
其中会涉及到几个概念
· media server - 系统多媒体服务
· media player server - 多媒体服务下的视频服务
· Binder驱动
先总结一下本篇所会涉及到的概念和他们之间的关系。
media server 是安卓系统中用来管理各个多媒体服务的“服务的服务类”。media server管理着多个服务的启动和加载,包括 AudioFlinger,Camera,MediaPlayerService,等等。
这些服务都需要通过media server注册到系统的ServiceManager中。
ServiceManager是android系统用来管理服务的管理器。在android里这些服务是以C/S架构存在的。所有的客户端想是用服务端功能,都需要先向系统的ServiceManager申请调用这些服务,而不能够直接使用服务的实际对象。
在C端使用S端的服务的过程中,C端所持有的是一个BinderProxy对象,它用BinderProxy,通过Binder驱动向S端发起调用,S端再通过Binder驱动把处理结果返回给C端。S端也持有一个Binder对象,和C端不同的是它不是proxy这种代理对象,它在Java层是我们写AIDL时候经常见到的Stub,在C++或者JNI层,是BBinder的派生类。
我们先从Binder驱动的启动开始。
android系统本质上也是个Linux系统,它的启动也依据 init.rc 的配置。在init.rc中,启动binder驱动的部分在servicemanager,
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
servicemanger是系统侧的进程,我们看看它代码的main入口。
Mashmallow/frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char **argv)
{
struct binder_state *bs;
bs = binder_open(128*1024); // 打开binder驱动
if (!bs) {
ALOGE("failed to open binder driver\n");
return -1;
}
if (binder_become_context_manager(bs)) { //设置fd为当前binder上下文
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
selinux_enabled = is_selinux_enabled();
sehandle = selinux_android_service_context_handle();
selinux_status_open(true);
if (selinux_enabled > 0) {
if (sehandle == NULL) {
ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
abort();
}
if (getcon(&service_manager_context) != 0) {
ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
abort();
}
}
union selinux_callback cb;
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
binder_loop(bs, svcmgr_handler); //开始事件循环,svcmgr_handler很重要,是处理事件的主要入口
return 0;
}
binder驱动的启动流程比较简单。首先它调用binder_open()去打开binder节点,我们知道在linux中一切皆是文件。
Mashmallow/frameworks/native/cmds/servicemanager/binder.c
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);//打开binder驱动
if (bs->fd < 0) {
fprintf(stderr,"binder: cannot open device (%s)\n",
strerror(errno));
goto fail_open;
}
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
fprintf(stderr,
"binder: kernel driver version (%d) differs from user space version (%d)\n",
vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
goto fail_open;
}
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//设定映射空间大小
if (bs->mapped == MAP_FAILED) {
fprintf(stderr,"binder: cannot map device (%s)\n",
strerror(errno));
goto fail_map;
}
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return NULL;
}
/dev/binder是所有binder设备的节点。binder框架的内存拷贝我们都知道只有一次,它是使用mmap在binder设备驱动上开辟了一个内存映射空间用来做内存拷贝的。因为省去了 用户空间-内核空间 的拷贝流程,所以本质上它能够做到比传统的IPC少一次内存拷贝。
但这里有个细节需要注意,这里的内存映射空间大小实际只有 128x 1024 字节,并不是我们所熟悉的1M。因为这是在系统侧的binder通信,这个内存空间实际上只有ServiceManager在使用,所以设计上只需要128K。
看到binder_loop之后就应该猜的到,这里是个事件循环机制,在一个for里面不停地等待事件的发生和处理。
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] = BC_ENTER_LOOPER;
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); //通过ioctl等待事件
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); //解析数据结构并且调用 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;
}
}
}
调用loop()的时候第二个参数 func是一个函数指针,它所指向的是service_manager中的函数svcmgr_handler()。
loop的逻辑比较简单,就是一般的事件驱动逻辑。
到这里binder驱动就启动完毕,并且进入循环模式不停地等待和处理从C端传过来的数据了。总的来说binder驱动做的事情包括
· 添加服务
· 查询服务
· 获取服务
这三个是主要功能,具体代码逻辑在 service_manager 的 svcmgr_handler里,也就是上面说的binder_loop()的第二个参数,
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
...
}
bingder驱动启动完毕后,就等待C端的ServiceManager和它通信了。到这里还只是bidner框架的其中一个部分,得结合C端的逻辑才能明白整个binder的工作原理
这里说的 media service 是提供多媒体服务的S端,它里面使用了ServiceManager的C端。在init.rc中,SM的C端的启动比S端稍微慢一点。并且它是在mediaserver进程里启动的。
service media /system/bin/mediaserver
class main
user media
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
ioprio rt 4
media sever是我们即将要启动的多媒体服务,它的主入口在
Mashmallow/frameworks/av/media/mediaserver/main_mediaserver.cpp
int main(int argc __unused, char** argv)
{
...
if (doLog && (childPid = fork()) != 0) { //从主进程fork出来子进程
//主进程部分继续做一些逻辑
} else { //子进程部分
// all other services
if (doLog) {
prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
setpgid(0, 0); // but if I die first, don't kill my parent
}
InitializeIcuOrDie();
sp<ProcessState> proc(ProcessState::self()); //在本地进程中打开binder驱动
sp<IServiceManager> sm = defaultServiceManager(); //启动C端的SM
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate(); //启动MediaPlayerService,添加到S端的SM中
ResourceManagerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
SoundTriggerHwService::instantiate();
RadioService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();//开始C端的事件循环
IPCThreadState::self()->joinThreadPool();
}
}
这个文件的代码很简单只有一百多行。我们删掉与fork出来的子进程逻辑无关的代码之后就剩下这些。
这里涉及到三个东西,ProcessState,ServiceManager,MediaPlayerService。
MediaPlayerService其实只是系统提供的多媒体服务的其中一个,类似的还有Camera,SurfaceFlinger等。还记得我们一开始说的,服务必须先添加到系统的SM里作为S端,C端再通过SM去获取服务吗。这里的media player service就是一个S端的服务,并且对比其他服务来说,它的代码和逻辑关系相对简单,所以下面我们会用它来做例子。
需要先明确一个基本关系,既在这里谁是C端谁是S端?
首先这里有两个东西,一个是ServiceManager,另外一个是MediaPlayerService。
_ServiceManager_是MediaPlayerService启动过程中需要用到的C端SM,在这里的任务是把服务添加到SM的S端中,它扮演的逻辑角色是SM的C端。而它的S端是在第一节里我们分析的binder启动那里。
_MediaPlayService_在这里扮演的角色是一个S端服务,它在等待SM的C端把它注册到系统中。
明确这两点后我们才能接着往下走,不然下面的很多逻辑都会想不明白。
ProcessState做了几件事情,创建自己的实例,打开binder。
Mashmallow/frameworks/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState;
return gProcess;
}
self()很简短,看的出来这里是个单例模式。第一次创建的时候是空的,然后 new 一个出来,第二次就直接返回第一次创建的对象了。创建对象调用了ProcessState的构造函数,
ProcessState::ProcessState()
: mDriverFD(open_driver())//注意这里打开binder
, 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) {
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
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;
}
#else
mDriverFD = -1;
#endif
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
构造函数里比较重要的是open_driver调用。它打开了binder驱动,返回一个fd,然后就可以用这个fd做内存映射了。在这里的内存映射大小是 BINDER_VM_SIZE,
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
它的大小刚好是1M-8K。为什么-8K有兴趣的可以自行了解。这里不是重点。
open_binder()代码,
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR);//打开binder驱动
if (fd >= 0) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers = 0;
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;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -1;
}
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;//返回文件描述符
}
注意这里只做了打开驱动一件事,并且把文件描述符返回。也许有会疑惑,这里没见到预想的事件循环?没错,这里只做打开驱动一件事,事件循环在mediaserver启动的最后一步才会开始。在这个阶段,所有的多媒体服务都还没有加入到系统SM中,因此还不需要事件循环来接受消息。
让我们回到 main_mediaserver 中。在ProcessState::self()之后是defaultServiceManager()。它在IServiceManager.cpp里,
Mashmallow/frameworks/native/libs/binder/IServiceManager.cpp
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL)); //获取BpBinder
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
OK,这里又是一个单例。但这里就稍微有点复杂了。
上一步我们实例化了ProcessState,这里我们还是调用 self(),拿到的也还是那个单例。然后去获取上下文对象,传入的是NULL也就是0.我们看看它做了什么
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); //查找entry
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) {
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); //创建BpBinder对象
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;
}
传进来的NULL也就是0对吧,首先它会去lookup一遍,拿到一个entry之后,看看entry里保存的e->binder是不是空的。空的就创建一个。然后把它返回。
这里创建的binder是BpBinder,参数handle也很特殊是0。
让我们回到IServiceManager中。从上面的分析知道从ProcessState里拿到的是一个 BpBinder。至于sp是个什么玩意不用太在意,IBinder表示返回的BpBinder是IBinder的派生。
问题来了,BpBinder怎么转成sp< IServiceManager >的?
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;
}
这是高科技,关键在于interface_cast这个玩意。展开这一段会有点复杂,但它里面涉及到后面要用到的remote对象,没办法绕开它理解。
interface_cast类似于java中的代理模式,或者类型强转。转换的类型必须是实现了同一套接口的对象。这里做的转换是BpBinder -> BpServiceManager。
个人觉得这里看成代理模式会好理解一些
interface_cast是一个内联函数,
Mashmallow/frameworks/native/include/binder/IInterface.h
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
它定义了一个模板 INTERFACE,展开后调用的是 INTERFACE:asInterface()。
INTERFACE:asInterface()又是个什么高科技?其实它是一个宏,也在 IInterface.h 中定义。它涉及到两个宏,DECLARE_META_INTERFACE 和 IMPLEMENT_META_INTERFACE。
#define DECLARE_META_INTERFACE(INTERFACE) \
static const android::String16 descriptor; \
static android::sp asInterface( \
const android::sp& 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::asInterface( \
const android::sp& obj) \
{ \
android::sp intr; \
if (obj != NULL) { \
intr = static_cast( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); //在这里做转换 \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { } \
IMPLEMENT是对DECLEAR的实现。DECLEAR定义了一系列api。
回到 IServiceManager.h中,它使用DECLEAR做了函数声明,
class IServiceManager : public IInterface
{
public:
DECLARE_META_INTERFACE(ServiceManager);
这里把宏展开,在宏展开后就有了这么个函数声明,
static android::sp<ServiceManager> asInterface( \
const android::sp<android::IBinder>& obj);
android::是一个命名域,关于命名域可以回头自己再去查是个什么概念。
这里的关键是 asInterface() 是个声明。那么它的实现在哪里?
答案在 IServiceManager.cpp 中,
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
我们对IMPLEMENT进行宏展开,就变成
android::sp<IServiceManager> IServiceManager::asInterface( \
const android::sp<android::IBinder>& obj) \
{ \
android::sp<IServiceManager> intr; \
if (obj != NULL) { \
intr = static_cast<IServiceManager*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new BpServiceManager(obj); //真正返回的东西 \
} \
} \
return intr; \
}
所以最后得到的是一个 BpServiceManager 对象。而传入的obj则是BpBinder。
如果你还没晕的话,继续往下看。如果已经晕了,建议把 ProcessState::self()
和 defaultServiceManager()
这两部分再看一次。如果没有C/C++功底的话,这两部分得花不少时间反复看才能看明白。
在经过上面两部分的逻辑之后,mediaserver进程就打开了binder驱动,并且获得了一个BpServiceManager对象。
Bp前缀表示的是BinderProxy,它代表着一个Binder对象在C端的代理。与之相对的有BnXXX,前缀Bn代表的是BinderNative,代表一个在S端的服务。
相对应的,MediaPlayerService也有Bp和Bn。
/Mashmallow/frameworks/av/media/libmediaplayerservice/MediaPlayerService.h
class MediaPlayerService : public BnMediaPlayerService
我们在 mediaserver 所要启动的MediaPlayerService实际是个 BnMediaPlayerService 派生类。那么BpXXX在哪里呢?熟悉Proxy的设计的话就知道,不管是在哪种语言哪种平台下,Proxy都希望是对用户透明的,也可以说用户看不见代理。那么BpXXX一定不会在 .h 头文件里对不?
再往前猜一步,media player service 的S端叫MediaPlayerService,那它的C端是不是应该有个对应的叫 IMediaPlayerService?
Mashmallow/frameworks/av/media/libmedia/IMediaPlayerService.cpp
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
{
public:
BpMediaPlayerService(const sp<IBinder>& impl)
: BpInterface<IMediaPlayerService>(impl)
{
}
果然在这里有个BpMediaPlayerService,并且在头文件IMediaPlayerService.h是没有声明的。
OK,回到 MediaPlayerService::instantiate(),这时候S端的MediaPlayerService准备启动,
Mashmallow/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
它调用了 defaultServiceManager,然后把实例化的 MediaPlayerService addService进去。
addService的实现在
Mashmallow/frameworks/native/libs/binder/IServiceManager.cpp
还记得 defaultServiceManager 拿到的 BpBinder 通过 interface_cast 变成了什么玩意吗?
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);//调用binder驱动传递消息
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
关键在于 remote()->transact,这里是通过Binder驱动真正进行消息传递的地方。传递的方向是,
BpServiceManager -> BnServiceManager
新的问题出现了
remote() 返回的是啥?
BnServiceManager 在哪?
OK,第一个问题,remote()返回什么。
BpServiceManager是从BpInterface派生的,
class BpServiceManager : public BpInterface<IServiceManager>
那么BpInterface的声明我们看看,
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp<IBinder>& remote);//这里的remote
protected:
virtual IBinder* onAsBinder();
};
是不是看到熟悉的remote了。
再回想BpServiceManager构造的时候传入的参数是啥? BpBinder对不对?
所以这里 remote()返回的其实是 BpBinder对象,也就是Binder驱动在C端的一个代理。
OK,下一个问题,BnServiceManager 在哪?
很不幸,虽然在 IServiceManager.cpp 里确实有 BnServiceManager 的实现,但这里的 BnServiceManager 实际上并不是这个东西,而是我们最开始的时候讲的 Binder驱动的启动
里的 servicemanager 进程里的binder。
明确这两点后回到 remote()->transact。现在知道是BpBinder的 transact() 使用了Binder驱动进行消息通信,
Mashmallow/frameworks/native/libs/binder/BpBinder.cpp
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是个什么玩意?
从名字上来看可以猜到 IPCThreadState 是一个用来进行跨进程通信(IPC)的线程。而且它并不是我们第一次见到,在ProcessState::self()->getContextObject(NULL)
中,创建BpBinder的时候已经调用过一次 IPCThreadState::self()了。
可想而知它也是个单例。调用transact是为了向Binder的S端发消息,
Mashmallow/frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
flags |= TF_ACCEPT_FDS;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
}
if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);//数据写入到mOut
}
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
if ((flags & TF_ONE_WAY) == 0) {
#if 0
if (code == 4) { // relayout
ALOGI(">>>>>> CALLING transaction 4");
} else {
ALOGI(">>>>>> CALLING transaction %d", code);
}
#endif
if (reply) {
err = waitForResponse(reply); //mOut写入到 /dev/binder 内存映射
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == 4) { // relayout
ALOGI("<<<<<< RETURNING transaction 4");
} else {
ALOGI("<<<<<< RETURNING transaction %d", code);
}
#endif
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
代码里有两处可疑的地方,分别是
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
err = waitForResponse(reply);
writeTransactionData看似发送消息,但实际上它只做了数据处理,
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr;
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
看到没,这里一点跟驱动交互的事情都没有。最终只是把要发送的数据写入到mOut这个buffer里。
waitForResponse做了什么呢,
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break; //和驱动交互
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
}
switch (cmd) {
...
goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
这里省略了一些代码。它一上来就跟驱动交互,通过talkWithDriver,把mOut里的东西往内存映射里写。然后等待通信完成,把返回的数据读到 mIn 里。talkWithDriver的代码虽然多但并不复杂,这里就不展开分析了。接收方是谁呢?上面已经说了,是 servicemanager 进程。
细心的会发现,binder的IPC过程,似乎是个同步过程?是的没错,它就是个同步过程。
到上面IPCThreadState的transact这里,其实整个流程还没结束。实际上到transact这里只是把MediaPlayerService启动起来,并且注册到servicemanager里。此时MediaPlayerService还没准备好接受消息。
这句话啥意思?
通过上面的分析可以知道,启动起来的MPS是个S端的服务,那么它是要提供服务给C端的。既然要提供服务,那么它就要有监听事件的能力对吧。也就是说,必然有个类似 event loop的逻辑。那么这个逻辑在哪里呢?
回到最开始的 main_mediaserver 启动流程,
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
MediaPlayerService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
这里还有两行代码没有分析,关键的event loop就在这里。
ProcessState::self()->startThreadPool() 会启动一个线程用于监听事件,也就是所谓的event loop。看看它的实现,
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); //创建PoolThread
t->run(name.string()); //启动线程
}
}
调用链最后会创建一个 PoolThread 对象,然后调用它的 run 方法。PoolThread是Threads的派生类,android源码里的Threads有很多实现,这里是从
Mashmallow/system/core/libutils/Threads.cpp
派生的,
省略一些代码后它的run方法如下,
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
if (mRunning) {
// thread already started
return INVALID_OPERATION;
}
// reset status and exitPending to their default value, so we can
// try again after an error happened (either below, or in readyToRun())
mStatus = NO_ERROR;
mExitPending = false;
mThread = thread_id_t(-1);
// hold a strong reference on ourself
mHoldSelf = this;
mRunning = true;
bool res;
if (mCanCallJava) {
res = createThreadEtc(_threadLoop, // _threadLoop
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop, // _threadLoop
this, name, priority, stack, &mThread);
}
它调用了一个叫 _threadLoop的东西,我们直接忽略其他代码看最终调用,
int Thread::_threadLoop(void* user)
{
...
do {
...
} else {
result = self->threadLoop();
}
看到了吗,它会回去调用派生类的 threadLoop() 方法,也就是在PoolThread中的threadLoop().
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
而threadLoop() 又会去调用 joinThreadPool()。
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
// This thread may have been spawned by a thread that was in the background
// scheduling group, so first we will make sure it is in the foreground
// one to avoid performing an initial transaction in the background.
set_sched_policy(mMyThreadId, SP_FOREGROUND);
status_t result;
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand(); //执行C端的命令
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
(void*)pthread_self(), getpid(), (void*)result);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
到 do{…}while() 就真相大白了,终于可以看到类似 event loop 的逻辑。此时 media player service 才真正具有了S端的能力,这里的event loop会等待消息进来,然后通过getAndExecuteCommand把C端的命令派发给S端服务去执行。
整一个binder通信流程基本到这里就清晰了。但还有个问题没解决,main_mediaserver在startThreadPool之后又有一行 joinThreadPool,那是干嘛?
在查阅了很多资料后我也没有明白这个设计。它实际做的事情不过是开另外个线程等事件进来,而网上有开发者在屏蔽了这行代码后也能正常执行所有流程,所以这个可能是谷歌的容错设计?万一挂了一个线程还有一个辅助线程么?如果有人明白的话欢迎解疑。