当前位置:主页 > 查看内容

Android Binder驱动分析四 addservice源码分析

发布时间:2021-04-25 00:00| 位朋友查看

简介:Android Binder驱动分析三 addservice源码分析 接着上网我们分析了如下的代码 将事务添加到 servicemanager 然后将其唤醒 添加一个 binder_work 事务给 mediaplayserice 我们这里分析 mediaplayservice 提交事务后会做什么 //drivers/staging/android/binder……

Android Binder驱动分析三 addservice源码分析

接着上网我们分析了如下的代码:

  1. 将事务添加到servicemanager,然后将其唤醒
  2. 添加一个binder_work事务给mediaplayserice

我们这里分析mediaplayservice提交事务后会做什么

//drivers/staging/android/binder.c


static int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread)
{
	int ret = 0;
	struct binder_proc *proc = filp->private_data;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;
	struct binder_write_read bwr;

    //从用户空间的arg的地址处拷贝到内核
    //ubuf = arg
	if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
		ret = -EFAULT;
		goto out;
	}
    //因为有数据传入所以不为0
	if (bwr.write_size > 0) {
	
	//	1. 将事务添加到`servicemanager`,然后将其唤醒
	//	2. 添加一个`binder_work`事务给`mediaplayserice` 
		ret = binder_thread_write(proc, thread,
					  bwr.write_buffer,
					  bwr.write_size,
					  &bwr.write_consumed);
	
	}
	
	//这里不为空,表示想接收binder驱动的信息
	if (bwr.read_size > 0) {
			ret = binder_thread_read(proc, thread, bwr.read_buffer,
					 bwr.read_size,
					 &bwr.read_consumed,
					 filp->f_flags & O_NONBLOCK);
		
		//如果还有未处理的任务唤醒线程,但是这里没有没有其他事务所以不会进入下面的代码
		if (!binder_worklist_empty_ilocked(&proc->todo))
			binder_wakeup_proc_ilocked(proc);
	
			goto out;
		}
	}
	//binder驱动将修改过后的bwr传回用户空间(mediaplayservice)
	//可见内存共享仅针对于服务端来说,客户端的读写还是要拷贝滴
	if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
		ret = -EFAULT;
		goto out;
	}
out:
	return ret;
}





//ret = binder_thread_read(proc, thread, bwr.read_buffer,
//				 bwr.read_size,
//				 &bwr.read_consumed,
//				 filp->f_flags & O_NONBLOCK);

static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{
	void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
	void __user *ptr = buffer + *consumed;
	void __user *end = buffer + size;

	int ret = 0;
	int wait_for_proc_work;
	//这里是0所以放入BR_NOOP
	if (*consumed == 0) {
		if (put_user(BR_NOOP, (uint32_t __user *)ptr))
			//失败处理
			return -EFAULT;
		//指针偏移
		ptr += sizeof(uint32_t);
	}



	while (1) {
		
		uint32_t cmd;
		struct binder_transaction_data_secctx tr;
		struct binder_transaction_data *trd = &tr.transaction_data;
		struct binder_work *w = NULL;
		struct list_head *list = NULL;
		struct binder_transaction *t = NULL;
		struct binder_thread *t_from;
		size_t trsize = sizeof(*trd);


		//一个程序的待处理任务会在线程或进程todo列表中
		//这里是取出列表对象
		if (!binder_worklist_empty_ilocked(&thread->todo))
			list = &thread->todo;
		else if (!binder_worklist_empty_ilocked(&proc->todo) &&
			   wait_for_proc_work)
			list = &proc->todo;
		//是否还有数据要读取
		if (end - ptr < sizeof(tr) + 4) {
			break;
		}

		//取出列表对象,这里就是上篇文章的的内容tcomplete    
		w = binder_dequeue_work_head_ilocked(list);

		switch (w->type) {
	
			case BINDER_WORK_TRANSACTION_COMPLETE: {
				cmd = BR_TRANSACTION_COMPLETE;
				//放入一个命令BR_TRANSACTION_COMPLETE
				if (put_user(cmd, (uint32_t __user *)ptr))
				
					return -EFAULT;
				//指针后移
				ptr += sizeof(uint32_t);

				
				kfree(w);
				
			} break;
		
		}

		

		
	}

done:
	//注意consume变成写入的数值大小
	//比如buffer是100      写入64 
	//ptr初始值=100   写入64为164.和原始地址先减去可以到写入的字节大小
	*consumed = ptr - buffer;
	
	//这里用于让用户空间新生成一个线程,这里我们先无视,就当没有写入
	if (proc->requested_threads == 0 &&
	    list_empty(&thread->proc->waiting_threads) &&
	    proc->requested_threads_started < proc->max_threads &&
	    (thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
	     BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
	     /*spawn a new thread if we leave this out */) {
		proc->requested_threads++;
	
	
		if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
			return -EFAULT;
		binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
	}
		 
	return 0;
}


可见binder驱动给mediaplayservice提交了两个主要命令BR_NOOPBR_TRANSACTION_COMPLETE 就返回用户空间

也就是以下代码:

// frameworks\native\libs\binder\IPCThreadState.cpp

status_t IPCThreadState::talkWithDriver(bool doReceive=true)
{

   	//略
    do {
       
		//将我们的内容发送给binder驱动,这时从驱动返回
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        
       
    } while (err == -EINTR);

   
    //binder驱动会修改bwr
    if (err >= NO_ERROR) {
        //运行到这时候binder驱动会消费我们传入bwr.write_buffer,具体消费了多个字节就是write_consumed
        if (bwr.write_consumed > 0) {
        	//将这个重置后继续下次使用
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        //binder驱动会顺带返回信息,返回的信息的大小是read_consumed
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
 
        return NO_ERROR;
    }
    
    return err;
}

没有太特殊继续向上层函数返回

以下函数首先读取BR_NOOP 后再进入循环调用talkWithDriver()后在读取信息,等返回后在处理BR_TRANSACTION_COMPLETE

// frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;

    while (1) {
    	//返回到这继续向下走
        if ((err=talkWithDriver()) < NO_ERROR) break;
        
      	//如果没有返回信息那么继续循环读取binder驱动
        if (mIn.dataAvail() == 0) continue;
        //读取binder驱动返回的前4字节,这四个字节表示binder驱动是什么消息类型
        cmd = (uint32_t)mIn.readInt32();
        
		//根据返回的binder返回的命令做出操作
		//首先读取BR_NOOP
        switch (cmd) {
        
	        case BR_TRANSACTION_COMPLETE:
	        //这里reply不为空,acquireResult为NULL
	         //所以!reply && !acquireResult 为false,因此继续循环进入talkWithDriver等
	         if (!reply && !acquireResult) goto finish;
            break;
	        case BR_DEAD_REPLY:
			//..略
	        case BR_FAILED_REPLY:
	        //..略          
	        case BR_ACQUIRE_RESULT:
	        //..略  
	        case BR_REPLY:
            //..略
        	default:
        		//BR_NOOP在内部什么都不做,继续循环进入talkWithDriver
            	err = executeCommand(cmd);
            	if (err != NO_ERROR) goto finish;
        }
    }
    return err;
}


status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;
    
    switch (cmd) {
  	//略
    case BR_NOOP:
        break;
   }
    return result;
}


第一次读取BR_NOOP没有太多特殊的情况于是乎继续进入talkWithDriver()


status_t IPCThreadState::talkWithDriver(bool doReceive)
{
 
    
    binder_write_read bwr;
    
    //因为dataPosition还有4字节没有读取,
    //假设dataSize为8字节,分别存放`BR_NOOP` 和`BR_TRANSACTION_COMPLETE` 
    //读取`BR_NOOP`后dataPosition为4
    //因此这里为false
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    
    //outAvail 自然为0
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();
	//needRead false
	//doReceive  true
	//这里走到false
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }


    
    // bwr.write_size == 0为true
    //  bwr.read_size == 0 为true
    // 那么整个表达式为true。因此直接返回
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
 

        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;


        if (mProcess->mDriverFD <= 0) {
            err = -EBADF;
        }
      
    } while (err == -EINTR);

  

    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
       
        return NO_ERROR;
    }
    
    return err;
}

talkWithDriver()返回继续读取下一个命令BR_TRANSACTION_COMPLETE 这里由于这个命令也没有特殊的地方,所以会重新再次进入talkWithDriver


status_t IPCThreadState::talkWithDriver(bool doReceive)
{
 
    
    binder_write_read bwr;
    
    //数据读取完`BR_TRANSACTION_COMPLETE`  dataPosition会等于dataSize
  
    //因此这里为true
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    
    //outAvail dataSize
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();
	//needRead true
	//doReceive  true
	//这里走到true
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }


    
 	//这里直接为false
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
 
		//这里在进入binder驱动中
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;


        if (mProcess->mDriverFD <= 0) {
            err = -EBADF;
        }
      
    } while (err == -EINTR);

  

    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
       
        return NO_ERROR;
    }
    
    return err;
}

最后再次进入binder驱动的binder_thread_read函数.


static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{
	void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
	void __user *ptr = buffer + *consumed;
	void __user *end = buffer + size;

	int ret = 0;
	int wait_for_proc_work;

	if (*consumed == 0) {
		if (put_user(BR_NOOP, (uint32_t __user *)ptr))
			return -EFAULT;
		ptr += sizeof(uint32_t);
	}

retry:
	//这里返回false.   binder_available_for_proc_work_ilocked如果有事务就返回true,没有就返回false
	wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);


	
	//这里为
	if (non_block) {
		//;略
	} else {
		//阻塞由于wait_for_proc_work为fakse
		//所以mediaplayservice被阻塞在这
		ret = binder_wait_for_work(thread, wait_for_proc_work);
	}

	//略
	return 0;
}

;原文链接:https://blog.csdn.net/qfanmingyiq/article/details/115427789
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文


随机推荐