> 文章列表 > 【】:addService 和 getService

【】:addService 和 getService

【】:addService 和 getService

一次完整的 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)设置最大的线程数据 15result = 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);// 分配内存 procproc = 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为 procfilp->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;elsebreak;}// 使用红黑树保存 threadif (*p == NULL) {// 创建一个 threadthread = 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);// 缓存下发的 argvoid __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_threadsif (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,调用 transactstatus_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);// 增长空间 writeInt32status_t err = writeInt32(len);if (err == NO_ERROR) {// len的值为 26,假如 char16_t为 2 个字节
// len =  52len *= 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的值为0if ((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时会调用 continueWritesize_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 为 datamData = data;// 设置 mDataSize为 0mDataSize = 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 容量为 39mDataCapacity = desired;}return NO_ERROR;
}

// 找到要写入的指针位置

uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t))

2-2)remote() 为 BpBinder,调用 transact

医学名词大全