深入掌握Binder原理(下)(一)

·  阅读 616

前言

在前一篇文章《深入掌握Binder原理上》中,我们已经了解Binder驱动程序以及ServiceManager这两部分,在这篇文章中,会对Binder剩下两部分Client和Server进行讲解,这里建议没有阅读上一篇文章的先读完上一篇文章,然后再来看这一篇,只有这两篇文章连起来,才能对Binder的体系有一个完整和深入的了解。

Binder实现原理

为了能更具体的理解Binder中Client和Server这两个组成部分,这里我以我们最熟悉的一个场景:在应用进程中startActivity,这个场景来讲解Clinet端和Server端是如何使用Binder的。在这个场景中,应用进程是Client端,位于system_server进程的ActivityManagerService是Server端。通过理解应用进程是如何调用Binder,通知AMS启动一个Activity的,我们便能理解Android系统中所有Clinet和Server进行Binder通信的原理,因为其他的场景的Binder通信原理都是一样的。

Client

当我们在桌面点击应用icon启动应用或者手动调用startActivity函数启动一个Activity,实际都是通过Binder调用ActivityManangerService去启动指定的Activity,在AMS启动Activity的流程中,会检查该Activity所属的进程是否存在,如果不存在,就会通知Zygote去fork该Activity的进程,关于Activity更详细的启动流程可以看我的这篇文章《Activity启动详解》,在这里我们只需要了解所有通过Zygote fork成功的进程,都会执行onZygoteInit回调,所以我们的应用进程,在第一次被创建时,也会执行onZygoteInit回调,而onZygoteInit中,默认会打开Binder。

/frameworks/base/cmds/app_process/app_main.cpp

virtual void onZygoteInit() {
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool(); 
}
复制代码

在前面讲ServiceManager使用Binder主要有这几步流程,第一步调用open打开binder,第二步调用mmap映射内存,第三步是在Binder驱动中将ServiceManagerServer注册成BinderManager,第四步让ServiceManager进程陷入循环,并不断的调用ioctl监听缓存区是否有数据。

onZygoteInit函数中虽然只有两行代码,但是其实做了ServiceManager第一步,第二步和第四步的事情。这两行代码主要做的事情如下

  1. ProcessState::self()打开binder驱动,并进行内存的映射
  2. proc->startThreadPool()让binder线程无线的循环,并不断的通过ioctl往binder驱动读或者写数据。

打开Binder

ProcessState

我们先来看看ProcessState::self()函数是如何打开Binder驱动程序的,ProcessState对象相当于是一个进程操作Binder的工具类,并且它是一个全局的单例对象,通过self获取单例的实例。

/frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState("/dev/binder");
    return gProcess;
}
复制代码

ProcessState的构造函数实现如下

/frameworks/native/libs/binder/ProcessState.cpp

#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
        , mDriverFD(open_driver(driver))  //打开binder
        , mVMStart(MAP_FAILED)
        , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
        , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
        , mExecutingThreadsCount(0)
        , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
        , mStarvationStartTimeMs(0)
        , mManagesContexts(false)
        , mBinderContextCheckFunc(NULL)
        , mBinderContextUserData(NULL)
        , mThreadPoolStarted(false)
        , mThreadPoolSeq(1)
    {
        if (mDriverFD >= 0) {
            mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);//进行内核空间和用户空间的内存映射
            if (mVMStart == MAP_FAILED) {
                close(mDriverFD);
                mDriverFD = -1;
                mDriverName.clear();
            }
        }
    }

复制代码

ProcessState的构造函数中主要做了这两件事情

  1. 调用open_driver("/dev/binder")函数,打开位于内核空间binder驱动程序
  2. 调用mmap函数,将Binder驱动的内核空间内存映射到当前进程的用户空间来
open_driver

我们先看open_driver("/dev/binder")这个函数的实现

/frameworks/native/libs/binder/ProcessState.cpp

static int open_driver(const char *driver)
{
    //打开binder驱动程序
    int fd = open(driver, O_RDWR | O_CLOEXEC);
    if (fd >= 0) {
        int vers = 0;
        //获取当前binder版本
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        if (result == -1) {
            close(fd);
            fd = -1;
        }
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
            close(fd);
            fd = -1;
        }
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        //设置binder最大线程数
        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;
}
复制代码

open_driver函数主要做了这三件事情

  1. 调用I/O函数open打开驱动,open函数会经过系统调用,最终执行binder驱动程序中的open_binder函数
  2. 调用I/O函数ioctl获取BINDER_VERSION,ioctl函数经过系统调用最终会执行binder驱动程序中的binder_ioctl函数
  3. 调用I/O函数ioctl设置当前进程最大的Binder线程数量,这里设置的线程数是15个

前一篇文章我们已经知道了系统调用的流程,以及binder驱动中open_binder函数实现,这里就不再讲了,并且还知道了binder_ioctl响应BINDER_SET_CONTEXT_MGR和BINDER_WRITE_READ命令的流程,在这里,我主要补充binder_ioctl函数是如何响应剩下的两个命令BINDER_VERSION和BINDER_SET_MAX_THREADS的。

响应BINDER_VERSION指令

/drivers/staging/android/binder.c

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;

	……

	switch (cmd) {
	case BINDER_WRITE_READ:
		……
		break;
	case BINDER_SET_MAX_THREADS:
        //将最大线程数从用户空间拷贝到内核空间,并赋值给binder_proc结构体中的max_threads变量
		if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
			ret = -EINVAL;
			goto err;
		}
		break;
	case BINDER_SET_CONTEXT_MGR:
		……
		break;
	case BINDER_THREAD_EXIT:
		……
		break;
	case BINDER_VERSION: {
		struct binder_version __user *ver = ubuf;
		if (size != sizeof(struct binder_version)) {
			ret = -EINVAL;
			goto err;
		}
        //将Binder驱动程序版本信息会写到用户空间
		if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
			     &ver->protocol_version)) {
			ret = -EINVAL;
			goto err;
		}
		break;
	}
	default:
		ret = -EINVAL;
		goto err;
	}
	ret = 0;
err:
	……
	return ret;
}
复制代码

在binder驱动程序的BINDER_VERSION响应逻辑中,会直接调用put_user函数将当前版本信息写入到用户空间地址**&vers**中,put_user函数是Linux内核函数,功能和copy_to_user类似,都是将数据从内核空间拷贝到用户空间,但是put_user函数只能拷贝一些简单的变量类似,复杂的数据结构和数据的拷贝,还是要copy_to_user来进行。

响应BINDER_SET_MAX_THREADS指令

在binder驱动程序的BINDER_SET_MAX_THREADS响应逻辑中,会调用copy_from_user函数,将线程数量拷贝到内核空间并赋值给proc->max_threads。

mmap

ProcessState构造函数执行open_driver函数打开binder驱动并且设置了binder线程数,便会执行mmap进行内存的映射,mmap的原理以及Binder驱动程序中binder_mmap的实现,在前一篇文章都详细讲了,这里也不重复讲了,需要注意的是,这儿映射的内存大小为BINDER_VM_SIZE,也就是1M-8kb的大小,而前面讲到的ServiceManager映射的内存是128kb。

陷入循环

ProcessState的构造函数中调用open_driver打开了binder驱动,以及调用了mmap进行内存映射后,就会执行proc->startThreadPool()让binder线程陷入无限循环,看一下它是怎么实现的。

/frameworks/native/libs/binder/ProcessState.cpp

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}
复制代码

startThreadPool函数实际是启动了一个PoolThread线程,该线程是ProcessState的内部类,然后执行该线程的run方法。

/frameworks/native/libs/binder/ProcessState.cpp

class PoolThread : public Thread
{
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }
    
protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }
    
    const bool mIsMain;
};
复制代码

IPCThreadState

PoolThread线程启动时会执行threadLoop函数中的IPCThreadState::self()->joinThreadPool(mIsMain)函数。Binder通信是基于多线程模型的,一个Binder线程就对应了一个IPCThreadState,它是进程中真正调用Binder驱动读写数据的对象,并且IPCThreadState是基于线程的单例模式,通过ThreadLocal,也就是本地线程存储机制,确保每个线程都只有唯一的一个IPCThreadState,我们看一下IPCThreadState::self()里的逻辑。

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

IPCThreadState* IPCThreadState::self()
{   
    //首次进来gHaveTLS的值为false
    if (gHaveTLS) {
restart:
        const pthread_key_t k = gTLS;
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;
        return new IPCThreadState;
    }
    if (!gHaveTLS) {
        //创建线程私有数据
        int key_create_value = pthread_key_create(&gTLS, threadDestructor);       
        gHaveTLS = true;
    }
    goto restart;
}
复制代码

接着看看IPCThreadState的构造函数

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

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
    pthread_setspecific(gTLS, this);
    clearCaller();
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}
复制代码

IPCThreadState构造函数初始化了mInmOut两个buffer,mIn用来存放其他进程写过来的数据,mOut用来存放需要传递给其他进程的数据。

joinThreadPool

了解了IPCThreadState,我们再看看它的joinThreadPool函数实现。

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

void IPCThreadState::joinThreadPool(bool isMain)
{
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

    status_t result;
    do {
        // now get the next command to be processed, waiting if necessary
        result = getAndExecuteCommand();

        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            abort();
        }

        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}
复制代码

joinThreadPool中通过do while不断的循环,并不断调用getAndExecuteCommand函数来进行数据的读写。

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

status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;

    //往Binder驱动读写数据
    result = talkWithDriver();
    if (result >= NO_ERROR) {
        size_t IN = mIn.dataAvail();
        if (IN < sizeof(int32_t)) return result;
        //有其他进程传递数据过来
        cmd = mIn.readInt32();
        pthread_mutex_lock(&mProcess->mThreadCountLock);
        mProcess->mExecutingThreadsCount++;
        if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
                mProcess->mStarvationStartTimeMs == 0) {
            mProcess->mStarvationStartTimeMs = uptimeMillis();
        }
        pthread_mutex_unlock(&mProcess->mThreadCountLock);

        //处理其他进程写入的数据
        result = executeCommand(cmd);

        pthread_mutex_lock(&mProcess->mThreadCountLock);
        mProcess->mExecutingThreadsCount--;
        if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
                mProcess->mStarvationStartTimeMs != 0) {
            int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
            if (starvationTimeMs > 100) {
                ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
                      mProcess->mMaxThreads, starvationTimeMs);
            }
            mProcess->mStarvationStartTimeMs = 0;
        }
        pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
        pthread_mutex_unlock(&mProcess->mThreadCountLock);
    }

    return result;
}
复制代码

getAndExecuteCommand函数中的关键流程是talkWithDriver函数,这个函数封装了ioctl函数直接会直接操作binder驱动程序,经过talkWithDriver调用后,会检查mIn缓冲区中是否有数据,如果有数据,就表示有其他进程写入了数据进来,则调用executeCommand处理数据。

我们先看看talkWithDriver函数。

talkWithDriver

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

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {
        return -EBADF;
    }

    binder_write_read bwr;


    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();

    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 {
        //往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;
}
复制代码

talkWithDriver函数中会调用ioctl函数,将binder_write_read结构体传给binder驱动,binder_write_read包含了一个write_buffer和一个read_buffer,write_buffer存放了要写入到其他进程的数据,read_buffer用来接收其他进程返回来的数据。binder驱动程序中会在binder_ioctl函数中响应BINDER_WRITE_READ命令。在上一篇文章中也讲到了ServerMananger陷入无限循环后,也是通过调用ioctl函数来不断的往binder驱动读写数据,并且也讲了Binder驱动是如何响应ServerMananger的ioctl函数中的BINDER_WRITE_READ命令的,这里就不再讲了,和ServerMananger是一样的,唯一的区别是这里是通过IPCThreadState对象封装调用的。

消息发送

经历了前面的步骤后,就能使用Binder进行消息的发送了,接下来开始讲解用户进程和AMS所在system_server进程进行Binder通信的全流程。这里先简单了解一下当我们调用startActivity启动一个activity时所经历的流程。

通知AMS启动Activity启动

startActivity函数最终都会调用startActivityForResult函数,看一下他的实现。

/frameworks/base/core/java/android/app/Activity.java

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
                                   @Nullable Bundle options) {
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
        //启动activity
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
            this, mMainThread.getApplicationThread(), mToken, this,
            intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
    } else {
       ……
    }
}

复制代码

startActivityForResult函数中实际是调用了Instrumentation对象的execStartActivity方法。

/frameworks/base/core/java/android/app/Instrumentation.java

public ActivityResult execStartActivity(
    Context who, IBinder contextThread, IBinder token, Activity target,
    Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != null ? target.onProvideReferrer() : null;
    if (referrer != null) {
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    ……
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                           intent.resolveTypeIfNeeded(who.getContentResolver()),
                           token, target != null ? target.mEmbeddedID : null,
                           requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}
复制代码

execStartActivity函数关键的代码就是ActivityManager.getService() .startActivity,通过这一行代码,就能调用AMS启动activity,这一行代码由三部分组成。

  1. 获取ServiceManager的Binder地址,并根据获取到的Binder地址创建ServiceManager在应用进程的Proxy
  2. 获取ActivityManagerService的Binder地址,更根据AMS的Binder地址创建AMS在应用进程的Proxy
  3. 通知ActivityManagerService启动activity。

Proxy是Server在Clinet端的代理,里面实际是持有了Server端的Binder地址,Clinet可以直接通过调用Proxy对象中某个业务函数的方式,如startActivity函数来直接Server通信,而不用自己去进行Binder通信要求的数据格式创建,协议封装,数据的处理等繁琐操作。如果我们不使用Android提供的Proxy,就要自己约定Server端和Clinet端的数据协议,格式,命令协议等等,这样就让Binder的使用变得繁琐和复杂。Proxy文件一般也是编译时自动生成的,当我们在AIDL文件约定好Server和Clinet的业务调用函数时,编译时会根据AIDL文件自动生成供Client端使用的Proxy。

下面来详细看一下这三步的具体实现。

获取ServcieManager

先看看ActivityManager.getService()的实现

/frameworks/base/core/java/android/app/ActivityManager.java


public static final String ACTIVITY_SERVICE = "activity";

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
    @Override
        protected IActivityManager create() {
        //获取ActivityManagerService的binder地址
        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
        //转成AMS的Proxy
        final IActivityManager am = IActivityManager.Stub.asInterface(b);
        return am;
    }
};
复制代码

可以看到,ActivityManager.getService()函数里面做了这两件事情

  1. 调用ServiceManager.getService(Context.ACTIVITY_SERVICE)获取AMS的Binder地址
  2. 调用IActivityManager.Stub.asInterface(b)根据AMS的binder地址,创建AMS在用户进程的Proxy。

接着来看**ServiceManager.getService(Context.ACTIVITY_SERVICE)**的流程。

/frameworks/base/core/java/android/os/ServiceManager.java

public static IBinder getService(String name) {
    try {
        //检查缓存是否有AMS的Binder地址
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            //通过ServiceManager获取AMS的binder地址
            return Binder.allowBlocking(getIServiceManager().getService(name));
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

private static IServiceManager getIServiceManager() {
    if (sServiceManager != null) {
        return sServiceManager;
    }

    // 获取ServiceMananger,并转换成proxy
    sServiceManager = ServiceManagerNative
        .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
    return sServiceManager;
}
复制代码

ServiceManager.getService()函数中做了这几件事情

  1. 判断sCache缓存中是否由AMS的binder地址
  2. 如果没有,则调用BinderInternal.getContextObject()函数获取ServiceManager的Binder地址
  3. 根据获取到的ServiceManager的binder地址,创建ServiceManager在用户进程的Proxy代理
  4. 创建了ServiceManager的Proxy代理后,通过该代理获取ActivityManagerService的Binder地址

先看BinderInternal.getContextObject()函数的实现,他是一个native函数,并且他在native中的实现函数位于之前提到过的ProcessState对象里面。

/frameworks/native/libs/binder/ProcessState.cpp

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                Parcel data;
                //往ServerMananger发送PING_TRANSACTION命令
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
			//以0为地址,创建BpBinder
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {         
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}
复制代码

getContextObject主要做了这两件事

  1. 调用IPCThreadState的transact函数往ServerMananger发送PING_TRANSACTION协议,用于校验Binder驱动程序和ServiceMannager是否正常
  2. 以0为Binder地址,也就是ServerManager在Binder驱动程序中的地址,构建BpBinder
IPCThreadState发送PING_TRANSACTION命令

先看看第一件事,调用IPCThreadState的transact函数往Binder驱动程序发送消息。在前面已经讲过了IPCThreadState这个对象,我们知道,不管是ServiceMannager往Binder驱动收发消息,或者是其他任何进程往Binder驱动收发消息,都必须通过通过ioctl函数进行系统调用,所以IPCThreadState实际也只是对ioctl操作的封装,并且采用基于线程的单例模式,下面看一下IPCThreadState发送消息具体实现。

transact

IPCThreadState是通过transact函数进行数据的发送的,我们看一下这个函数的实现。

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

status_t IPCThreadState::trantrasact(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 (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;
}
复制代码

trantrasact函数中做了两件事情:

  1. 调用writeTransactionData构建要传输的数据
  2. 调用waitForResponse发送数据
writeTransactionData

先看第一件事情,writeTransactionData构建传输的数据。

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

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; 
    //设置target的handle地址,此时这个handle为0,表示ServiceMananger
    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) {
        //将要传输的数据封装到binder_transaction_data数据结构中
        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) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }

    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}
复制代码

数据构建的流程如下:

  1. 将需要传输的数据及其目标进程target的信息,如binder地址等,封装到binder_transaction_data结构体中
  2. 将封装后的binder_transaction_data放在mOut缓冲区中,并设置协议码为BC_TRANSACTION。在前面我们已经知道了很多协议,如PING_TRANSACTION等,这些都是Server的业务协议,BC_TRANSACTION属于Binder驱动的协议。Binder协议的封装和网络传输很像,网络传输数据时,要从上到下封装HTTP协议,TCP协议,IP协议等。而binder通信也会封装具体的业务协议,如PING_TRANSACTION,然后再封装Binder驱动协议,如BC_TRANSACTION。

构建好数据后,我们接着来看waitForResponse是如何发送数据的。

waitForResponse

transact函数中会根据flags&TF_ONE_WAY == 0 来决定这次Binder通信是否需要返回数据,如果需要的话就会阻塞等待Binder驱动的返回数据。TF_ONE_WAY 的值为1,前面trantrasact的flag入参是0,所以这一次的通信是非ONE_WAY模式,这种模式下会阻塞等待,此时会调用waitForResponse(&fakeReply)函数,它的实现如下。

/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;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;

        cmd = (uint32_t)mIn.readInt32();
		//处理返回数据
        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;

        case BR_DEAD_REPLY:
            err = DEAD_OBJECT;
            goto finish;

        case BR_FAILED_REPLY:
            err = FAILED_TRANSACTION;
            goto finish;

        case BR_ACQUIRE_RESULT:
            {
                ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
                const int32_t result = mIn.readInt32();
                if (!acquireResult) continue;
                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
            }
            goto finish;

        case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                if (err != NO_ERROR) goto finish;

                if (reply) {
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t),
                            freeBuffer, this);
                    } else {
                        err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
                        freeBuffer(NULL,
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t), this);
                    }
                } else {
                    freeBuffer(NULL,
                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                        tr.data_size,
                        reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                        tr.offsets_size/sizeof(binder_size_t), this);
                    continue;
                }
            }
            goto finish;

        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }

    return err;
}
复制代码

可以看到waitForResponse通过while(1)来进行阻塞,里面主要做了这几件事情

  1. 调用talkWithDriver往Binder驱动收发数据
  2. 根据Binder驱动的返回协议,处理Binder驱动返回的数据
talkWithDriver

先看talkWithDriver,这个函数在前面也提到过了,他的本质其实也是封装了ioctl函数往Binder驱动收发送数据。

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

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {
        return -EBADF;
    }

    binder_write_read bwr;


    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();

    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 {
        //往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;
}
复制代码

talkWithDriver将mIn和mOut这两个缓冲区封装到binder_write_read结构体的read_buffer和write_buffer中,通过ioctl函数将binder_write_read这个结构体传递给Binder驱动程序,这样Binder驱动就可以通过读取write_buffer来获取要传递的数据,并将Server返回数据写入到read_buffer中。

上一篇文章已经讲过了Binder驱动是如何响应ServiceMananger调用ioctl函数中封装的BINDER_WRITE_READ协议的,这里我们再把Binder驱动响应BINDER_WRITE_READ的流程过一遍。

Binder驱动响应请求数据

接着看Binder驱动程序在binder_ioctl函数中处理BINDER_WRITE_READ协议的逻辑。

/drivers/staging/android/binder.c

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;

	
	ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
	if (ret)
		goto err_unlocked;

	binder_lock(__func__);
    //创建或获取binder_thread
	thread = binder_get_thread(proc);
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {
	case BINDER_WRITE_READ:
        //读写逻辑处理
		ret = binder_ioctl_write_read(filp, cmd, arg, thread);
		if (ret)
			goto err;
		break;
	case BINDER_SET_MAX_THREADS:
		……
		break;
	case BINDER_SET_CONTEXT_MGR:
		……
		break;
	case BINDER_THREAD_EXIT:
		……
	case BINDER_VERSION: {
		……
		break;
	}
	default:
		ret = -EINVAL;
		goto err;
	}
	ret = 0;
    ……
	return ret;
}
复制代码

可以看到响应BINDER_WRITE_READ的逻辑代码中调用了binder_ioctl_write_read函数,下面看一下他的实现。

binder_ioctl_write_read

/drivers/staging/android/binder.c

tatic int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread)
{
	int ret = 0;
    //获取当前进程的binder_proc结构体
	struct binder_proc *proc = filp->private_data;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;
	struct binder_write_read bwr;

	if (size != sizeof(struct binder_write_read)) {
		ret = -EINVAL;
		goto out;
	}
	if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
		ret = -EFAULT;
		goto out;
	}

    
	if (bwr.write_size > 0) {
        //处理write_buffer,也就是需要传递给其他进程的数据
		ret = binder_thread_write(proc, thread,
					  bwr.write_buffer,
					  bwr.write_size,
					  &bwr.write_consumed);
		trace_binder_write_done(ret);
		if (ret < 0) {
			bwr.read_consumed = 0;
			if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
				ret = -EFAULT;
			goto out;
		}
	}
	if (bwr.read_size > 0) {
        //处理read_buffer,也就是其他进程传递过来的数据
		ret = binder_thread_read(proc, thread, bwr.read_buffer,
					 bwr.read_size,
					 &bwr.read_consumed,
					 filp->f_flags & O_NONBLOCK);
		trace_binder_read_done(ret);
		if (!list_empty(&proc->todo))
			wake_up_interruptible(&proc->wait);
		if (ret < 0) {
			if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
				ret = -EFAULT;
			goto out;
		}
	}

	if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
		ret = -EFAULT;
		goto out;
	}
out:
	return ret;
}
复制代码

binder_ioctl_write_read会判断bwr里面的write_size和read_size来决定是否要写数据或者读数据,在讲ServiceMananger时,我讲解了ServerMananger处理read_buffer的流程,这里我们看一下write_buffer的处理流程,处理流程在binder_thread_write函数中实现。

binder_thread_write

binder_thread_write主要是对BC_开头的协议的处理,这个协议是通过writeTransactionData构建传输的数据时封装的,在前面提到过,此时的协议是BC_TRANSACTION,表示Clinet向Server发送数据,我们看一下函数里是如何处理的。

/drivers/staging/android/binder.c

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;

	while (ptr < end && thread->return_error == BR_OK) {
		if (get_user(cmd, (uint32_t __user *)ptr))
			return -EFAULT;
		ptr += sizeof(uint32_t);
		trace_binder_command(cmd);
		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 BC_INCREFS:
		case BC_ACQUIRE:
		case BC_RELEASE:
		case BC_DECREFS: ……
		case BC_INCREFS_DONE:
		case BC_ACQUIRE_DONE: ……
		case BC_ATTEMPT_ACQUIRE:……
		case BC_ACQUIRE_RESULT:……
		case BC_FREE_BUFFER: ……
		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;
		}

		case BC_REGISTER_LOOPER:……
		case BC_ENTER_LOOPER:……
		case BC_EXIT_LOOPER:……
		case BC_REQUEST_DEATH_NOTIFICATION:
		case BC_CLEAR_DEATH_NOTIFICATION: ……
		case BC_DEAD_BINDER_DONE: ……
		default:return -EINVAL;
		}
		*consumed = ptr - buffer;
	}
	return 0;
}
复制代码

BC_TRANSACTION的响应逻辑做了两件事

  1. 调用copy_from_user将buffer中的数据从用户空间拷贝到Binder驱动程序的内核空间中
  2. 调用binder_transaction处理数据
binder_transaction

我们看一下binder_transaction函数是如何处理buffer的。

/drivers/staging/android/binder.c

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply)
{
	struct binder_transaction *t;
	struct binder_work *tcomplete;
	binder_size_t *offp, *off_end;
	binder_size_t off_min;
	struct binder_proc *target_proc;  //目标binder_proc结构体
	struct binder_thread *target_thread = NULL;  //目标线程
	struct binder_node *target_node = NULL;  //目标binder节点
	struct list_head *target_list;//目标TODO队列
	wait_queue_head_t *target_wait; //目标等待队列
	struct binder_transaction *in_reply_to = NULL;
	struct binder_transaction_log_entry *e;
	uint32_t return_error;


	if (reply) {
		……
	} else {       
		if (tr->target.handle) {
			struct binder_ref *ref;
            //如果target的binder地址不为0,则在binder_proc结构体的refs_by_desc中查找binder
			ref = binder_get_ref(proc, tr->target.handle);
			if (ref == NULL) {
				……
				goto err_invalid_target_handle;
			}
			target_node = ref->node;
		} else {
            //如果target为0,说明目标binder为server_mamanger,直接取全局变量binder_context_mgr_node
			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;
        //获取目标binder的binder_proc结构体
		target_proc = target_node->proc;
		……
	}
	if (target_thread) {
		e->to_thread = target_thread->pid;
		target_list = &target_thread->todo;
		target_wait = &target_thread->wait;
	} else {
        //首次执行target_thread为空,所以会走到这儿
		target_list = &target_proc->todo;
		target_wait = &target_proc->wait;
	}
	e->to_proc = target_proc->pid;

	//创建binder_transaction节点
	t = kzalloc(sizeof(*t), GFP_KERNEL);
	

    //创建一个binder_work节点
	tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
	if (tcomplete == NULL) {
		return_error = BR_FAILED_REPLY;
		goto err_alloc_tcomplete_failed;
	}
	binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);

	t->debug_id = ++binder_last_id;
	e->debug_id = t->debug_id;

    //非oneway的通信方式,把当前thread保存到transaction的from字段
	if (!reply && !(tr->flags & TF_ONE_WAY))
		t->from = thread;
	else
		t->from = NULL;
	t->sender_euid = task_euid(proc->tsk);
	t->to_proc = target_proc;
	t->to_thread = target_thread;
	t->code = tr->code;
	t->flags = tr->flags;
	t->priority = task_nice(current);


    //给目标进程的buffer分配内存空间
	t->buffer = binder_alloc_buf(target_proc, tr->data_size,
		tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
	if (t->buffer == NULL) {
		return_error = BR_FAILED_REPLY;
		goto err_binder_alloc_buf_failed;
	}
	t->buffer->allow_user_free = 0;
	t->buffer->debug_id = t->debug_id;
	t->buffer->transaction = t;
	t->buffer->target_node = target_node;
	trace_binder_transaction_alloc_buf(t->buffer);
	

	offp = (binder_size_t *)(t->buffer->data +
				 ALIGN(tr->data_size, sizeof(void *)));

    //将数据拷贝到目标进程的Buffer中
	if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
			   tr->data.ptr.buffer, tr->data_size)) {
				proc->pid, thread->pid);
		return_error = BR_FAILED_REPLY;
		goto err_copy_data_failed;
	}
	if (copy_from_user(offp, (const void __user *)(uintptr_t)
			   tr->data.ptr.offsets, tr->offsets_size)) {
		return_error = BR_FAILED_REPLY;
		goto err_copy_data_failed;
	}

	off_end = (void *)offp + tr->offsets_size;
	off_min = 0;
	for (; offp < off_end; offp++) {
		struct flat_binder_object *fp;

		fp = (struct flat_binder_object *)(t->buffer->data + *offp);
		off_min = *offp + sizeof(struct flat_binder_object);
		switch (fp->type) {
		case BINDER_TYPE_BINDER:
		case BINDER_TYPE_WEAK_BINDER: {
			struct binder_ref *ref;
            //获取目标进程的binder_node
			struct binder_node *node = binder_get_node(proc, fp->binder);

            //如果目标进程的binder_node不存在,则为目标进程新建binder_node,并插入到当前进程的binder_proc结构提的rb_node中
			if (node == NULL) {
				node = binder_new_node(proc, fp->binder, fp->cookie);
				if (node == NULL) {
					return_error = BR_FAILED_REPLY;
					goto err_binder_new_node_failed;
				}
				node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
				node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
			}
			……
            //根据binder_node查找binder_ref,如果查不到就新建,并插入到进程的binder_ref红黑树中
			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;
			}
			……
		} break;
		case BINDER_TYPE_HANDLE:
		case BINDER_TYPE_WEAK_HANDLE: {
            //获取目标进程的binder_ref
			struct binder_ref *ref = binder_get_ref(proc, fp->handle);

			if (ref == NULL) {
				……
				goto err_binder_get_ref_failed;
			}
			……
			if (ref->node->proc == target_proc) {
				if (fp->type == BINDER_TYPE_HANDLE)
					fp->type = BINDER_TYPE_BINDER;
				else
					fp->type = BINDER_TYPE_WEAK_BINDER;
				fp->binder = ref->node->ptr;
				fp->cookie = ref->node->cookie;
				binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
				trace_binder_transaction_ref_to_node(t, ref);
				binder_debug(BINDER_DEBUG_TRANSACTION,
					     "        ref %d desc %d -> node %d u%016llx\n",
					     ref->debug_id, ref->desc, ref->node->debug_id,
					     (u64)ref->node->ptr);
			} else {
				struct binder_ref *new_ref;

				new_ref = binder_get_ref_for_node(target_proc, ref->node);
				if (new_ref == NULL) {
					return_error = BR_FAILED_REPLY;
					goto err_binder_get_ref_for_node_failed;
				}
				fp->handle = new_ref->desc;
				binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
				trace_binder_transaction_ref_to_ref(t, ref,
								    new_ref);
			}
		} break;

		case BINDER_TYPE_FD:……

		default:……
		}
	}
	if (reply) {
		BUG_ON(t->buffer->async_transaction != 0);
		binder_pop_transaction(target_thread, in_reply_to);
	} else if (!(t->flags & TF_ONE_WAY)) {
		BUG_ON(t->buffer->async_transaction != 0);
		t->need_reply = 1;
		t->from_parent = thread->transaction_stack;
		thread->transaction_stack = t;
	} else {
		BUG_ON(target_node == NULL);
		BUG_ON(t->buffer->async_transaction != 1);
		if (target_node->has_async_transaction) {
			target_list = &target_node->async_todo;
			target_wait = NULL;
		} else
			target_node->has_async_transaction = 1;
	}
	t->work.type = BINDER_WORK_TRANSACTION;
    //将binder_work 插入到目标队列
	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);
	return;
}
复制代码

binder_transaction函数非常的长,下面来介绍一下函数中主要做的事情

  1. 根据target.handle,寻找目标进程的binder_proc,如果handle为0,就会直接取全局变量binder_context_mgr_node,binder_context_mgr_node在上一篇讲过ServiceMananger注册为bindermananger时,驱动就会为ServerMananger专门创建一个全局的binder_node,也就是这个binder_context_mgr_node。这里需要注意,如果target.handle不为0就会去当前进程的binder_proc结构体中寻找目标binder,这里可能有人会有疑问,binder_proc中目标的target是怎么创建的呢?其实当Client通过getService向ServiceManager请求该Service服务的时候,ServiceManager会在注册的Service列表中查找该服务,如果找到就将该服务返回给Client,在这个过程中,ServiceManager会在Client进程的binder_ref引用中插入Server的binder节点,所以Client第二次就能根据handle地址在binder_proc的binder引用中找到目标binder。
  2. 给目标进程的binder_proc结构体中的buffer分配内存,在上一篇我们已经知道binder_proc中的buffer是专门用来缓存数据的。
  3. 将当前进程的binder插入到目标进程的binder_proc的红黑树引用中去,在这里我们知道不管是Clinet进程,还是Server进程的binder_proc中的binder引用,都不是自己主动插入的,都是Binder驱动程序中插入的。
  4. 创建binder_transaction节点,并将其插入目标进程的todo列表
  5. 尝试唤醒目标进程

之前讲过ServiceManager会不断的通过ioctl函数读取是否有其他进程传输数据过来,binder驱动经过binder_transaction的流程,将用户进程的数据写入到了目标进程,也就是ServiceManager的buffer中,ServiceManager调用ioctl函数,发现有数据写入,就会开始处理数据,我们接着来看ServerManager是如何响应PING_TRANSACTION的。

ServiceManager响应PING_TRANSACTION消息

ServiceManager会在binder_loop函数中,不断的读写数据,并解析处理数据。

/frameworks/native/cmds/servicemanager/binder.c

void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(uint32_t));

    //进入for循环
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

        //读写取数据
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }

        //解析数据
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}
复制代码

接着看一下解析函数**binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func)**的实现

/frameworks/native/cmds/servicemanager/service_manager.c

int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;

    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        switch(cmd) {
        case BR_NOOP:
            break;
        case BR_TRANSACTION_COMPLETE:
            break;
        case BR_INCREFS:
        case BR_ACQUIRE:
        case BR_RELEASE:
        case BR_DECREFS:
            ptr += sizeof(struct binder_ptr_cookie);
            break;
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                return -1;
            }
            binder_dump_txn(txn);
            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);
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
            }
            ptr += sizeof(*txn);
            break;
        }
        case BR_REPLY:……
        case BR_DEAD_BINDER:……
        case BR_FAILED_REPLY:
            r = -1;
            break;
        case BR_DEAD_REPLY:
            r = -1;
            break;
        default:
            return -1;
        }
    }

    return r;
}
复制代码

在上一篇也讲到,Binder驱动在执行binder_thread_read函数读取传输数据时,会根据数据写入响应的响应码,最常见的进程间通信的响应码就是BR_TRANSACTION,表示有数据写入,ServiceMananger处理BR_TRANSACTION时,会将数据binder_transaction_data直接交给func这个入参函数处理,func入参函数的实现如下。

/frameworks/native/cmds/servicemanager/service_manager.c

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;


    if (txn->target.ptr != BINDER_SERVICE_MANAGER)
        return -1;

    //返回0
    if (txn->code == PING_TRANSACTION)
        return 0;

   ……

    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        bio_put_ref(reply, handle);
        return 0;

    case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        if (do_add_service(bs, s, len, handle, txn->sender_euid,
            allow_isolated, txn->sender_pid))
            return -1;
        break;

    case SVC_MGR_LIST_SERVICES: {
        uint32_t n = bio_get_uint32(msg);

        if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
            ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
                    txn->sender_euid);
            return -1;
        }
        si = svclist;
        while ((n-- > 0) && si)
            si = si->next;
        if (si) {
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
    default:
        ALOGE("unknown code %d\n", txn->code);
        return -1;
    }

    bio_put_uint32(reply, 0);
    return 0;
}
复制代码

可以看到当业务协议是PING_TRANSACTION时,会直接返回0。svcmgr_handler处理的响应逻辑主要还有SVC_MGR_GET_SERVICE,SVC_MGR_CHECK_SERVICE,SVC_MGR_ADD_SERVICE,SVC_MGR_LIST_SERVICES。里面最常用的就是SVC_MGR_ADD_SERVICE,也就是当Server端调用ServiceMananger的addService方法时使用的协议,后面会再详细讲这个协议。

ServiceManager会将0通过ioctl写入binder驱动中,返回给我们的用户进程。到这里,整个PING_TRANSACTION的流程就结束。PING_TRANSACTION的校验完成后,就会以0创建BpBinder,并且返回给Java层,而java层就会拿着这个BPBinder,创建Java层的Proxy。

由于字数限制,这篇文章拆成了两篇,我们接着往下看深入掌握Binder原理(下)(二),或者这里阅读完整的篇章深入掌握Binder原理(下)

分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改