AIDL底层实现的猜想

    技术2025-06-05  78

           这篇文章是我AIDL底层实现的猜想。

    还是拿AIDL实例做例子:

            首先,在onServiceConnected中,入参‍service作为一个IBinder,通过myService = IMyService.Stub.asInterface(service);来获得真正的service。看一下生成的IMyService.java中asInterface(android.os.IBinder obj)的实现:

    ...

    ‍package com.yubing;public interface IMyService extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.yubing.IMyService{private static final java.lang.String DESCRIPTOR = "com.yubing.IMyService";...

    public static com.yubing.IMyService asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.yubing.IMyService))) {return ((com.yubing.IMyService)iin);}return new com.yubing.IMyService.Stub.Proxy(obj);}...

    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{switch (code){case INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_getValue:{data.enforceInterface(DESCRIPTOR);java.lang.String _result = this.getValue();reply.writeNoException();reply.writeString(_result);return true;}}return super.onTransact(code, data, reply, flags);}

    private static class Proxy implements com.yubing.IMyService{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}...

    public java.lang.String getValue() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getValue, _data, _reply, 0);_reply.readException();_result = _reply.readString();}finally {_reply.recycle();_data.recycle();}return _result;}

    }

    ...

    }

    我的第一个猜想:如果是本地调用,将会在return ((com.yubing.IMyService)iin);处返回;而如果是远程调用,将会在return new com.yubing.IMyService.Stub.Proxy(obj);处返回。

    这样,在onServiceConnected中的myService成为一个com.yubing.IMyService$Stub$Proxy的实例。

           然后,我的第二个猜想:myService.getValue()通过transact将service需要的入参写到/dev/binder driver,并等待返回。service端有个循环,不断查看driver上的数据,一旦有服务请求,service会调用onTransact。这样,真正的service,也就是‍MyServiceImpl中的‍getValue()被调用。

     

    ‍package com.yubing;

    ...

    public class MyService extends Service{    // IMyService.Stub类是根据IMyService.aidl文件生成的类,该类中包含了接口方法(getValue)    public class MyServiceImpl extends IMyService.Stub    {        @Override        public String getValue() throws RemoteException        {            return "从AIDL服务获得的值:OK.";        }    }...

    }

           最后,service执行的结果将会写到‍/dev/binder driver,transact返回,调用结束。

           基本流程如上所述,这里还有两个问题,第一是client端调用了transact后,是如何实现等待的,onTransact是如何被调用的?第二是server端得到结果后,是如何通知client端的,client端又是如何返回的?下面来处理这些问题。

           继续我的第三个猜想:transact调用的是BpBinder.cpp中的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;}

    BpBinder调用‍IPCThreadState::transact。

     

     

    status_t IPCThreadState::transact(int32_t handle,                                  uint32_t code, const Parcel& data,                                  Parcel* reply, uint32_t flags){    ...        if (err == NO_ERROR) {        LOG_ONEWAY(">>>> SEND from 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 ((flags & TF_ONE_WAY) == 0) {        if (reply) {            err = waitForResponse(reply);        } else {            Parcel fakeReply;            err = waitForResponse(&fakeReply);        }                IF_LOG_TRANSACTIONS() {            TextOutput::Bundle _b(alog);            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "                << handle << ": ";            if (reply) alog << indent << *reply << dedent << endl;            else alog << "(none requested)" << endl;        }    } else {        err = waitForResponse(NULL, NULL);    }        return err;}

     

    ‍waitForResponse也在这里实现了,它通过talkWithDriver读写binder kernel driver:

    status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){    ...

        while (1) {‍        if ((err=talkWithDriver()) < NO_ERROR) break;        ...

            switch (cmd) {        ...

            case BR_REPLY:            {                binder_transaction_data tr;                err = mIn.read(&tr, sizeof(tr));                LOG_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 size_t*>(tr.data.ptr.offsets),                            tr.offsets_size/sizeof(size_t),                            freeBuffer, this);                    } else {                        err = *static_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 size_t*>(tr.data.ptr.offsets),                            tr.offsets_size/sizeof(size_t), this);                    }                } else {                    freeBuffer(NULL,                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),                        tr.data_size,                        reinterpret_cast<const size_t*>(tr.data.ptr.offsets),                        tr.offsets_size/sizeof(size_t), this);                    continue;                }            }            goto finish;

                ...

            }    }

    finish:    if (err != NO_ERROR) {        if (acquireResult) *acquireResult = err;        if (reply) reply->setError(err);        mLastError = err;    }        return err;}在用‍IPCThreadState::transact中,通过writeTransactionData将需要的数据写到/dev/binder driver。以上都是client端的动作。

    在server端,在service启动的时候,通过IPCThreadState::joinThreadPool ‍talkWithDriver并executeCommand(cmd)。

     

    void IPCThreadState::joinThreadPool(bool isMain){

         ...

        do {        ...

            // now get the next command to be processed, waiting if necessary        result = talkWithDriver();        if (result >= NO_ERROR) {            size_t IN = mIn.dataAvail();            if (IN < sizeof(int32_t)) continue;            cmd = mIn.readInt32();            IF_LOG_COMMANDS() {                alog << "Processing top-level Command: "                    << getReturnString(cmd) << endl;            }

                result = executeCommand(cmd);        }        ...

        } while (result != -ECONNREFUSED && result != -EBADF);

        ...

    }我们这里的cmd是‍BR_TRANSACTION。

     

        case BR_TRANSACTION:        {            binder_transaction_data tr;             ...

                Parcel reply;            ...

                if (tr.target.ptr) {                sp<BBinder> b((BBinder*)tr.cookie);                const status_t error = b->transact(tr.code, buffer, &reply, 0);                if (error < NO_ERROR) reply.setError(error);                            } else {                const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);                if (error < NO_ERROR) reply.setError(error);            }            ...

                if ((tr.flags & TF_ONE_WAY) == 0) {                LOG_ONEWAY("Sending reply to %d!", mCallingPid);                sendReply(reply, 0);            } else {                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);            }            ...        }        break;

     

     

    这里‍b->transact调用‍BBinder::transact,并通过sendReply把输出结果写到binder kernel driver。

     

    ‍status_t BBinder::transact(    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){    data.setDataPosition(0);

        status_t err = NO_ERROR;    switch (code) {        case PING_TRANSACTION:            reply->writeInt32(pingBinder());            break;        default:            err = onTransact(code, data, reply, flags);            break;    }

        if (reply != NULL) {        reply->setDataPosition(0);    }

        return err;}在这里onTransact得到调用。到此,第一个问题解决了。

    ‍status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags){    status_t err;    status_t statusBuffer;    err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);    if (err < NO_ERROR) return err;        return waitForResponse(NULL, NULL);}

    在sendReply中,通过waitForResponse把结果写到驱动。到此第二个问题解决了。但是我们又有了几个新问题:第三:client端,为什么transact调用的是BpBinder.cpp中的transact?第四:server端,‍const status_t error = b->transact(tr.code, buffer, &reply, 0);中,b哪儿来的?第五:client和server端都是如何与驱动交互的?

    继续调研:第四个猜想:client端调用‍getStrongProxyForHandle最终得到的是‍BpBinder。

     

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

        AutoMutex _l(mLock);

        handle_entry* e = lookupHandleLocked(handle);

        if (e != NULL) {        // We need to create a new BpBinder if there isn't currently one, OR we        // are unable to acquire a weak reference on this current one. See comment        // in getWeakProxyForHandle() for more info about this.        IBinder* b = e->binder;        if (b == NULL || !e->refs->attemptIncWeak(this)) {            b = new BpBinder(handle);             e->binder = b;            if (b) e->refs = b->getWeakRefs();            result = b;        } else {            // This little bit of nastyness is to allow us to add a primary            // reference to the remote proxy when this team doesn't have one            // but another team is sending the handle to us.            result.force_set(b);            e->refs->decWeak(this);        }    }

        return result;}

     

    第五个猜想:service继承自‍BnInterface,而‍BnInterface 继承自BBinder。在server启动的时候,已经把这个BBinder保存起来,当被调用时,从cookie中读取。

    最新回复(0)