Android Framework Analysis---2 message mechanism native layer

Source: Internet
Author: User
Tags epoll

In the Android messaging mechanism. It not only provides a message loop for Java used by application development. In fact, the Java mechanism finally depends on native to achieve. The native not only provides a set of messaging and processing mechanisms, but also provides a listening mechanism that defines the I/O time of the file description descriptor. Let's analyze it from the detailed code below.

Key classes for the native layer:

Looper.cpp. The hibernate and wake mechanisms for pollonce and wake are provided in this class.

The same time in the constructor also creates the pipeline and adds the epoll mechanism. To monitor its status changes.

Looper::looper (bool allownoncallbacks): Mallownoncallbacks (Allownoncallbacks), Msendingmessage (false), mRes    Ponseindex (0), Mnextmessageuptime (llong_max) {int wakefds[2];    int result = pipe (WAKEFDS);  LOG_ALWAYS_FATAL_IF (Result! = 0, "Could not create wake pipe.    errno=%d ", errno);    MWAKEREADPIPEFD = Wakefds[0];    MWAKEWRITEPIPEFD = wakefds[1];    result = Fcntl (MWAKEREADPIPEFD, F_SETFL, O_nonblock);  LOG_ALWAYS_FATAL_IF (Result! = 0, "Could not make wake read pipe non-blocking.    errno=%d ", errno);    result = Fcntl (MWAKEWRITEPIPEFD, F_SETFL, O_nonblock);  LOG_ALWAYS_FATAL_IF (Result! = 0, "Could not make wake write pipe non-blocking.    errno=%d ", errno);    Allocate the Epoll instance and register the wake pipe.    MEPOLLFD = Epoll_create (epoll_size_hint);  Log_always_fatal_if (MEPOLLFD < 0, "Could not create epoll instance.    errno=%d ", errno);    struct Epoll_event eventitem; memset (& eventitem, 0, sizeof (epoll_event)); //Zero out unused members of data field Union eventitem.events = Epollin;    EVENTITEM.DATA.FD = MWAKEREADPIPEFD;    result = Epoll_ctl (MEPOLLFD, Epoll_ctl_add, MWAKEREADPIPEFD, & Eventitem);  LOG_ALWAYS_FATAL_IF (Result! = 0, "Could not add wake read pipe to Epoll instance. errno=%d ", errno);}
Detailed epoll mechanism, please see I have another article. Reprint of the epoll mechanism. An efficient and improved poll mechanism.

In fact looper in the entire message loop, the main is to implement MessageQueue in the sleep and wake mechanism.

 struct Epoll_event eventitems[epoll_max_events];    int eventcount = epoll_wait (MEPOLLFD, Eventitems, epoll_max_events, Timeoutmillis);    Acquire lock.    Mlock.lock ();    Check for poll error.        if (EventCount < 0) {if (errno = = eintr) {goto done;        } ALOGW ("Poll failed with an unexpected error, errno=%d", errno);        result = Alooper_poll_error;    Goto done;    }//Check for poll timeout. if (EventCount = = 0) {#if debug_poll_and_wake alogd ("%p ~ pollonce-timeout", this); #endif result = Alooper        _poll_timeout;    Goto done; }//Handle all events. #if debug_poll_and_wake alogd ("%p ~ pollonce-handling events from%d FDs", this, EventCount        ); #endif for (int i = 0; i < EventCount; i++) {int FD = EVENTITEMS[I].DATA.FD;        uint32_t epollevents = eventitems[i].events;            if (fd = = MWAKEREADPIPEFD) {if (Epollevents & Epollin) {awoken (); } else {ALOGW ("Ignoring unexpected epoll events 0x%x on Wake Read pipe.", epollevents);            }} else {ssize_t requestindex = Mrequests.indexofkey (FD);                if (requestindex >= 0) {int events = 0;                if (Epollevents & Epollin) events |= Alooper_event_input;                if (Epollevents & epollout) events |= Alooper_event_output;                if (Epollevents & Epollerr) events |= Alooper_event_error;                if (Epollevents & epollhup) events |= Alooper_event_hangup;            Pushresponse (Events, Mrequests.valueat (Requestindex)); } else {ALOGW ("Ignoring unexpected epoll events 0x%x on FD%d so is" "no longer            Registered. ", epollevents, FD);     }        }

From the above code can be seen, Looper pollonce mainly in the listening pipeline to see if there are events, at the same time under else can be implemented to their own definition of the file description of the listener role.

Get the next message in detail, or implement it in Messagequeue.java next () and return a MSG.

When should you wake up and wake up?

Take a look at the MessageQueue code. When a msg is added to the related queue. Called with the Nativewake method

static void Android_os_messagequeue_nativewake (jnienv* env, jobject obj, jint ptr) {    nativemessagequeue* Nativemessagequeue = Reinterpret_cast<nativemessagequeue*> (PTR);    return Nativemessagequeue->wake ();} void Looper::wake () {#if debug_poll_and_wake    alogd ("%p ~ Wake", this); #endif    ssize_t nwrite;    do {        nwrite = write (MWAKEWRITEPIPEFD, "W", 1), and while    (nwrite = = 1 && errno = = eintr);    if (nwrite! = 1) {        if (errno! = eagain) {            ALOGW ("Could not write wake signal, errno=%d", errno);}        }}    
The way to wake up is to write a ' W ' to MWAKEWIRTEPIPEFD, triggering the Epoll MWAKEREADPIPFDD wakeup process, and then get the next msg from the MessageQueue next method.

Final Message Next () {int pendingidlehandlercount =-1;//1 only during first iteration int Nextpolltimeo        Utmillis = 0; for (;;)            {if (Nextpolltimeoutmillis! = 0) {binder.flushpendingcommands ();            } nativepollonce (Mptr, Nextpolltimeoutmillis);                Synchronized (this) {if (mquiting) {return null;  }//Try to retrieve the next message.                Return if found.                Final Long now = Systemclock.uptimemillis ();                Message prevmsg = null;                Message msg = mmessages;  if (msg! = NULL && Msg.target = = null) {//stalled by a barrier.                    Find the next asynchronous message in the queue.                        do {prevmsg = msg;                    msg = Msg.next;                } while (msg! = null &&!msg.isasynchronous ());              }  if (msg! = null) {if (now < Msg.when) {//Next message are not ready.                        Set a timeout to wake up when it was ready.                    Nextpolltimeoutmillis = (int) math.min (Msg.when-now, Integer.max_value);                        } else {//Got a message.                        mblocked = false;                        if (prevmsg! = null) {Prevmsg.next = Msg.next;                        } else {mmessages = Msg.next;                        } msg.next = null;                        if (false) log.v ("MessageQueue", "returning message:" + msg);                        Msg.markinuse ();                    return msg;                    }} else {//No more messages.                Nextpolltimeoutmillis =-1; }


Looper monitoring and processing of file description descriptors:

Looper can listen to ordinary files, device files or sockets. Android itself has provided a set of mechanisms.

/** * Adds A new file descriptor to is polled by the Looper. * If the same file descriptor was previously added, it is replaced. * * "FD" is the file descriptor to be added. * "Ident" is a identifier for this event, which was returned from Alooper_pollonce (). * The identifier must be >= 0, or Alooper_poll_callback if providing a non-null CALLBACK.  * "Events" is the poll events to wake-on. Typically this is alooper_event_input. * "Callback" is the function of the "There" is a event on the file descriptor. * "Data" is a private data pointer to supply to the callback. * * There is both main uses of this function: * * (1) If ' callback ' is non-null and then this function would be called when th  ERE is * Data on the file descriptor.  It should execute any events it had pending, * appropriately reading from the file descriptor. The ' ident ' is a ignored in this case. * * (2) If "callback" is NULL, the ' ident ' would be a returned by Alooper_pollonce * While its file descriptor have data availAble, requiring the caller to take * care of processing it. * * Returns 1 if the file descriptor is added or-1 if an error occurred. * * This method can is called on any thread. * This method may be block briefly if it needs to wake the poll. */int ALOOPER_ADDFD (alooper* looper, int fd, int ident, int events, Alooper_callbackfunc callback, void* data);

Through the above interface, we can be in the native layer to achieve a variety of file monitoring and processing. In addition, Android also provides native layer of message and MessageHandler to handle the messaging mechanism.

These are all in the Looper.h file. We have time to study.

/** * Interface for a Looper message handler. * * The Looper holds a strong reference to the message handler whenever it had * a message to deliver to it.  Make sure to call looper::removemessages * To remove any pending messages destined for the handler so, the handler * C An IS destroyed. */class Messagehandler:public Virtual Refbase {protected:    virtual ~messagehandler () {}public:    /**     * Handles a message.     *    /virtual void handlemessage (const message& Message) = 0;};
It feels very similar to Java.







Android Framework Analysis---2 message mechanism native layer

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.