java 层binder 对象传递流程

1. 闲来无事又瞎折腾 binder 源码,以前 看binder理论 云里雾里的不知所云,于是就来折腾了,只为念头通透。

2.  从bindService 方法开始来了解 java binder 对象的传递过程.基于4.4源码:

ContextImpl.java
1.以此为入口 sd 是一个java binder。
ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(),
                service, service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, user.getIdentifier());


ActivityManagerProxy.java
2.

  public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType, IServiceConnection connection,
            int flags, int userId) throws RemoteException {
     ....
        data.writeStrongBinder(connection.asBinder()); //asBinder()返回 是本身
     ....
        return res;
    }
Parcel.java---》Android_os_Parcel.cpp

3.
   static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
{
    ...
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
   ...
} 

 Android_utils_Binder.cpp
4.为java Object 对象创建 c层的Binder 对象,神来之笔简化了应用层.

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;
    //Binder.java    
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        //这个对jbh 对象创建是在java Binder构造时调用init()创建的 
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetIntField(obj, gBinderOffsets.mObject);
        //这里获取到一个JavaBBinder 
        return jbh != NULL ? jbh->get(env, obj) : NULL;
    }
    //BinderProxy.java    
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        // mObject对象指向的 c层的一个BpBinder指针
        return (IBinder*)
            env->GetIntField(obj, gBinderProxyOffsets.mObject);
    }

    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}
Parcel.cpp
5.将Binder 写入 Parcel 缓冲区
    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();//不为空 返回JavaBBinder 对象
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
         ...
        } else {
               //执行这个
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = local->getWeakRefs();
            obj.cookie = local; //JavaBBinder对象
        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = NULL;
        obj.cookie = NULL;
    }
      //写入内存
    return finish_flatten_binder(binder, obj, out);
}

    2.1 代码不难,难点在于理解数据的存储结构.可以在service_manager.c,bctest.c 找到一些用于的信息,这些结构没有那么多业务数据易于理解

1.bctest.c
int svcmgr_publish(struct binder_state *bs, void *target, const char *name, void *ptr)
{
    unsigned status;
    unsigned iodata[512/4];
    struct binder_io msg, reply;
...
//格式化数据存储的格式
    bio_init(&msg, iodata, sizeof(iodata), 4);
 ...
//    
    bio_put_obj(&msg, ptr);

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
   ....

    return status;
}
2.bio_init
void bio_init(struct binder_io *bio, void *data,
              uint32_t maxdata, uint32_t maxoffs)
{
    uint32_t n = maxoffs * sizeof(uint32_t);// 4*4
    ....
    //数据是从偏移量16 开始的插入的 
    bio->data = bio->data0 = (char *) data + n;
   //指向数组首地址
    bio->offs = bio->offs0 = data;
    //还剩多少数据可以用,这里不像 Parcel.cpp 还能扩容而且还没有限制
    bio->data_avail = maxdata - n; //512-16
    bio->offs_avail = maxoffs; // 能放四个Binder 对象或者其他东西,不管你存什么当Binder 驱动返回这些数据时能用就行,当然你先于你的代码,乱写系统就不认识了
    bio->flags = 0;
}
binder.c
//存放Binder
3.调用bio_put_obj 方法插入类似binder对象的数据
void bio_put_obj(struct binder_io *bio, void *ptr)
{
    struct binder_object *obj;

    obj = bio_alloc_obj(bio);
  ....
    obj->pointer = ptr; //  指针想存啥都行
  ...
}
4.bio_alloc_obj 
static struct binder_object *bio_alloc_obj(struct binder_io *bio)
{
    struct binder_object *obj;

    obj = bio_alloc(bio, sizeof(*obj));
    
    if (obj && bio->offs_avail) {
        bio->offs_avail--;
// 前十六个字节用来表示这个,偏移量就是已存放数据的大小减去bio->data0(数组+4)
        *bio->offs++ = ((char*) obj) - ((char*) bio->data0);
        return obj;
    }

    bio->flags |= BIO_F_OVERFLOW;
    return 0;
}
static void *bio_alloc(struct binder_io *bio, uint32_t size)
{
    size = (size + 3) & (~3);  // 在Parcel.cpp write 方法开头时 也用这样的方法,因为前面16个字节用来表示其他东西了 (一个int 用四字节表示,四个int).
    if (size > bio->data_avail) {
        bio->flags |= BIO_F_OVERFLOW;
        return 0;
    } else {
        void *ptr = bio->data;
        bio->data += size;
        bio->data_avail -= size;
        return ptr;
    }
}

 

    2.2 内存数据

 

 

    2.3 向binder 驱动传递数据:

1.向binder 驱动写数据
    int binder_call(struct binder_state *bs,
                struct binder_io *msg, struct binder_io *reply,
                void *target, uint32_t code)
{
    int res;
    struct binder_write_read bwr; // binder 驱动第一次调用copy_from_user() bwr 数据
    struct {
        uint32_t cmd;
        struct binder_txn txn; //等于 binder_transaction_data, binder 驱动第二次调用copy_from_user() txn 数据
    } writebuf;
    unsigned readbuf[32];

    if (msg->flags & BIO_F_OVERFLOW) {
        fprintf(stderr,"binder: txn buffer overflow\n");
        goto fail;
    }

    writebuf.cmd = BC_TRANSACTION;
    writebuf.txn.target = target;
    writebuf.txn.code = code;
    writebuf.txn.flags = 0;
    writebuf.txn.data_size = msg->data - msg->data0;
    writebuf.txn.offs_size = ((char*) msg->offs) - ((char*) msg->offs0);
    writebuf.txn.data = msg->data0;  // binder 驱动第三次调用copy_from_user() 拷贝用户传递数据
    writebuf.txn.offs = msg->offs0;//binder 驱动第四次调用copy_from_user() 拷贝用户传递binder 数据

    bwr.write_size = sizeof(writebuf);
    bwr.write_consumed = 0;
    bwr.write_buffer = (unsigned) &writebuf;
    
    hexdump(msg->data0, msg->data - msg->data0);
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;
        //调用驱动
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

     ...
}

  为什么调用copy_from_user()一次不能把所有数据拷贝过来呢,原因它传递的是指针,拷贝过来的也是指针。msg->data0 和msg->offs0最好的证明,还有Parcel.cpp 普通数据和flat_binder_object 对象 都是是通过调用malloc()方法分配内存的,指针是不一样的,并不像上面一样他们是连续的在一个数组中。唯一我不懂的是,上面offs 指向的是数组首地址,调用copy_from_user()也拷贝不了对相应binder对象的数据,而 下面tr.data.ptr.offsets 指向的是存放着所有flat_binder_object对象内存首地址,完全能拷贝binder 对象数据。

3.当数据写完时,接着构造驱动数据: BpBinder.transact(...)-> IPCThreadState->transact()->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.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(size_t);// flat_binder_object 对象的个数
        tr.data.ptr.offsets = data.ipcObjects(); //存放flat_binder_object对象内存首地址 
    } 
      ....
    
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));
    
    return NO_ERROR;
}

4.调用 IPCThreadState->waitForResponse(...) 进入binder 内核代码(只分析java binder 对象传递流程 ):

       

binder.c
1.binder_transaction{
    ...
  //tr 数据结构看第三个代码段
    //ALIGN 等于 data_size+3 为啥加+3 看第二个代码段
  offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
    //data.ptr.buffer 指向存放着用户态的普通数据地址,拷贝到内核态
	if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
		...
	}
    //data.ptr.offsets 指向存放用户态的flat_binder_object地址
	if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
	...
	}
    //以上两个操作将用户态 数据拷贝到内核态
    
	off_end = (void *)offp + tr->offsets_size;
    // 遍历flat_binder_object 对象 
	for (; offp < off_end; offp++) {
		struct flat_binder_object *fp;
		if (*offp > t->buffer->data_size - sizeof(*fp) ||
		    t->buffer->data_size < sizeof(*fp) ||
		    !IS_ALIGNED(*offp, sizeof(void *))) {
			...
		}
		fp = (struct flat_binder_object *)(t->buffer->data + *offp);
		switch (fp->type) {
        //传递的是BINDER_TYPE_BINDER
		case BINDER_TYPE_BINDER:
		case BINDER_TYPE_WEAK_BINDER: {
			struct binder_ref *ref;
            //proc 调用者的进程 ,用户态fp->binder 弱指针 ,第一次进入 node 为null
			struct binder_node *node = binder_get_node(proc, fp->binder);
			if (node == NULL) {
                //为当前进程 java binder对象 在Binder 驱动内建立binder_node 节点
				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);
			}
			...
            // target_proc 为ActivityManagerService进程
            // 为这个进程建立一个binder_ref指向binder_node. 
			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;
            // 拿到这个进程指向binder_node 的handle
            //对于同一个进程handle 是唯一的,代码在binder_get_ref_for_node()可以得到结论.
			fp->handle = ref->desc;
			binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
				       &thread->todo);

			binder_debug(BINDER_DEBUG_TRANSACTION,
				     "        node %d u%p -> ref %d desc %d\n",
				     node->debug_id, node->ptr, ref->debug_id,
				     ref->desc);
		} break;
	

	...
		
	}
...
}

   5.binder 驱动处理完,唤醒对应的进程处理数据:

IPCThreadState.cpp
status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;
    
    switch (cmd) {
   ...
    case BR_TRANSACTION:
        {
        
            .....
            // 在binder 驱动 binder_thread_read()中会通过target_node 把cookie赋值给ptr
            //cookie是什么可以看看 第二个代码段 
            //这里 tr.target.ptr是ActivityManagerSerice的JavaBBinder
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);

            } 
            
       ....
    
    return result;
}
2.调用JavaBBinder
 virtual status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
    {
        JNIEnv* env = javavm_to_jnienv(mVM);

       ...
        //mObject 指向ActivityManagerService
        // 不知道调用哪个方法可以看看android_utils_Binder 的int_register_android_os_Binder方法   
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, (int32_t)&data, (int32_t)reply, flags);
        jthrowable excep = env->ExceptionOccurred();
      ...

    } 
3.执行  Binder.execTransact()-> ActivityManagerService->onTransact()->ActivityManager.onTransact

      public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
          ...

        case BIND_SERVICE_TRANSACTION: {
           data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
            IApplicationThread app = ApplicationThreadNative.asInterface(b);
            IBinder token = data.readStrongBinder();
            Intent service = Intent.CREATOR.createFromParcel(data);
            String resolvedType = data.readString();
            //怎么样写就怎么样读就对了 ,所以这里是读取ServiceConnection
            b = data.readStrongBinder();
            int fl = data.readInt();
            int userId = data.readInt();
            IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
            int res = bindService(app, token, service, resolvedType, conn, fl, userId);
            reply.writeNoException();
            reply.writeInt(res);
            return true;
        }
...
}
4. android_os_Parcel.cpp
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
{
    ...
     //为binder对象创建Java 对象
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    ...
   
}
5.Parcel.cpp
 status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);
    
    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = static_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            //从第四段驱动代码中BINDER_TYPE_BINDER转成BINDER_TYPE_HANDLE
            //所以执行者这一段
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}
6.ProcessState.cpp
 sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);
    //第一次没有插入一handle_entry
    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
     
        IBinder* b = e->binder; //第一次为空
        
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
           ...
            //创建一个BpBinder!!!
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        }
       ...
    }

    return result;
}
7. 为BpBiner对象创建一个BinderProxy java 对象
 jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;
    // 这个是BpBinder 对象这个方法默认返回false
    if (val->checkSubclass(&gBinderOffsets)) {
        // One of our own!
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }

    // For the rest of the function we will hold this lock, to serialize
    // looking/creation of Java proxies for native Binder proxies.
    AutoMutex _l(mProxyLock);

    //  第一次进入,所以object 为null;
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = jniGetReferent(env, object);
        if (res != NULL) {
            ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
            return res;
        }
        LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }
    // 创建一个BinderProxy 对象
    //不知道创建什么可以看下 int_register_android_os_BinderProxy()方法
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        
        env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
        val->incStrong((void*)javaObjectForIBinder);

        // The native object needs to hold a weak reference back to the
        // proxy, so we can retrieve the same proxy if it is still active.
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        // 添加弱引用,第二次进来就不为空了
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);
       ....
    }

    return object;
}

6.IServiceConnection.Stub.asInterface(b) 获取代理对象,代码懒得找,自己创建一个adil 文件

    

 // 随便创建一个adil 文件就行了 
 public static com.test.testbiner.IHellolInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
     //如果这里obj 是stub 对象, 那么就返回JavaBBinder对象
     // 什么情况下会返回JavaBBinder对象 ,是在获取handle 引用时,获取的进程跟binder 注册的进程是同一个 将会返回,可以编译一个adil运行下,也可以看看binder 驱动 在遍历flat_biner_object对象 类型为BINDER_TYPE_HANDLE 的代码
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.test.testbiner.IHellolInterface))) {
        return ((com.test.testbiner.IHellolInterface)iin);
      }
    // 例子执行的是这个
      return new com.test.testbiner.IHellolInterface.Stub.Proxy(obj);
    }

  画个图来说明数据的流向:

  

ps:有人说java service端也有BnBinder接口 .

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值