Android Binder Mechanism II (client and normal server)

Source: Internet
Author: User

Before we talk about the communication between them, let's take mediaserver as an example to see what the normal server process is doing.

int main () {...//Get Processstate instance sp<processstate> proc (processstate::self ());// Get the Binderclient instance of ServiceManager        sp<iservicemanager> sm = Defaultservicemanager (), ...// MediaPlayer Service Mediaplayerservice::instantiate () through ServiceManager binderclient to the system        ;        ...//start run        processstate::self ()->startthreadpool ();        Ipcthreadstate::self ()->jointhreadpool ();}

Defaultservicemanager () has been introduced in the previous article.

The implementation of Mediaplayerservice::instantiate () such as the following, is AddService to ServiceManager. Similar to the getservice of the previous article, it is not introduced.

void Mediaplayerservice::instantiate () {    Defaultservicemanager ()->addservice (            String16 ("Media.player" ), New Mediaplayerservice ());}
Next look at the implementation of Processstate::self ()->startthreadpool ()

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;};
As a matter of fact. This function simply creates a new thread, and then creates a ipcthreadstate in the process. and called 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->mdriv            ERFD, result);        Abort (); }/Let this thread exit the thread pool if it's no longer//needed and it's not the main proces        S 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. The main thread and newly created threads. Is doing one thing, Talkwithdriver reads the binder driver and then handles the request ExecuteCommand. This is what the normal server process has been doing since it started: Waiting for a client request. Process the request. It is then returned to the client.

Now that the server process is ready. Now it's up to the client to shine, and the client will ask the server to do something through binder. Next 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;}

Getmediaplayerservice () has been analyzed before. Returning a bpmediaplayerservice, here's a question: Why would this bpmediaplayerservice be able to do binder communication with the mediaplayerservice process, rather than any other server processes?

Think back to 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 binder = Sm->getservice (String16 ("Media.player")), and the return value binder will be used as the Bpmediaplayerservice constructor. To come down to see 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) {con St flat_binder_object* flat = In.readobJect (FALSE); if (flat) {switch (flat->type) {case Binder_type_binder: *out = Static_cast<ibind                Er*> (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;}

The Unflatten_binder function. Flat->type and Flat->handle are assigned values in ServiceManager, and the Flat->type value is binder_type_handle,flat-> The value of the handle is the corresponding handle value for the service being queried, and the intermediate process involves the binder's underlying driver code, not described here.

This way binder = Sm->getservice (String16 ("Media.player") is run. Binder=bpbinder (Handle), where the value of Handle is the corresponding Handle value for the service being queried. Such Communication between the client side and the service side is established.

Finish analyzing Getmediaplayerservice (). The communication pathway was established and the communication was formally entered.


Sp<imediaplayer>player (Service->create (this, Maudiosessionid));

Enter IMediaPlayerService.cpp to see 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 were able to very easily instruct remote () to return Bpbinder (HANDLE), Transact (Create,data, &reply) to write data to the binder driver and wake up the service process. Next we'll see how the server reacts.

Now we know that the server process is always reading the binder driver. Then ExecuteCommand. The following is a direct look at 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.D Ata_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 ha ve inherited a reduced the caller, but does not//want to run                    S. The driver set our//priority already (though not we 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 is from the caller. Ensure this thread was in the background scheduling class,//Since the driver won ' t modify Schedulin                    g Classes for us. The scheduling group is reset to default by the caller//once this metHod returns after the transaction are 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.targe                    T.ptr << "/Code" << TypeCode (Tr.code) << ":" << indent << buffer << dedent << Endl << "Data addr =" << Reinte Rpret_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&LT                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",//Mcalli                        Ngpid, 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 <<": "&L            t;< indent << reply << dedent << Endl;    }} break;        ... default:printf ("* * * COMMAND%d received from Binder driver\n", cmd);        result = Unknown_error;    Break    } if (Result! = No_error) {Mlasterror = result; } return result;

Look 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_err OR) Reply.seterror (error);}
The b here is actually the Mediaplayerservice object that we created at AddService, which is a data type that has been transferred and transformed, including the binder driver.


void Mediaplayerservice::instantiate () {    Defaultservicemanager ()->addservice (            String16 ("Media.player" ), New Mediaplayerservice ());}

Look at the following inheritance relationships,

Classmediaplayerservice:public Bnmediaplayerservice

Mediaplayerservice itself does not implement the Transact method, so. B->transact (Tr.code,buffer, &reply, Tr.flags) is a Bnmediaplayerservice method called Transact.

Enter IMEDIAPLAYERSERVICE.CPP to find the Transact method for bnmediaplayerservice, such as the following:

status_t bnmediaplayerservice::ontransact (    uint32_t Code, const parcel& data, parcel* reply, uint32_t flags) { C1/>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. Enter the 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;}
So far, the server has finished processing the transaction. Next, return the processing results to the client, see here:

if ((Tr.flags & tf_one_way) = = 0) {Log_oneway ("Sending reply to%d!", mcallingpid); sendReply (reply, 0);} else {Log_one ("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);}
Calling Sendreply writes the result back to the binder driver, allowing it to return to the client process.

Communication is complete.

Android Binder Mechanism II (client and normal server)

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.