【Android】Binder传送文件描述符分析

在进行dumpsys调用的时候,dump方法的第一个参数是文件描述符

BinderProxy.java

    publicvoid dump(FileDescriptor fd, String[] args) 


通过传送文件描述符来让服务端向给定的文件写数据,

等等,仔细想想,好像有什么不对

是啊,每个进程中的文件描述符是独立无关的,你把C进程中的文件描述符传给S进程,这不是刻舟求剑么?


但是,Android的binder看上去就是传送了文件描述符,这里面暗藏了什么玄机呢?


我们在读写文件描述符的地方加上log

frameworks/native/libs/binder/Parcel.cpp

status_t Parcel::writeDupFileDescriptor(int fd)
{
    int dupFd = dup(fd);
    if (dupFd < 0) {
        return -errno;
    }
//在这里添加log,查看fd的值
ALOGE("writeDupFileDescriptor: fd = %d, dupfd =  %d\n", fd, dupFd);
    status_t err = writeFileDescriptor(dupFd, true /*takeOwnership*/);
    if (err) {
        close(dupFd);
    }
    return err;
}

frameworks/base/core/jni/android_os_Parcel.cpp


static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        int fd = parcel->readFileDescriptor();
ALOGD("00 ========== android_os_Parcel_readFileDescriptor, fd=%d", fd);
        if (fd < 0) return NULL;
        fd = dup(fd);
ALOGD("========== android_os_Parcel_readFileDescriptor, fd=%d", fd);
        if (fd < 0) return NULL;
        return jniCreateFileDescriptor(env, fd);
    }
    return NULL;
}

进行一次dump调用,查看log

我们会发现,写入的fd和服务端读出的fd不一样,但是服务端却正确的完成了数据的输出,为什么呢?


肯定有地方进行了处理。

通过查看,我们发现,原来是在数据传输的过程中被做了手脚,binder驱动在传送数据的时候,在服务端上创建了一个新的fd,并且把这个fd和客户端fd所对应的文件进行了关联。


处理流程

 

BinderProxy.java

    public void dump(FileDescriptor fd,String[] args) throws RemoteException {

        Parcel data = Parcel.obtain();

        Parcel reply = Parcel.obtain();

        data.writeFileDescriptor(fd);

        data.writeStringArray(args);

        try {

            transact(DUMP_TRANSACTION, data,reply, 0);

            reply.readException();

        } finally {

            data.recycle();

            reply.recycle();

        }

    }

调用到

Parcel.java

    public final void writeFileDescriptor(FileDescriptor val) {

        updateNativeSize(nativeWriteFileDescriptor(mNativePtr,val));

    }

 

frameworks/base/core/jni/android_util_Binder.cpp

staticjboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,

        jint code, jobject dataObj, jobjectreplyObj, jint flags) // throws RemoteException

{

 

frameworks/native/libs/binder/BpBinder.cpp

status_tBpBinder::transact(

    uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)

{

    // Once a binder has died, it will nevercome back to life.

    if (mAlive) {

        status_t status =IPCThreadState::self()->transact(

            mHandle, code, data, reply, flags);

 

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

status_tIPCThreadState::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_LOG_TRANSACTIONS() {

        TextOutput::Bundle _b(alog);

        alog << "BC_TRANSACTION thr" << (void*)pthread_self() << " / hand "

            << handle << " /code " << TypeCode(code) << ": "

            << indent << data<< dedent << endl;

    }

 

    if (err == NO_ERROR) {

        LOG_ONEWAY(">>>> SENDfrom 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 (reply) {

            err = waitForResponse(reply);

        } else {

            Parcel fakeReply;

            err =waitForResponse(&fakeReply);

        }

 

status_tIPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)

{

    uint32_t cmd;

    int32_t err;

#ifdef_MTK_ENG_BUILD_

    cmd = 0;// initialze it for build error[-Werror=maybe-uninitialized]

#endif

 

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

 

 

status_tIPCThreadState::talkWithDriver(bool doReceive)

{

        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ,&bwr) >= 0)

 

然后调用到binder驱动里

最终,调用到方法binder_transaction

在里面对fd进行了处理


kernel-3.18/drivers/staging/android/binder.c

static void binder_transaction(structbinder_proc *proc,

                               structbinder_thread *thread,

                               structbinder_transaction_data *tr, int reply)

{

… …

                case BINDER_TYPE_FD:{

                                int target_fd;

                                struct file *file;

 

                                if (reply) {

                                        if(!(in_reply_to->flags & TF_ACCEPT_FDS)) {

                                               binder_user_error

                                                    ("%d:%dgot reply with fd, %d, but target does not allow fds\n",

                                                    proc->pid, thread->pid, fp->handle);

                                               return_error = BR_FAILED_REPLY;

                                               goto err_fd_not_allowed;

                                        }

                                } else if(!target_node->accept_fds) {

                                       binder_user_error

                                           ("%d:%d got transaction with fd, %d, but target does not allowfds\n",

                                            proc->pid, thread->pid, fp->handle);

                                       return_error = BR_FAILED_REPLY;

                                        gotoerr_fd_not_allowed;

                                }

//根据文件描述符获取到其对应的文件信息

//在某些Unix系统中,该方法名是getf

                                file =fget(fp->handle);

                                if (file ==NULL) {

                                       binder_user_error

                                           ("%d:%d got transaction with invalid fd, %d\n",

                                            proc->pid, thread->pid, fp->handle);

                                       return_error = BR_FAILED_REPLY;

                                        gotoerr_fget_failed;

                                }

                                if(security_binder_transfer_file

                                   (proc->tsk, target_proc->tsk, file) < 0) {

                                       fput(file);

                                       return_error = BR_FAILED_REPLY;

                                        goto err_get_unused_fd_failed;

                                }

//在目标进程中获取一个没有使用的文件描述符

                                target_fd =task_get_unused_fd_flags(target_proc, O_CLOEXEC);

                                if (target_fd< 0) {

                                        fput(file);

                                       return_error = BR_FAILED_REPLY;

                                        gotoerr_get_unused_fd_failed;

                                }

//把目标进程中新建的fdfile信息关联起来,实现了进程间fd的复制

                               task_fd_install(target_proc, target_fd, file);

                               trace_binder_transaction_fd(t, fp->handle, target_fd);

                               binder_debug(BINDER_DEBUG_TRANSACTION,

                                             "        fd %d -> %d\n", fp->handle,target_fd);

                                /* TODO: fput?*/

                                fp->binder =0;

                                fp->handle = target_fd;

#ifdefBINDER_MONITOR

                                e->fd =target_fd;

#endif

                        }

                        break;

 




  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android BinderAndroid操作系统中的一个IPC(进程间通信)机制,用于实现进程之间的通信和数据传输。Binder的源码主要位于frameworks/native目录下。 在Binder的源码中,最核心的部分是Binder驱动和Binder服务。Binder驱动是位于内核空间的组件,负责处理进程间的数据传输和交互。Binder服务是位于用户空间的组件,负责提供接口和功能来进行进程间通信。 在Binder的源码中,主要涉及到以下几个重要的文件和目录: 1. drivers目录:包含了Binder驱动的代码,其中最重要的文件是binder.c,它实现了Binder驱动的核心逻辑。 2. include目录:包含了Binder的头文件,其中最重要的文件是binder.h,它定义了Binder的接口和数据结构。 3. libbinder目录:包含了Binder服务的代码,其中最重要的文件是IBinder.cpp和BpBinder.cpp,它们分别实现了Binder服务的接口和代理类。 4. services目录:包含了一些系统级别的Binder服务,例如Package Manager Service和Activity Manager Service。 如果你想深入了解Android Binder的源码,可以参考以下资源: 1. Android 源码:你可以从Android官网或者GitHub上获取Android源码,并在frameworks/native目录下查看Binder相关的代码。 2. Android系统架构指南:Android官网提供了关于Android系统架构的详细文档,其中有关IPC和Binder的章节对于理解Binder的实现原理和源码结构很有帮助。 3. 《深入理解Android:卷2》一书中有关于Binder的详细介绍和源码解析,可以作为参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值