Android IPC机制Binder解析
来源:互联网 发布:网络转232 编辑:程序博客网 时间:2024/04/30 02:07
花了一个上午的时间把这篇文章翻译完,确实写的很透彻,但美中不足的地方是没有插图,不能直观的了解Binder机制,说实话我自己对binder也理解的很浅显,特别是到binder kernel driver哪块,还要等我先学习linux驱动再来看一遍吧,等以后看懂了再自己绘图应该更有助于理解。
------------------------------------------------------------------------荤勾线-----------------------------------------------------------------------------------------------------
我将利用IAudioFlinger::setMode这个API作为一个简单的场景,来展示Android IPC系统是如何工作的,AudioFlinger是多媒体服务系统中的一个服务。
运行Service Manager
service_manager 是为其它进程提供“服务”管理的“服务”。所以,它必须比于其它任何服务先运行。
- int main(int argc, char **argv)
- {
- struct binder_state *bs;
- void *svcmgr = BINDER_SERVICE_MANAGER;
- bs = binder_open(128*1024);
- if (binder_become_context_manager(bs)) {
- LOGE("cannot become context manager (%s)/n", strerror(errno));
- return -1;
- }
- svcmgr_handle = svcmgr;
- binder_loop(bs, svcmgr_handler);
- return 0;
- }
首先打开“/dev/binder”驱动,且调用BINDER_SET_CONTEXT_MGR这个ioctl,让内核驱动知道该设备是作为管理者(manager)的角色。然后进入一个循环,等待来自其它进程的数据。
- void binder_loop(struct binder_state *bs, binder_handler func)
- {
- int res;
- struct binder_write_read bwr;
- unsigned readbuf[32];
- bwr.write_size = 0;
- bwr.write_consumed = 0;
- bwr.write_buffer = 0;
- readbuf[0] = BC_ENTER_LOOPER;
- binder_write(bs, readbuf, sizeof(unsigned));
- for (;;) {
- bwr.read_size = sizeof(readbuf);
- bwr.read_consumed = 0;
- bwr.read_buffer = (unsigned) readbuf;
- res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
- if (res < 0) {
- LOGE("binder_loop: ioctl failed (%s)/n", strerror(errno));
- break;
- }
- res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
- if (res == 0) {
- LOGE("binder_loop: unexpected reply?!/n");
- break;
- }
- if (res < 0) {
- LOGE("binder_loop: io error %d %s/n", res, strerror(errno));
- break;
- }
- }
- }
注意BINDER_SERVICE_MANAGER.
- /* the one magic object */
- #define BINDER_SERVICE_MANAGER ((void*) 0)
BINDER_SERVICE_MANAGER是向service_manager注册的句柄(handle),其它进程必须通过它来跟service_manager通信。
获取IserviceManager
得到IServiceManager实例的唯一方法是调用IServiceManager.cpp实现的defaultServiceManager接口。
- sp<IServiceManager> defaultServiceManager()
- {
- if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
- {
- AutoMutex _l(gDefaultServiceManagerLock);
- if (gDefaultServiceManager == NULL) {
- gDefaultServiceManager = interface_cast<IServiceManager>(
- ProcessState::self()->getContextObject(NULL));
- }
- }
- return gDefaultServiceManager;
- }
gDefaultServiceManager在libutil内有定义,所以使用到该对象的程序都要包含该头文件。gDefaultServiceManager初始值为NULL,因此第一次运行时,会通过调用ProcessState::self()获得ProcessState实例。每个进程只能有一个这样的实例。ProcessState会打开“/dev/binder”驱动提供给IPCThreadState使用。
- ProcessState::ProcessState()
- : mDriverFD(open_driver())
现在我们有了一个ProcessState实例,再来看看getContextObject。
- sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
- {
- if (supportsProcesses()) {
- return getStrongProxyForHandle(0);
- } else {
- return getContextObject(String16("default"), caller);
- }
- }
我们的板子支持binder驱动,所以进入getStrongProxyForHandle。(Handle 0为service manager保留,后续会解释原因。)
- sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
- {
- sp<IBinder> result;
- AutoMutex _l(mLock);
- handle_entry* e = lookupHandleLocked(handle);
- 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)) {
- b = new BpBinder(handle);
- 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;
- }
初次b将会是NULL,所以这段代码会new 一个BpBinder实例。BpBinder是一个远程binder对象的代理类。
- BpBinder::BpBinder(int32_t handle)
- : mHandle(handle)
- , mAlive(1)
- , mObitsSent(0)
- , mObituaries(NULL)
- {
- LOGV("Creating BpBinder %p handle %d/n", this, mHandle);
- extendObjectLifetime(OBJECT_LIFETIME_WEAK);
- IPCThreadState::self()->incWeakHandle(handle);
- }
IPCThreadState::incWeakHandle将添加一个BC_INCREFS的命令到输出buffer
- void IPCThreadState::incWeakHandle(int32_t handle)
- {
- LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)/n", handle);
- mOut.writeInt32(BC_INCREFS);
- mOut.writeInt32(handle);
- }
现在getContextObject返回了一个BpBinder的实例,它将通过interface_cast转换为IServiceManager.interface_cast在IInterface.h有定义,展开如下:
- inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
- {
- return IServiceManager::asInterface(obj);
- }
现在我们来看看IServiceManager的定义
- class IServiceManager : public IInterface
- {
- public:
- DECLARE_META_INTERFACE(ServiceManager);
- /**
- * Retrieve an existing service, blocking for a few seconds
- * if it doesn't yet exist.
- */
- virtual sp<IBinder> getService( const String16& name) const = 0;
- /**
- * Retrieve an existing service, non-blocking.
- */
- virtual sp<IBinder> checkService( const String16& name) const = 0;
- /**
- * Register a service.
- */
- virtual status_t addService( const String16& name,
- const sp<IBinder>& service) = 0;
- /**
- * Return list of all existing services.
- */
- virtual Vector<String16> listServices() = 0;
- enum {
- GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- CHECK_SERVICE_TRANSACTION,
- ADD_SERVICE_TRANSACTION,
- LIST_SERVICES_TRANSACTION,
- };
- };
DECLARE_META_INTERFACE是在IInterface.h中定义的一个宏,展开如下:
- static const String16 descriptor;
- static sp<IServiceManager> asInterface(const sp<IBinder>& obj);
- virtual String16 getInterfaceDescriptor() const;
如你所见,DECLARE_META_INTERFACE宏生命了两个函数,这两个函数将在IServiceManager.cpp中被实现
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
代码展开如下:
- const String16 IServiceManager::descriptor(NAME);
- String16 IServiceManager::getInterfaceDescriptor() const {
- return IServiceManager::descriptor;
- }
- sp<IServiceManager> IServiceManager::asInterface(const sp<IBinder>& obj)
- {
- sp<IServiceManager> intr;
- if (obj != NULL) {
- intr = static_cast<IServiceManager*>(
- obj->queryLocalInterface(
- IServiceManager::descriptor).get());
- if (intr == NULL) {
- intr = new BpServiceManager(obj);
- }
- }
- return intr;
- }
所以IServiceManager::asInterface最终会new一个BpServiceManager实例,并且返回给用户。BpServiceManager作为远程BnServiceManager的代理。任何在IServiceManager操作现在实际上是调用BpServiceManager相应的虚函数。
摘要:
这个部分给出了如何获取远程对象的代理对象,加入你想实现你自己的服务IFunnyTest,你必须完成下面的步骤:
1、将DECLARE_META_INTERFACE(FunnyTest)宏写进你的接口头文件(interface header file)。
2、讲IMPLEMENT_META_INTERFACE(Funnytest, “your unique name”)宏放进你的接口源文件(interface source file)。
3、实现你自己的BpFunnyTest类。
触发AudioFlinger服务
media_server系统讲会启动AudioFlinger服务,代码如下:
- int main(int argc, char** argv)
- {
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- LOGI("ServiceManager: %p", sm.get());
- AudioFlinger::instantiate();
- MediaPlayerService::instantiate();
- CameraService::instantiate();
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- }
AudioFlinger将会调用ServiceManager::addService,这是个远程调用(RPC)。
- void AudioFlinger::instantiate() {
- defaultServiceManager()->addService(
- String16("media.audio_flinger"), new AudioFlinger());
- }
AudioFlinger继承字BnAudioFlinger,BnAudioFlinger是BnInterface的模板(template);
- class BnAudioFlinger : public BnInterface<IAudioFlinger>
- {
- public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
- };
BnInterface继承自BBinder.
- template<typename INTERFACE>class BnInterface : public INTERFACE, public BBinder
- {
- public:
- virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
- virtual String16 getInterfaceDescriptor() const;
- protected:
- virtual IBinder* onAsBinder();
- };
- template<typename INTERFACE>
- IBinder* BnInterface<INTERFACE>::onAsBinder()
- {
- return this;
- }
根据BnInterface的实现,我们知道传给IServiceManager::addService的参数实际上是一个AudioFlinger实例的地址,BBinder继承自IBinder,它的transact函数将会调用虚函数onTransact。
- 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:
- reply->writeInt32(pingBinder());
- break;
- default:
- err = onTransact(code, data, reply, flags);
- break;
- }
- if (reply != NULL) {
- reply->setDataPosition(0);
- }
- return err;
- }
这里面最重要的函数就是onTransact。BnAudioFlinger会实现这个虚函数,在这里,我们只需要专注于SET_MODE这个分支。
- status_t BnAudioFlinger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- switch(code) {
- case SET_MODE: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- int mode = data.readInt32();
- reply->writeInt32( setMode(mode) );
- return NO_ERROR;
- } break;
media_server将会通过IPCThreadState::joinThreadPool进入一个循环,就向service_manager一样,它会在talkWithDriver里面等待来自其它进程的数据。
- void IPCThreadState::joinThreadPool(bool isMain)
- {
- mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
- status_t result;
- do {
- int32_t cmd;
- result = talkWithDriver();
- if (result >= NO_ERROR) {
- size_t IN = mIn.dataAvail();
- if (IN < sizeof(int32_t)) continue;
- cmd = mIn.readInt32();
- result = executeCommand(cmd);
- }
- // 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);
- mOut.writeInt32(BC_EXIT_LOOPER);
- talkWithDriver(false);
- }
假如你想实现自己的IFunnyTest服务,你必须做到洗面几点:
1、实现你自己的BnFunnyTest类
2、在你的服务运行的进程里,调用IPCThreadState::joinThreadPool开始binder循环。
远程调用(RPC Call)IServiceManager::addService
我们调用IServiceManager::addService,其实是调用BpServiceManager::addService。
- virtual status_t addService(const String16& name, const sp<IBinder>& service){
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- data.writeStrongBinder(service);
- status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
- return err == NO_ERROR ? reply.readInt32() : err;
- }
Parcel很简单,我们把它想象成一个连续的buffer。这里要注意,service这个参数只想BBinder对象(AudioFlinger继承自Bn)
- status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
- {
- return flatten_binder(ProcessState::self(), val, this);
- }
flatten_binder将会触发一个Binber指令。因为BBinder是一个本地(local)的binder对象,所以我们的代码分支将会标识成红色
- status_t flatten_binder(const sp<ProcessState>& proc,
- const sp<IBinder>& binder, Parcel* out)
- {
- flat_binder_object obj;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (binder != NULL) {
- IBinder *local = binder->localBinder();
- if (!local) {
- BpBinder *proxy = binder->remoteBinder();
- if (proxy == NULL) {
- LOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_HANDLE;
- obj.handle = handle;
- obj.cookie = NULL;
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = local->getWeakRefs();
- obj.cookie = local;
- }
- }
- return finish_flatten_binder(binder, obj, out);
- }
注意这几行红色的代码,local的地址放入(稍候会用到)。等到addService这个远程调用(RPC)用到的数据包(packet)打包好后,BpServiceManager::addService将会调用BpBinder的transact方法。
- 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;
- }
BpBinder调用IPCThreadState::transact开始将binder对象传送给对应的句柄(mHandler),在这里,mHandler为0。(也就是传送给service manager这个服务)。
- 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 (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);
- }
- if (err != NO_ERROR) {
- if (reply) reply->setError(err);
- return (mLastError = err);
- }
- if ((flags & TF_ONE_WAY) == 0) {
- if (reply) {
- err = waitForResponse(reply);
- } else {
- Parcel fakeReply;
- err = waitForResponse(&fakeReply);
- }
- } else {
- err = waitForResponse(NULL, NULL);
- }
- return err;
- }
IPCThreadState::transact开始会调用writeTransactionData为binder的内核驱动构造一个传输数据的结构体,注意以下代码,这对binder内核驱动区分传输目标(transaction target)非常重要。
- 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.handle = handle;
- tr.code = code;
- tr.flags = binderFlags;
- 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(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 = statusBuffer;
- tr.offsets_size = 0;
- tr.data.ptr.offsets = NULL;
- } else {
- return (mLastError = err);
- }
- mOut.writeInt32(cmd);
- mOut.write(&tr, sizeof(tr));
- return NO_ERROR;
- }
然后waitForResponse会调用talkWithDriver,ioctl设置为BINDER_WRITE_READ。
- #if defined(HAVE_ANDROID_OS)
- if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
- err = NO_ERROR;
- else
- err = -errno;
- #else
现在,数据已经传送给了binder内核驱动。
摘要:
代理对象会触发一个需要数据包的RPC,然后调用BINDER_WRITE_READ将数据包传给binder内核驱动。这个数据包是一个格式化的包,对与RPC,它使用的包类型是BC_TRANSACTION
假定你想实现你自己的IfunnyTest,你必须完成下面几点:
在你的服务运行的进程里面,调用IServiceManager::addService想service_manager注册你的服务
在Binber内核驱动里面的传输
当任何进程打开“/dev/binder”驱动的时候,一个对应的binder_proc结构将会传递给binder_open。
- static int binder_open(struct inode *nodp, struct file *filp)
- {
- struct binder_proc *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);
- mutex_lock(&binder_lock);
- binder_stats.obj_created[BINDER_STAT_PROC]++;
- hlist_add_head(&proc->proc_node, &binder_procs);
- proc->pid = current->group_leader->pid;
- INIT_LIST_HEAD(&proc->delivered_death);
- filp->private_data = proc;
- mutex_unlock(&binder_lock);
- if (binder_proc_dir_entry_proc) {
- char strbuf[11];
- snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
- create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc,
- binder_read_proc_proc, proc);
- }
- return 0;
- }
所以,当任何ioctl到来的时候,驱动都知道他的进程信息,传输数据是通过BINDER_WRITE_READ的ioctl来传送的。
- case BINDER_WRITE_READ: {
- struct binder_write_read bwr;
- if (size != sizeof(struct binder_write_read)) {
- ret = -EINVAL;
- goto err;
- }
- if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
- ret = -EFAULT;
- goto err;
- }
- if (bwr.write_size > 0) {
- ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer,
- bwr.write_size, &bwr.write_consumed);
- if (ret < 0) {
- bwr.read_consumed = 0;
- if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
- ret = -EFAULT;
- goto err;
- }
- }
- if (bwr.read_size > 0) {
- ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer,
- bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
- if (!list_empty(&proc->todo))
- wake_up_interruptible(&proc->wait);
- if (ret < 0) {
- if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
- ret = -EFAULT;
- goto err;
- }
- }
- if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
- ret = -EFAULT;
- goto err;
- }
- break;
- }
驱动首先进行写操作,我们先看看binder_thread_write。binder_thread_write的核心,是一个循环,它将指令打包写到buffer里面,然后执行响应的指令。
- uint32_t cmd;
- void __user *ptr = buffer + *consumed;
- void __user *end = buffer + size;
- while (ptr < end && thread->return_error == BR_OK) {
- if (get_user(cmd, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
- binder_stats.bc[_IOC_NR(cmd)]++;
- proc->stats.bc[_IOC_NR(cmd)]++;
- thread->stats.bc[_IOC_NR(cmd)]++;
- }
- switch (cmd) {
- case ***:
- default:
- printk(KERN_ERR "binder: %d:%d unknown command %d/n", proc->pid,
- thread->pid, cmd);
- return -EINVAL;
- }
- *consumed = ptr - buffer;
- }
我们看看其中的两个指令,一个是BC_INCREFS.
- case BC_INCREFS:
- case BC_ACQUIRE:
- case BC_RELEASE:
- case BC_DECREFS: {
- uint32_t target;
- struct binder_ref *ref;
- const char *debug_string;
- if (get_user(target, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (target == 0 && binder_context_mgr_node &&
- (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
- ref = binder_get_ref_for_node(proc,
- binder_context_mgr_node);
- } else
- ref = binder_get_ref(proc, target);
- if (ref == NULL) {
- binder_user_error("binder: %d:%d refcou"
- "nt change on invalid ref %d/n",
- proc->pid, thread->pid, target);
- break;
- }
- switch (cmd) {
- case BC_INCREFS:
- debug_string = "IncRefs";
- binder_inc_ref(ref, 0, NULL);
- break;
- }
- break;
记住,我们上面提到,在这里,我们的目标(target)是0,当system_manager调用BINDER_SET_CONTEXT_MGR这个ioctl的时候,binder_context_mgr_node代表0。所以这里仅仅是将binder_context_mgr_node节点的弱应用(weak reference)增加1.。
binder_context_mgr_node = binder_new_node(proc, NULL);
另一个指令是BC_TRANSACTION.
- case BC_TRANSACTION:
- case BC_REPLY: {
- struct binder_transaction_data tr;
- if (copy_from_user(&tr, ptr, sizeof(tr)))
- return -EFAULT;
- ptr += sizeof(tr);
- binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
- break;
- }
假如数据包里面包含BINDER_TYPE_BINDER这个flattened对象的话,binder_transaction将会创建一个信的binder节点。
- fp = (struct flat_binder_object *)(t->buffer->data + *offp);
- switch (fp->type) {
- case BINDER_TYPE_BINDER:
- case BINDER_TYPE_WEAK_BINDER: {
- struct binder_ref *ref;
- struct binder_node *node = binder_get_node(proc, fp->binder);
- if (node == NULL) {
- node = binder_new_node(proc, fp->binder);
- if (node == NULL) {
- return_error = BR_FAILED_REPLY;
- goto err_binder_new_node_failed;
- }
- node->cookie = fp->cookie;
- }
- ref = binder_get_ref_for_node(target_proc, node);
- if (ref == NULL) {
- return_error = BR_FAILED_REPLY;
- goto err_binder_get_ref_for_node_failed;
- }
- if (fp->type == BINDER_TYPE_BINDER)
- fp->type = BINDER_TYPE_HANDLE;
- else
- fp->type = BINDER_TYPE_WEAK_HANDLE;
- fp->handle = ref->desc;
- binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);
- if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
- printk(KERN_INFO " node %d u%p -> ref %d desc %d/n",
- node->debug_id, node->ptr, ref->debug_id, ref->desc);
- } break;
binder_transaction会知道目标是句柄(handle)0,所以运行下列分支,找到target_node, target_proc和target_thread
- } else {
- target_node = binder_context_mgr_node;
- if (target_node == NULL) {
- return_error = BR_DEAD_REPLY;
- goto err_no_context_mgr_node;
- }
- }
- e->to_node = target_node->debug_id;
- target_proc = target_node->proc;
- if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
- struct binder_transaction *tmp;
- tmp = thread->transaction_stack;
- while (tmp) {
- if (tmp->from && tmp->from->proc == target_proc)
- target_thread = tmp->from;
- tmp = tmp->from_parent;
- }
- }
最终,binder_transaction会讲请求放入列表,唤醒等待binder_thread_read里面的线程。
- t->work.type = BINDER_WORK_TRANSACTION;
- list_add_tail(&t->work.entry, target_list);
- tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
- list_add_tail(&tcomplete->entry, &thread->todo);
- if (target_wait)
- wake_up_interruptible(target_wait);
现在我们来看看binder_thread_read。当service_manager跑起来后,它会在这里等待一直到有请求到来。
- ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc,thread));
因为之前media_server进程的写请求已经把它唤醒了,所以继续执行。下面的代码是从media_server的写buffer拷贝到system_manager的读buffer
- tr.data_size = t->buffer->data_size;
- tr.offsets_size = t->buffer->offsets_size;
- tr.data.ptr.buffer = (void *)((void *)t->buffer->data + proc->user_buffer_offset);
- tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));
- if (put_user(cmd, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (copy_to_user(ptr, &tr, sizeof(tr)))
- return -EFAULT;
- ptr += sizeof(tr);
摘要:
这部分展示了RPC的客户端和服务端的数据流向。
Service Manager 处理 Add Service请求
直到现在,service_manager已经从madia_server的BR_TRANSACTION数据包,然后调用binder_paser处理这个数据包。
- case BR_TRANSACTION: {
- if (func) {
- unsigned rdata[256/4];
- struct binder_io msg;
- struct binder_io reply;
- int res;
- bio_init(&reply, rdata, sizeof(rdata), 4);
- bio_init_from_txn(&msg, txn);
- res = func(bs, txn, &msg, &reply);
- binder_send_reply(bs, &reply, txn->data, res);
- }
- ptr += sizeof(*txn) / sizeof(uint32_t);
- break;
- }
binder_parser调用svcmgr_handler解析BR_TRANSACTION包,跟BpServerManager进程相反。这里的结构体binder_txn实际上跟binder_transaction_data相同。在这里,传输码(transaction code)是SVC_MGR_ADD_SERVICE.
- binder_parser will call svcmgr_handler to parse BR_TRANSACTION packet, which is the reverse
- process of BpServerManager. Here structure binder_txn actually is the same with structure
- binder_transaction_data. In our scenario, the transaction code is SVC_MGR_ADD_SERVICE.
- int svcmgr_handler(struct binder_state *bs,
- struct binder_txn *txn,
- struct binder_io *msg,
- struct binder_io *reply)
- {
- struct svcinfo *si;
- uint16_t *s;
- unsigned len;
- void *ptr;
- if (txn->target != svcmgr_handle)
- return -1;
- s = bio_get_string16(msg, &len);
- if ((len != (sizeof(svcmgr_id) / 2)) ||
- memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
- fprintf(stderr,"invalid id %s/n", str8(s));
- return -1;
- }
- switch(txn->code) {
- case SVC_MGR_ADD_SERVICE:
- s = bio_get_string16(msg, &len);
- ptr = bio_get_ref(msg);
- if (do_add_service(bs, s, len, ptr, txn->sender_euid))
- return -1;
- break;
因此,service_manager知道这个服务即将启动,并且调用bio_get_ref来获取服务的信息。
- void *bio_get_ref(struct binder_io *bio)
- {
- struct binder_object *obj;
- obj = _bio_get_obj(bio);
- if (!obj)
- return 0;
- if (obj->type == BINDER_TYPE_HANDLE)
- return obj->pointer;
- return 0;
- }
bio_get_ref做了flatten_binder完全相反的工作。do_add_service最终通过调用BC_ACQUIRE得到一个对象的强引用,由ptr指向它。
摘要:
这部分展示了服务怎么添加到service manager中去。
假如你想实现你自己的服务IFunnyTest,你必须完成一下步骤:
1、将你的服务名字添加到service_manager的服务列表里去
获取IaudioFlinger
获取service接口的唯一途径是通过调用IServiceManager::getService。比如说,这里的获取AudioSystem的方法是IAudioFlinger.
- / establish binder interface to AudioFlinger service
- const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
- {
- Mutex::Autolock _l(gLock);
- if (gAudioFlinger.get() == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16("media.audio_flinger"));
- if (binder != 0)
- break;
- LOGW("AudioFlinger not published, waiting...");
- usleep(500000); // 0.5 s
- } while(true);
- gAudioFlinger = interface_cast<IAudioFlinger>(binder);
- }
- LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
- return gAudioFlinger;
- }
- IServiceManager::getService会调用BpServiceManager::getService.
- virtual sp<IBinder> getService(const String16& name) const
- {
- unsigned n;
- for (n = 0; n < 5; n++){
- sp<IBinder> svc = checkService(name);
- if (svc != NULL) return svc;
- LOGI("Waiting for sevice %s.../n", String8(name).string());
- sleep(1);
- }
- return NULL;
- }
- virtual sp<IBinder> checkService( const String16& name) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
- return reply.readStrongBinder();
- }
就跟刚才分析的一样,这个调用最终会通过binder内核驱动被service_manager处理。
- switch(txn->code) {
- case SVC_MGR_GET_SERVICE:
- case SVC_MGR_CHECK_SERVICE:
- s = bio_get_string16(msg, &len);
- ptr = do_find_service(bs, s, len);
- if (!ptr)
- break;
- bio_put_ref(reply, ptr);
- return 0;
然后service_manager会返回一个先前的句柄(previous handle),这个句柄由media_server设置,实际上就是AudioFlinger实例的地址。然后BpServiceManager::checkService会从remote()->transact调用中返回。然后,就像在IServiceManager中分析的一样,它将创建一个新的BpBinder实例,对应service_manager返回的handle,interface_cast<IAudioFlinger>(binder)最终返回一个BpAudioFlinger实例。
摘要
就想获取IServieManager一样,但是这次需要获取一个service_manager的handle,当然我们的IServiceManager的handle总是为0.
远程调用IAudioFlinger::SetMode
加入我们在AAA进程中调用IAudioFlinger::SetMode,实际上我们调用的是
- BpAudioFlinger::setMode.
- virtual status_t setMode(int mode)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(mode);
- remote()->transact(SET_MODE, data, &reply);
- return reply.readInt32();
- }
就像分析IServiceManager::addService一样,这个函数将会出发一个数据包,并写入binder驱动内核,等待读应答。唯一的不同点是target handle指向了media_server进程的某些地址。
处理 IAudioFlinger::SetMode
Binder内核驱动最终会唤醒在media_server进程中运行在IPCThreadState::joinThreadPool的读线程,现在我们再来看看这段代码:
- oid IPCThreadState::joinThreadPool(bool isMain)
- mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
- status_t result;
- do {
- int32_t cmd;
- result = talkWithDriver();
- if (result >= NO_ERROR) {
- size_t IN = mIn.dataAvail();
- if (IN < sizeof(int32_t)) continue;
- cmd = mIn.readInt32();
- result = executeCommand(cmd);
- }
- // 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);
- mOut.writeInt32(BC_EXIT_LOOPER);
- talkWithDriver(false);
这一次,talkWithDriver讲返回BpServiceManager::setMode生成的数据包,然后executeCommand会处理这些命令,在这里,命令是BR_TRANSACTION.
- case BR_TRANSACTION:
- {
- binder_transaction_data tr;
- Parcel reply;
- if (tr.target.ptr) {
- sp<BBinder> b((BBinder*)tr.cookie);
- const status_t error = b->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
- } else {
- const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
- }
- if ((tr.flags & TF_ONE_WAY) == 0) {
- LOG_ONEWAY("Sending reply to %d!", mCallingPid);
- sendReply(reply, 0);
- } else {
- LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
- }
- }
- break;
最重要的两行已经标记为红色,这里获取了从binder内核驱动的地址,并且强制转换为BBinder指针(这个地址当调用IServiceManager::addService时传给了binder内核驱动)。记住,AudioFlinger是派生自Bbinder。这个指针实际上指向的就是我们的AudioFlinger实例。所以写下来的trancat调用最终会调用我们BnAudioFlinger的onTransact这个虚函数。
- status_t BnAudioFlinger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- case SET_MODE: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- int mode = data.readInt32();
- reply->writeInt32( setMode(mode) );
- return NO_ERROR;
- } break;
- }
然后将通过调用sendReply将应答写回去。
- status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
- {
- status_t err;
- status_t statusBuffer;
- err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
- if (err < NO_ERROR) return err;
- return waitForResponse(NULL, NULL);
- }
它最终写到binder内核驱动里去,内核驱动最后会唤醒AAA进程的读线程。
摘要
Service_manager<---->service provider<------->service user
| | |
| | |
| | |
| | |
------------------------>Binder Driver<-----------------
这是Android IPC系统的大致架构,分为四大块。
1、Binder Driver
这是IPC系统的核心,负责service provider 和service user之间的数据传输
2、service provider
它提供一些服务,它解析来自binder driver的数据,并且真正执行动作。
3、service_manager
这是一个特殊的服务。它为其它的服务提供管理服务。
4、service user
它远程调用service provider,出发一个RPC调用,并将数据传入binder driver
在我们所列举的场景里面,下面列举出了主要的控制流程
1、service_manager首先运行,它想binder driver注册特殊的节点0
2、Media_server 获取特殊节点0的IServiceManager代理对象
3、media_server通过RPC调用IServiceManager::addService添加IAudioFlinger服务,
这个调用的目的节点为0。然后向binder driver发送数据。
4、Binder driver知道数据是给节点0的,然后数据包含了创建新节点的指令,因此它为IAudioFlinger创建另外一个节点(假如为A),表示service_manager.
5、service_manager读取来自binder driver的数据,然后处理IServiceManager::addService的RPC调用
6、另外一个进程P获取特殊节点0的IServiceManager对象
7、P通过RPC调用IServiceManager::getService获取IAudioFlinger服务。这个调用追溯到节点0,它发送据给binder driver
8、Binder driver知道数据是给节点0的,所以它把数据传给service_manager.
9、service_manager读取从binder driver传上来的数据,处理IServiceManager::getService调用,将代表IAudioFlinger服务的节点A发回给binder driver
10、P 通过RPC调用l IAudioFlinger::setMode. 现在这个调用追溯的节点是A.
11、Binder driver知道数据是给节点A的,所以它把数据传给media_server.
12、media_server读取数据,处理IAudioFlinger::setMode调用,将结果发回给binder driver
13、Binder driver讲结果发回给进程P
14、P从binder driver读取数据,这样最终的结果就得到了
0 0
- Android IPC机制Binder解析
- Android IPC机制Binder解析
- Android Binder IPC机制
- Android的IPC机制-Binder
- android的IPC机制 - Binder
- Android的IPC机制Binder
- Android的IPC机制-Binder
- Android的IPC机制Binder
- Android IPC之Binder机制
- Android IPC机制 Binder学习
- 深入理解 Android 的 IPC 机制--------Binder
- Binder---- Android 的IPC 通信机制
- Android进程间通信IPC机制Binder
- Binder---- Android 的IPC 通信机制
- Binder---- Android 的IPC 通信机制
- Binder---- Android 的IPC 通信机制
- 技术内幕:Android的IPC机制-Binder
- Binder---- Android 的IPC 通信机制
- 案例——用户登录注册xml版
- Qualcomm msm8974 编译
- 通过SMART法则进行网站策划
- #Flex开发# 找不到所需Adobe Flash Player调试版本
- (MultipartHttpServletRequest) request对象转换错误
- Android IPC机制Binder解析
- 黑马程序员---泛型
- python 目录操作
- uva 11504 - Dominos (scc)
- 异步上传文件并获得返回值(完全跨域)
- 进程间通信——管道
- hello csdn!
- jdbc注册驱动三种方式
- Android二维码扫描+开闪光灯