Android Framework Analysis---Messaging mechanism native layer

Source: Internet
Author: User
Tags epoll

In the Android messaging mechanism, it not only provides a message loop for Java that application development uses. In fact, the Java mechanism ultimately depends on native to achieve. The native not only provides a set of messaging and processing mechanisms, but also provides a listener mechanism for the I/O time of the custom file descriptor. Let's analyze it from the specific code below.

Key classes for the native layer:

Looper.cpp. The hibernate and wake mechanisms for pollonce and wake are provided in this class. It also creates a pipeline in the constructor and joins the epoll mechanism to listen for its state 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);}
Specific epoll mechanism, please refer to my other article, reproduced the Epoll mechanism. An efficient and improved poll mechanism.

In fact looper in the entire message loop, mainly to implement the MessageQueue 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);     }        }

As can be seen from the above code, Looper's pollonce mainly in the listening pipeline to see if there is an event, while under else can be implemented on the custom file descriptor monitoring role.

Specifically get the next message, or the next () Messagequeue.java to implement and return a MSG.

When should you wake up and wake up?

See the code for MessageQueue, when adding a msg to the relevant 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 descriptors:

Looper can listen to normal 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, you 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 similar to Java.





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.