Android binder Mechanism 2 (client and common server), androidbinder

Source: Internet
Author: User

Android binder Mechanism 2 (client and common server), androidbinder

Before talking about the communication between them, let's take MediaServer as an example to see what common Server processes are doing.

Int main (){...... // Obtain the ProcessState instance sp <ProcessState> proc (ProcessState: self (); // obtain the ServiceManager's Binder client instance sp <IServiceManager> sm = defaservicservicemanager ();...... // Use the Binder client of ServiceManager to register the MediaPlayer service MediaPlayerService: instantiate ();...... // Start run ProcessState: self ()-> startThreadPool (); IPCThreadState: self ()-> joinThreadPool ();}

Defaservicservicemanager () has been introduced in the previous article.

MediaPlayerService: instantiate () is implemented as follows, that is, addService to ServiceManager, which is similar to getService in the previous article, so it is not described.

void MediaPlayerService::instantiate() {    defaultServiceManager()->addService(            String16("media.player"), new MediaPlayerService());}
Next, let's take a look at ProcessState: self ()-> startThreadPool () implementation.

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());    }}
class PoolThread : public Thread{public:    PoolThread(bool isMain)        : mIsMain(isMain)    {    }    protected:    virtual bool threadLoop()    {        IPCThreadState::self()->joinThreadPool(mIsMain);        return false;    }        const bool mIsMain;};
In fact, this function creates a new thread, creates an IPCThreadState in the thread, and calls the joinThreadPool function.

void IPCThreadState::joinThreadPool(bool isMain){    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);        set_sched_policy(mMyThreadId, SP_FOREGROUND);            status_t result;    do {        processPendingDerefs();        // now get the next command to be processed, waiting if necessary        result = getAndExecuteCommand();        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {            ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",                  mProcess->mDriverFD, result);            abort();        }                // 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);    mOut.writeInt32(BC_EXIT_LOOPER);    talkWithDriver(false);}
status_t IPCThreadState::getAndExecuteCommand(){    status_t result;    int32_t cmd;    result = talkWithDriver();    if (result >= NO_ERROR) {        size_t IN = mIn.dataAvail();        if (IN < sizeof(int32_t)) return result;        cmd = mIn.readInt32();        result = executeCommand(cmd);        set_sched_policy(mMyThreadId, SP_FOREGROUND);    }    return result;}

We can see that the main thread and the newly created thread are doing one thing. talkWithDriver reads the Binder driver and then executes the command to process the request. This is what the common Server process has been doing after it is started: Wait for the client request, process the request, and then return it to the client.

Now that the Server process is ready, it is time for the Client to make a debut. The Client will request the Server to do something through the Binder. Next, let's look at the Code:

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length){    status_t err = UNKNOWN_ERROR;    const sp<IMediaPlayerService>& service(getMediaPlayerService());    if (service != 0) {        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||            (NO_ERROR != player->setDataSource(fd, offset, length))) {            player.clear();        }        err = attachNewPlayer(player);    }    return err;}

After analysis before getMediaPlayerService (), a BpMediaPlayerService is returned. The following is a question: why can this BpMediaPlayerService communicate with the MediaPlayerService process through a Binder instead of other Server processes?

Let's review the Code:

/*static*/const sp<IMediaPlayerService>&IMediaDeathNotifier::getMediaPlayerService(){    Mutex::Autolock _l(sServiceLock);    if (sMediaPlayerService == 0) {        sp<IServiceManager> sm = defaultServiceManager();        sp<IBinder> binder;        do {            binder = sm->getService(String16("media.player"));            if (binder != 0) {                break;            }            ALOGW("Media player service not published, waiting...");            usleep(500000); // 0.5 s        } while (true);        if (sDeathNotifier == NULL) {            sDeathNotifier = new DeathNotifier();        }        binder->linkToDeath(sDeathNotifier);        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);    }    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");    return sMediaPlayerService;}
The answer should be in the binder = sm-> getService (String16 ("media. player") sentence, the returned value of binder will be used as a parameter of the BpMediaPlayerService constructor. Let's take a look at getService.

virtual sp<IBinder> getService(const String16& name) const    {        unsigned n;        for (n = 0; n < 5; n++){            sp<IBinder> svc = checkService(name);            if (svc != NULL) return svc;            ALOGI("Waiting for service %s...\n", String8(name).string());            sleep(1);        }        return NULL;    }    virtual sp<IBinder> checkService( const String16& name) const    {        Parcel data, reply;        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());        data.writeString16(name);        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);        return reply.readStrongBinder();    }sp<IBinder> Parcel::readStrongBinder() const{    sp<IBinder> val;    unflatten_binder(ProcessState::self(), *this, &val);    return val;}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);            case BINDER_TYPE_HANDLE:                *out = proc->getStrongProxyForHandle(flat->handle);                return finish_unflatten_binder(                    static_cast<BpBinder*>(out->get()), *flat, in);        }            }    return BAD_TYPE;}

In the unflatten_binder function, flat-> type and flat-> handle are assigned values in ServiceManager. The value of flat-> type is BINDER_TYPE_HANDLE, the value of flat-> handle is the Handle value corresponding to the queried Service. The intermediate process involves the code of the underlying driver of the binder, which is not described here.

In this way, binder = sm-> getService (String16 ("media. player ") after execution, binder = BpBinder (Handle), where the Handle value is the Handle value corresponding to the queried Service. In this way, communication between the client and the service is established.

After analyzing the getMediaPlayerService (), the communication path is established, and then the communication is officially started.

Sp <IMediaPlayer> player (service-> create (this, mAudioSessionId ));

Go to IMediaPlayerService. cpp to check the implementation of create.

virtual sp<IMediaPlayer> create(            const sp<IMediaPlayerClient>& client, int audioSessionId) {        Parcel data, reply;        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());        data.writeStrongBinder(client->asBinder());        data.writeInt32(audioSessionId);        remote()->transact(CREATE, data, &reply);        return interface_cast<IMediaPlayer>(reply.readStrongBinder());    }
After the previous analysis, we can easily guide remote () to return BpBinder (handle), transact (CREATE, data, & reply) to write data to the Binder driver, and wake up the Service process. Next we will look at how the Server will respond. Now we know that the Server process has been reading the Binder driver and then executeCommand. The following describes the implementation of executeCommand.

status_t IPCThreadState::executeCommand(int32_t cmd){    BBinder* obj;    RefBase::weakref_type* refs;    status_t result = NO_ERROR;        switch (cmd) {    ……    case BR_TRANSACTION:        {            binder_transaction_data tr;            result = mIn.read(&tr, sizeof(tr));            ALOG_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.                    set_sched_policy(mMyThreadId, SP_BACKGROUND);                }            }            //ALOGI(">>>> 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);            }                        //ALOGI("<<<< 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;    ……    default:        printf("*** BAD COMMAND %d received from Binder driver\n", cmd);        result = UNKNOWN_ERROR;        break;    }    if (result != NO_ERROR) {        mLastError = result;    }        return result;}

Here:

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);}
Here, B is actually the MediaPlayerService object we created during addService. After transmission and conversion, including the Binder driver, it becomes such a data type.

void MediaPlayerService::instantiate() {    defaultServiceManager()->addService(            String16("media.player"), new MediaPlayerService());}

See the following inheritance relationship,

ClassMediaPlayerService: public BnMediaPlayerService

MediaPlayerService itself does not implement the transact method. Therefore, B-> transact (tr. code, buffer, & reply, tr. flags) calls the transact method of BnMediaPlayerService.

Go to IMediaPlayerService. cpp and find the transact method of BnMediaPlayerService, as shown below:

status_t BnMediaPlayerService::onTransact(    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){    switch (code) {        case CREATE: {            CHECK_INTERFACE(IMediaPlayerService, data, reply);            sp<IMediaPlayerClient> client =                interface_cast<IMediaPlayerClient>(data.readStrongBinder());            int audioSessionId = data.readInt32();            sp<IMediaPlayer> player = create(client, audioSessionId);            reply->writeStrongBinder(player->asBinder());            return NO_ERROR;        } break;……}
Sp <IMediaPlayer> player = create (client, audioSessionId) The create method called here is implemented in the MediaPlayerService class and enters MediaPlayerService. cpp:

sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,        int audioSessionId){    pid_t pid = IPCThreadState::self()->getCallingPid();    int32_t connId = android_atomic_inc(&mNextConnId);    sp<Client> c = new Client(            this, pid, connId, client, audioSessionId,            IPCThreadState::self()->getCallingUid());    ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,         IPCThreadState::self()->getCallingUid());    /* add by Gary. start {{----------------------------------- */    c->setScreen(mScreen);    /* add by Gary. end   -----------------------------------}} */    c->setSubGate(mGlobalSubGate);  // 2012-03-12, add the global interfaces to control the subtitle gate    wp<Client> w = c;    {        Mutex::Autolock lock(mLock);        mClients.add(w);    }    return c;}
Till now, the Server has finished processing the transaction, and then returns the processing result to the client. See here:

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);}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);}
Call sendReply to write the result back to the Binder driver to return the client process. Communication is complete.


Q: Is there a limit on the number of binder threads in the android process?

In AndroidManifest. xml
Android: syncable = "false" android: multiprocess = "false"
 
What is Android Binder? Binder is a driver.

In Android, Binder is used for inter-process communication. ViewBinder should be a Binder class. When this class is called by the last application, this class calls the underlying library.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.