一次完整的 Binder IPC 通信过程通常是这样:
首先 Binder 驱动在内核空间创建一个数据接收缓存区; 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系; 发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。【因为存在映射关系,所以不用再拷贝一次】 如下图:
每个Android的进程,只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小是可以通过参数配置调整的。
对于用户空间,不同进程之间彼此是不能共享的,而内核空间却是可共享的。Client进程向Server进程通信,恰恰是利用进程间可共享的内核内存空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl等方法跟内核空间的驱动进行交互。
安卓10 的 addService 的流程,以mediaplayerservice 为例子:
/frameworks/av/media/mediaserver/main_mediaserver.cpp
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
// 1. 获取 ProcessState 对象
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
ALOGI("ServiceManager: %p", sm.get());
AIcu_initializeIcuOrDie();
// 2. MediaPlayerService 的addService 方法
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
1 获取 ProcessState 对象
ProcessState
的单例模式的惟一性,因此一个进程只打开binder设备一次,其中ProcessState的成员变量mDriverFD
记录binder驱动的fd,用于访问binder设备。BINDER_VM_SIZE = (1*1024*1024) - (4096 *2)
, binder分配的默认内存大小为1M-8k。DEFAULT_MAX_BINDER_THREADS = 15
,binder默认的最大可并发访问的线程数为16。
/frameworks/native/libs/binder/ProcessState.cpp
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))
// 打开设备驱动 open_driver
, mDriverFD(open_driver(driver))
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mManagesContexts(false)
, mBinderContextCheckFunc(nullptr)
, mBinderContextUserData(nullptr)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
// 采用内存映射函数mmap,给binder分配一块虚拟地址空间
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
打开设备驱动 open_driver
static int open_driver(const char *driver)
{
// 1-0) 打开设备驱动:"/dev/binder"
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
// 1-1)设置binder 版本
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(%d) does not match user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
// 1-2)设置最大的线程数据 15
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 '%s' failed: %s\n", driver, strerror(errno));
}
return fd;
}
// 1-0) 打开设备驱动:"/dev/binder"
int fd = open(driver, O_RDWR | O_CLOEXEC)
xref: /drivers/staging/android/binder.c
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
current->group_leader->pid, current->pid);
// 分配内存 proc
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
get_task_struct(current);
proc->tsk = current;
// 初始化双向链表
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->wait);
proc->default_priority = task_nice(current);
binder_lock(__func__);
binder_stats_created(BINDER_STAT_PROC);
// 将 proc->proc_node 增加到 binder_procs双向链表中
hlist_add_head(&proc->proc_node, &binder_procs);
proc->pid = current->group_leader->pid;
// 又初始化双向链表
INIT_LIST_HEAD(&proc->delivered_death);
// 设置 filp->private_data为 proc
filp->private_data = proc;
binder_unlock(__func__);
if (binder_debugfs_dir_entry_proc) {
char strbuf[11];
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
}
return 0;
}
// 1-1)设置binder 版本
status_t result = ioctl(fd, BINDER_VERSION, &vers)
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
proc->pid, current->pid, cmd, arg);*/
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
。。
case BINDER_VERSION: {
struct binder_version __user *ver = ubuf;
if (size != sizeof(struct binder_version)) {
ret = -EINVAL;
goto err;
}
// put_user 将结果 &ver->protocol_version传给用户空间。
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
&ver->protocol_version)) {
ret = -EINVAL;
goto err;
}
break;
}
其中 binder_get_thread 函数:
static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
struct binder_thread *thread = NULL;
struct rb_node *parent = NULL;
struct rb_node **p = &proc->threads.rb_node;
while (*p) {
parent = *p;
thread = rb_entry(parent, struct binder_thread, rb_node);
if (current->pid < thread->pid)
p = &(*p)->rb_left;
else if (current->pid > thread->pid)
p = &(*p)->rb_right;
else
break;
}
// 使用红黑树保存 thread
if (*p == NULL) {
// 创建一个 thread
thread = kzalloc(sizeof(*thread), GFP_KERNEL);
if (thread == NULL)
return NULL;
binder_stats_created(BINDER_STAT_THREAD);
thread->proc = proc;
thread->pid = current->pid;
init_waitqueue_head(&thread->wait);
INIT_LIST_HEAD(&thread->todo);
rb_link_node(&thread->rb_node, parent, p);
// 插入到红黑树中
rb_insert_color(&thread->rb_node, &proc->threads);
thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
thread->return_error = BR_OK;
thread->return_error2 = BR_OK;
}
return thread;
}
put_user 将结果 &ver->protocol_version传给用户空间
/frameworks/native/libs/binder/ProcessState.cpp
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;
}
// 用户空间的binder version与返回的值对比
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
// 1-2)设置最大的线程数据 15
拷贝用户空间的数据copy_from_user:到 proc->max_threads
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
// 缓存下发的 arg
void __user *ubuf = (void __user *)arg;
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
proc->pid, current->pid, cmd, arg);*/
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_SET_MAX_THREADS:
// 拷贝用户空间的数据到 proc->max_threads
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret = -EINVAL;
goto err;
}
break;
2. MediaPlayerService 的addService 方法
MediaPlayerService::instantiate函数把MediaPlayerService添加到Service Manger中
/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
由前一篇博客分析可以知道:defaultServiceManager() 的值为:
BpServiceManager(new BpBinder(0)) 调用客户端的方法
执行:addService(String16("media.player"), new MediaPlayerService());
/frameworks/native/libs/binder/IServiceManager.cpp
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
explicit BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{
}
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated, int dumpsysPriority) {
Parcel data, reply;
// 2-1)先看下 Parcel 序列化的一些方法
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
data.writeInt32(dumpsysPriority);
// 2-2)remote() 为 BpBinder,调用 transact
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()),
其中:IServiceManager::getInterfaceDescriptor()的值为:"android.os.IServiceManager"
2-1)先看下 Parcel 序列化的一些方法
- writeString16 ("media.player")方法:
/frameworks/native/libs/binder/Parcel.cpp
status_t Parcel::writeString16(const String16& str)
{
return writeString16(str.string(), str.size());
}
=====
status_t Parcel::writeString16(const char16_t* str, size_t len)
{
if (str == nullptr) return writeInt32(-1);
// 增长空间 writeInt32
status_t err = writeInt32(len);
if (err == NO_ERROR) {
// len的值为 26,假如 char16_t为 2 个字节
// len = 52
len *= sizeof(char16_t);
// 找到要写入的指针位置
// data 为 uint8_t* const data = mData+mDataPos;
uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
if (data) {
// 将 str 保存到 data 中
memcpy(data, str, len);
*reinterpret_cast<char16_t*>(data+len) = 0;
return NO_ERROR;
}
err = mError;
}
return err;
}
// 增长空间 writeInt32
status_t err = writeInt32(len)
// val 的值为 12
status_t Parcel::writeInt32(int32_t val)
{
return writeAligned(val);
}
======
template<class T>
status_t Parcel::writeAligned(T val) {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
// 初始化Parcel 时调用 initState(),mDataCapacity的值为0
if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
// 首次插入 mDataPos为 0
// 如果是首次插入,则设置 *reinterpret_cast<int32_t*>(mData+0) = 26
// *reinterpret_cast<int32_t*>(mData) = 26
*reinterpret_cast<T*>(mData+mDataPos) = val;
// 重新去设置mDataPos 和 mDataSize 的值
// 设置 mDataPos增加插入的字符长度
// mDataPos += len;
return finishWrite(sizeof(val));
}
// 增大数据
status_t err = growData(sizeof(val));
// 如果没有错误的化,则 跳转到 restart_write:
if (err == NO_ERROR) goto restart_write;
return err;
}
==========
status_t Parcel::growData(size_t len)
{
if (len > INT32_MAX) {
// don't accept size_t values which may have come from an
// inadvertent conversion from a negative int.
return BAD_VALUE;
}
// 其中 writeInterfaceToken("android.os.IServiceManager" )的时候也会调用 writeInt32,走到如下:
// 26*3/2 = 39
// writeInterfaceToken时会调用 continueWrite
size_t newSize = ((mDataSize+len)*3)/2;
return (newSize <= mDataSize)
? (status_t) NO_MEMORY
: continueWrite(newSize);
}
执行:continueWrite(39)
status_t Parcel::continueWrite(size_t desired)
{
if (desired > INT32_MAX) {
// don't accept size_t values which may have come from an
// inadvertent conversion from a negative int.
return BAD_VALUE;
}
。。。。。
} else {
// This is the first data. Easy!
// 分配 39 个字节的空间
uint8_t* data = (uint8_t*)malloc(desired);
if (!data) {
mError = NO_MEMORY;
return NO_MEMORY;
}
if(!(mDataCapacity == 0 && mObjects == nullptr
&& mObjectsCapacity == 0)) {
ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity, mObjects, mObjectsCapacity, desired);
}
LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired);
pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
// 设置全局分配的空间
gParcelGlobalAllocSize += desired;
// 分配了多少次
gParcelGlobalAllocCount++;
pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
// 设置全局 mData 为 data
mData = data;
// 设置 mDataSize为 0
mDataSize = mDataPos = 0;
ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize);
ALOGV("continueWrite Setting data pos of %p to %zu", this, mDataPos);
// 设置data 容量为 39
mDataCapacity = desired;
}
return NO_ERROR;
}
// 找到要写入的指针位置
uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t))
2-2)remote() 为 BpBinder,调用 transact