Android Binder机制(十) getService详解之请求的发送

梦想与她 提交于 2019-12-12 05:30:32

   Android Binder机制(十) getService详解之请求的发送

   在前面的篇章中,我们以MediaPlayerService为例,介绍了Service服务是如何通过addService请求添加到ServiceManager中的(其中的艰难困苦,你懂的)。本文,将以MediaPlayer获取MediaPlayerService服务为例,来介绍Client端是如何通过getService请求从ServiceManager中获取到Server接入点的。在本文的getService请求中,MediaPlayer是Client端,它要获取的Server接入点是MediaPlayerService。和前面介绍addService篇章一样,在分析getService时,会将文章分为请求的发送,请求的处理,和请求的反馈这三部分来分别进行介绍(不要问我为啥是三部分,因为内容太多)。

注意:本文是基于Android 7.xx版本进行介绍的



getService整体概述

   老规矩,在大讲特讲之前,还是让我们上图说话,这样让读者先从整体上有一个了解,然后再深入细节,这个可不是谈女朋友额。上图:
在这里插入图片描述
猛地一看,你会发现该时序图和Android Binder机制(六) addService详解之请求的发送中的时序图几乎是一模一样的,难道是换了马甲不成,还不允许别人长一个样了啊,天下美女不还都差不多啊。
下面我们分步讲解,一一攻破,手到擒来:
(1) 先是MediaPlayer进程将getService以BC_TRANSACTION事务的方式发给Binder驱动。
(2) Binder驱动收到之后,对内容进行解析;然后唤醒ServiceManager,同时反馈一个BR_TRANSACTION_COMPLETE给MediaPlayer。反馈的BR_TRANSACTION_COMPLETE是告诉MediaPlayer,它的getService请求已经被Binder驱动成功收到。
(3) 接着,MediaPlayer就进入等待状态,等待ServiceManager的反馈。 ServiceManager被唤醒之后,读取Binder驱动传递给它的BR_TRANSACTION事务。在得知是获取MediaPlayerService的请求之后,就从缓冲中取出MediaPlayerService的相关信息;然后和BC_REPLY指令一起反馈给Binder驱动。
(4) Binder驱动收到ServiceManager的反馈之后,将内容进一步反馈给MediaPlayer,并将MediaPlayer唤醒。
(5) MediaPlayer被唤醒之后,从Binder驱动反馈的BR_REPLY中解析出MediaPlayerService的相关信息;这样,MediaPlayer就成功获取到了MediaPlayerService的接入点。



getService的代码解析


1.MediaPlayer的getService入口

const sp<IMediaPlayerService>
IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            ALOGW("Media player service not published, waiting...");
            usleep(500000); // 0.5 s
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}

如上代码是在C++层获取MediaPlayerService代理对象的代码,定义在./frameworks/av/media/libmedia/IMediaDeathNotifier.cpp文件里面,也许会有读者说这个和我们在App看到的获取MediaPlayerService的不一样,这个会在后续说明(最终通过JNI调用到这里),下面来详细解读一下该段代码:
(1) sMediaPlayerService是sp成员,初始化为null。因此if(sMediaPlayerService==0)为true。
(2) 调用defaultServiceManager()获取IServiceManager对象,该对象实际上是BpServiceManager类的实例。defaultServiceManager()的详细流程请参考Android Binder机制(五) defaultServiceManager()的实现,此时可能会出现服务还没有添加成功的可能,那么等待0.5秒继续获取知直到成功。
(3) 接着就是调用sm->getService(String16(“media.player”))获取MediaPlayerService对象。


2.BpServiceManager::getService()

    virtual sp<IBinder> getService(const String16& name) const
    {
        unsigned n;
        for (n = 0; n < 5; n++){//会尝试5次
            if (n > 0) {
                ALOGI("Waiting for service %s...", String8(name).string());
                sleep(1);
            }
            sp<IBinder> svc = checkService(name);
            if (svc != NULL) return svc;
        }
        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();
    }

如上代码在Android源码的frameworks/native/libs/binder/IServiceManager.cpp中,下面我么解读一下该段代码:
(1) getService()是通过调用checkService()来获取IBinder对象的。如果获取失败,它会调用sleep()休眠1ms之后再次尝试;若尝试5次都失败,则返回null。之所以要尝试5次,是由于可能此时MediaPlayerService服务还没有准备好。有没有种谈女朋友向其表白,被拒绝不死心继续表白,如果实在不行那就只能拉到了呗,难不成大老爷们一棵树上吊着不成。
(2) 下面看看checkService(),它和"Android Binder机制(六) addService详解之请求的发送中的addService()"很多内容都相似。 checkService()会先调用writeInterfaceToken()写入一个消息头:“4字节的整型数” + “字符串android.os.IServiceManager”。然后,再调用writeString16(name)将服务名"media.player"写入到data中。 最后,调用remote()->transact()进行事务交互,其中remote()返回的是BpBinder对象。


3.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;
}

如上代码在frameworks/native/libs/binder/BpBinder.cpp中,是不是很熟悉的感觉,它最后会调用IPCThreadState::transact()。


4.IPCThreadState::transact()

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) {
		...
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }  
	...   
    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            err = waitForResponse(reply);
        } else {
			...
        }
		...
    } else {
        ...
    }    
    return err;
}

该代码在frameworks/native/libs/binder/IPCThreadState.cpp中。它会先通过writeTransactionData()将要发送的指令和数据打包到binder_transaction_data中,然后调用waitForResponse()和Binder驱动进行通信。由于在前面addService中已经仔细解读过,在这里就一笔带过了。


5.IPCThreadState::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) {
		...
    } else {
        ...
    }
    
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));
    
    return NO_ERROR;
}

该函数会读取Parcel中的数据,然后将其打包到tr中,tr是binder_transaction_data结构体的对象。之后,将"指令"+"数据"写入到mOut中。指令(cmd)=BC_TRANSACTION,数据就是tr。


6.IPCThreadState::waitForResponse()

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;

    while (1) {
    	//先通过talkWithDriver()和Binder驱动交互
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
        
        //然后读取返回接口,再根据结果进行处理
        cmd = (uint32_t)mIn.readInt32();

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            ...
        case BR_DEAD_REPLY:
            ...
        case BR_FAILED_REPLY:
            ...
        case BR_ACQUIRE_RESULT:
            ...
        case BR_REPLY:
            ...
        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }
finish:
    ...
    return err;
}

如果读者有细读addService的章节,那么这里就so easy了,waitForResponse()会先调用talkWithDriver()和Binder驱动交互,然后根据反馈结果来进行处理。


7.IPCThreadState::talkWithDriver()

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
	...
    binder_write_read bwr;
    
    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
	...
    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;
		...
    } 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()会先初始化bwr(binder_write_read类型的变量),然后将bwr通过ioctl()发送给Binder驱动。初始化之后的bwr各个成员的值如下:

bwr.write_size = outAvail;                          // mOut中数据大小,大于0
bwr.write_buffer = (long unsigned int)mOut.data();  // mOut中数据的地址
bwr.write_consumed = 0;
bwr.read_size = mIn.dataCapacity();                 // 256
bwr.read_buffer = (long unsigned int)mIn.data();    // mIn.mData,实际上为空
bwr.read_consumed = 0;

bwr初始化完成之后,调用ioctl(,BINDER_WRITE_READ,)和Binder驱动进行交互。


8.Binder驱动中binder_ioctl()的BINDER_WRITE_READ相关部分的源码

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;

	...
	//中断等待函数
	// 1. 当binder_stop_on_user_error < 2为true时;不会进入等待状态;直接跳过。
	// 2. 当binder_stop_on_user_error < 2为false时,进入等待状态。
	//    当有其他进程通过wake_up_interruptible来唤醒binder_user_error_wait队列,并且binder_stop_on_user_error < 2为true时;
	//    则继续执行;否则,再进入等待状态。
	ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
	...
	
	binder_lock(__func__);
	//在proc进程中查找该线程对应的binder_thread;若查找失败,则新建一个binder_thread,并添加到proc->threads中。
	thread = binder_get_thread(proc);
	...
	
	switch (cmd) {
	case BINDER_WRITE_READ: {
		struct binder_write_read bwr;
		...
		
		//将binder_write_read从“用户空间”拷贝到“内核空间”
		if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
			ret = -EFAULT;
			goto err;
		}
		...

		//如果write_size>0,则进行写操作
		if (bwr.write_size > 0) {
			ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
			...
		}
		//如果read_size>0,则进行读操作
		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 (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
			ret = -EFAULT;
			goto err;
		}
		break;
	}
	...
	}
	ret = 0;
	
	...
	return ret;
}

兜兜转转,最后又到了这里,是不是非常熟悉,这个词都说好多遍了,后面依然会说。首先,代码中会将binder_write_read从用户空间拷贝到内核空间之后。拷贝之后,读取出来的bwr.write_size和bwr.read_size都>0,因此先写后读。即,先执行binder_thread_write(),然后执行binder_thread_read()。


9.Binder驱动中binder_thread_write()的源码

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

	//读取binder_write_read.write_buffer中的内容。
	//每次读取32bit(即四个字节)
	while (ptr < end && thread->return_error == BR_OK) {
		// 从用户空间读取32bit到内核中,并赋值给cmd。
		if (get_user(cmd, (uint32_t __user *)ptr))
			return -EFAULT;
		ptr += sizeof(uint32_t);
		...
		switch (cmd) {
		...
			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;
			}
		...
		}
		//更新bwr.write_consumed的值
		*consumed = ptr - buffer;
	}
	return 0;
}		

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!