【android】binder机制-service

来源:互联网 发布:金盾软件下载 编辑:程序博客网 时间:2024/05/15 04:08

参考下mediaservice的服务,在framework/base/media/mediaservice/main_mediaservice.cpp中的main函数是mediaservice的入口函数

int main(int argc, char** argv){    sp<ProcessState> proc(ProcessState::self());    sp<IServiceManager> sm = defaultServiceManager();    LOGI("ServiceManager: %p", sm.get());    AudioFlinger::instantiate();    MediaPlayerService::instantiate();    CameraService::instantiate();    AudioPolicyService::instantiate();    ProcessState::self()->startThreadPool();    IPCThreadState::self()->joinThreadPool();}

这里着重看后两个语句就行

ProcessState::self()->startThreadPool();和IPCThreadState::self()->joinThreadPool();

在/frameworks/base/libs/binder目录中的ProcessState.cpp定义了对象ProcessState类,该类维护所有的service代理

启动service时会调用ProcessState::self()获取一个service实例

sp<ProcessState> ProcessState::self(){    if (gProcess != NULL) return gProcess;        AutoMutex _l(gProcessMutex);    if (gProcess == NULL) gProcess = new ProcessState;    return gProcess;}

该函数创建了一个新的ProcessState并将其指针返回

创建ProcessState对象会调用其构造函数

ProcessState::ProcessState()    : mDriverFD(open_driver())    , mVMStart(MAP_FAILED)    , mManagesContexts(false)    , mBinderContextCheckFunc(NULL)    , mBinderContextUserData(NULL)    , mThreadPoolStarted(false)    , mThreadPoolSeq(1){    if (mDriverFD >= 0) {        // XXX Ideally, there should be a specific define for whether we        // have mmap (or whether we could possibly have the kernel module        // availabla).#if !defined(HAVE_WIN32_IPC)        // mmap the binder, providing a chunk of virtual address space to receive transactions.        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);        if (mVMStart == MAP_FAILED) {            // *sigh*            LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");            close(mDriverFD);            mDriverFD = -1;        }#else        mDriverFD = -1;#endif    }    if (mDriverFD < 0) {        // Need to run without the driver, starting our own thread pool.    }}

首先调用open_driver打开/dev/binder

static int open_driver(){    if (gSingleProcess) {        return -1;    }    int fd = open("/dev/binder", O_RDWR);//打开/dev/binder设备文件    if (fd >= 0) {        fcntl(fd, F_SETFD, FD_CLOEXEC);        int vers;#if defined(HAVE_ANDROID_OS)        status_t result = ioctl(fd, BINDER_VERSION, &vers);//获取版本#else        status_t result = -1;        errno = EPERM;#endif        if (result == -1) {            LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));            close(fd);            fd = -1;        }        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {            LOGE("Binder driver protocol does not match user space protocol!");            close(fd);            fd = -1;        }#if defined(HAVE_ANDROID_OS)        size_t maxThreads = 15;        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//设置最大线程数        if (result == -1) {            LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));        }#endif            } else {        LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));    }    return fd;}

接着mmap()映射内存

mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0)

这里基本上完成了binder通讯的基本操作

接着看IPCThreadState::self()->joinThreadPool();

void IPCThreadState::joinThreadPool(bool isMain){    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);        // This thread may have been spawned by a thread that was in the background    // scheduling group, so first we will make sure it is in the default/foreground    // one to avoid performing an initial transaction in the background.    androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);            status_t result;    do {        int32_t cmd;                // When we've cleared the incoming command queue, process any pending derefs        if (mIn.dataPosition() >= mIn.dataSize()) {            size_t numPending = mPendingWeakDerefs.size();            if (numPending > 0) {                for (size_t i = 0; i < numPending; i++) {                    RefBase::weakref_type* refs = mPendingWeakDerefs[i];                    refs->decWeak(mProcess.get());                }                mPendingWeakDerefs.clear();            }            numPending = mPendingStrongDerefs.size();            if (numPending > 0) {                for (size_t i = 0; i < numPending; i++) {                    BBinder* obj = mPendingStrongDerefs[i];                    obj->decStrong(mProcess.get());                }                mPendingStrongDerefs.clear();            }        }        // now get the next command to be processed, waiting if necessary        result = talkWithDriver();//调用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);//调用executeCommand处理命令        }                // After executing the command, ensure that the thread is returned to the        // default cgroup before rejoining the pool.  The driver takes care of        // restoring the priority, but doesn't do anything with cgroups so we        // need to take care of that here in userspace.  Note that we do make        // sure to go in the foreground after executing a transaction, but        // there are other callbacks into user code that could have changed        // our group so we want to make absolutely sure it is put back.        androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);        // Let this thread exit the thread pool if it is no longer        // needed and it is not the main process thread.        if(result == TIMED_OUT && !isMain) {            break;        }    } while (result != -ECONNREFUSED && result != -EBADF);    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",        (void*)pthread_self(), getpid(), (void*)result);        mOut.writeInt32(BC_EXIT_LOOPER);    talkWithDriver(false);//调用talkWithDriver}

这里调用talkWithDriver和设备驱动打交道(talk with driver)

status_t IPCThreadState::talkWithDriver(bool doReceive){    LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");        binder_write_read bwr;//声明一个binder_write_read结构体        // Is the read buffer empty?    const bool needRead = mIn.dataPosition() >= mIn.dataSize();        // We don't want to write anything if we are still reading    // from data left in the input buffer and the caller    // has requested to read the next data.    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;        bwr.write_size = outAvail;//对bwr赋值初始化    bwr.write_buffer = (long unsigned int)mOut.data();    // This is what we'll read.    if (doReceive && needRead) {        bwr.read_size = mIn.dataCapacity();        bwr.read_buffer = (long unsigned int)mIn.data();    } else {        bwr.read_size = 0;    }        IF_LOG_COMMANDS() {        TextOutput::Bundle _b(alog);        if (outAvail != 0) {            alog << "Sending commands to driver: " << indent;            const void* cmds = (const void*)bwr.write_buffer;            const void* end = ((const uint8_t*)cmds)+bwr.write_size;            alog << HexDump(cmds, bwr.write_size) << endl;            while (cmds < end) cmds = printCommand(alog, cmds);            alog << dedent;        }        alog << "Size of receive buffer: " << bwr.read_size            << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;    }        // Return immediately if there is nothing to do.    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_LOG_COMMANDS() {            alog << "About to read/write, write size = " << mOut.dataSize() << endl;        }#if defined(HAVE_ANDROID_OS)        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//调用了ioctl方法的BINDER_WRITE_READ            err = NO_ERROR;        else            err = -errno;#else        err = INVALID_OPERATION;#endif        IF_LOG_COMMANDS() {            alog << "Finished read/write, write size = " << mOut.dataSize() << endl;        }    } while (err == -EINTR);        IF_LOG_COMMANDS() {        alog << "Our err: " << (void*)err << ", write consumed: "            << bwr.write_consumed << " (of " << mOut.dataSize()<< "), read consumed: " << bwr.read_consumed << endl;    }    if (err >= NO_ERROR) {        if (bwr.write_consumed > 0) {            if (bwr.write_consumed < (ssize_t)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);        }        IF_LOG_COMMANDS() {            TextOutput::Bundle _b(alog);            alog << "Remaining data size: " << mOut.dataSize() << endl;            alog << "Received commands from driver: " << indent;            const void* cmds = mIn.data();            const void* end = mIn.data() + mIn.dataSize();            alog << HexDump(cmds, mIn.dataSize()) << endl;            while (cmds < end) cmds = printReturnCommand(alog, cmds);            alog << dedent;        }        return NO_ERROR;    }        return err;}


调用executeCommand处理命令

status_t IPCThreadState::executeCommand(int32_t cmd){    BBinder* obj;    RefBase::weakref_type* refs;    status_t result = NO_ERROR;        switch (cmd) {    case BR_ERROR:        result = mIn.readInt32();        break;            case BR_OK:        break;            case BR_ACQUIRE:        refs = (RefBase::weakref_type*)mIn.readInt32();        obj = (BBinder*)mIn.readInt32();        LOG_ASSERT(refs->refBase() == obj,"BR_ACQUIRE: object %p does not match cookie %p (expected %p)",refs, obj, refs->refBase());        obj->incStrong(mProcess.get());        IF_LOG_REMOTEREFS() {            LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);            obj->printRefs();        }        mOut.writeInt32(BC_ACQUIRE_DONE);        mOut.writeInt32((int32_t)refs);        mOut.writeInt32((int32_t)obj);        break;            case BR_RELEASE:        refs = (RefBase::weakref_type*)mIn.readInt32();        obj = (BBinder*)mIn.readInt32();        LOG_ASSERT(refs->refBase() == obj,                   "BR_RELEASE: object %p does not match cookie %p (expected %p)",                   refs, obj, refs->refBase());        IF_LOG_REMOTEREFS() {            LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);            obj->printRefs();        }        mPendingStrongDerefs.push(obj);        break;            case BR_INCREFS:        refs = (RefBase::weakref_type*)mIn.readInt32();        obj = (BBinder*)mIn.readInt32();        refs->incWeak(mProcess.get());        mOut.writeInt32(BC_INCREFS_DONE);        mOut.writeInt32((int32_t)refs);        mOut.writeInt32((int32_t)obj);        break;            case BR_DECREFS:        refs = (RefBase::weakref_type*)mIn.readInt32();        obj = (BBinder*)mIn.readInt32();        // NOTE: This assertion is not valid, because the object may no        // longer exist (thus the (BBinder*)cast above resulting in a different        // memory address).        //LOG_ASSERT(refs->refBase() == obj,        //           "BR_DECREFS: object %p does not match cookie %p (expected %p)",        //           refs, obj, refs->refBase());        mPendingWeakDerefs.push(refs);        break;            case BR_ATTEMPT_ACQUIRE:        refs = (RefBase::weakref_type*)mIn.readInt32();        obj = (BBinder*)mIn.readInt32();                 {            const bool success = refs->attemptIncStrong(mProcess.get());            LOG_ASSERT(success && refs->refBase() == obj,                       "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",                       refs, obj, refs->refBase());                        mOut.writeInt32(BC_ACQUIRE_RESULT);            mOut.writeInt32((int32_t)success);        }        break;        case BR_TRANSACTION:        {            binder_transaction_data tr;            result = mIn.read(&tr, sizeof(tr));            LOG_ASSERT(result == NO_ERROR,                "Not enough command data for brTRANSACTION");            if (result != NO_ERROR) break;                        Parcel buffer;            buffer.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);                        const pid_t origPid = mCallingPid;            const uid_t origUid = mCallingUid;                        mCallingPid = tr.sender_pid;            mCallingUid = tr.sender_euid;                        int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);            if (gDisableBackgroundScheduling) {                if (curPrio > ANDROID_PRIORITY_NORMAL) {                    // We have inherited a reduced priority from the caller, but do not                    // want to run in that state in this process.  The driver set our                    // priority already (though not our scheduling class), so bounce                    // it back to the default before invoking the transaction.                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);                }            } else {                if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {                    // We want to use the inherited priority from the caller.                    // Ensure this thread is in the background scheduling class,                    // since the driver won't modify scheduling classes for us.                    // The scheduling group is reset to default by the caller                    // once this method returns after the transaction is complete.                    androidSetThreadSchedulingGroup(mMyThreadId,                                                    ANDROID_TGROUP_BG_NONINTERACT);                }            }            //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);                        Parcel reply;            IF_LOG_TRANSACTIONS() {                TextOutput::Bundle _b(alog);                alog << "BR_TRANSACTION thr " << (void*)pthread_self()                    << " / obj " << tr.target.ptr << " / code "                    << TypeCode(tr.code) << ": " << indent << buffer                    << dedent << endl                    << "Data addr = "                    << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)                    << ", offsets addr="                    << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;            }            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);            } else {                const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);                if (error < NO_ERROR) reply.setError(error);            }                        //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",            //     mCallingPid, origPid, origUid);                        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);            }                        mCallingPid = origPid;            mCallingUid = origUid;            IF_LOG_TRANSACTIONS() {                TextOutput::Bundle _b(alog);                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "                    << tr.target.ptr << ": " << indent << reply << dedent << endl;            }                    }        break;        case BR_DEAD_BINDER:        {            BpBinder *proxy = (BpBinder*)mIn.readInt32();            proxy->sendObituary();            mOut.writeInt32(BC_DEAD_BINDER_DONE);            mOut.writeInt32((int32_t)proxy);        } break;            case BR_CLEAR_DEATH_NOTIFICATION_DONE:        {            BpBinder *proxy = (BpBinder*)mIn.readInt32();            proxy->getWeakRefs()->decWeak(proxy);        } break;            case BR_FINISHED:        result = TIMED_OUT;        break;            case BR_NOOP:        break;            case BR_SPAWN_LOOPER:        mProcess->spawnPooledThread(false);        break;            default:        printf("*** BAD COMMAND %d received from Binder driver\n", cmd);        result = UNKNOWN_ERROR;        break;    }    if (result != NO_ERROR) {        mLastError = result;    }        return result;}