Android7. 0 messagequeue details

The message processing mechanism in Android relies heavily on handler. Each handler has a corresponding looper, which is used to continuously fetch messages from the corresponding messagequeue for processing.

For a long time, I think messagequeue should be an abstraction of the Java layer. However, in fact, the main part of messagequeue is in the native layer. I am not familiar with the work of messagequeue in the native layer. I take this opportunity to analyze it.

1、 Creation of messagequeue

When looper needs to be used, we will call Looper's prepare function:

1 NativeMessageQueue

Let's look at the constructor of messagequeue:

The native function is called in the constructor of messagequeue. Let's take a look at Android_ os_ MessageQueue. Implementation in CPP:

We follow up the constructor of nativemessagequeue:

From the code point of view, both the native layer and the Java layer have looper objects, which should operate messagequeue. Messagequeue has its own storage structure in Java layer and native layer, which stores messages in Java layer and native layer respectively.

2 looper of native layer

Let's look at the constructor of the native layer looper:

In the native layer, when the looper in the messagequeue is initialized, the rebuildepolllocked function is also called. Let's follow up:

From the looper of the native layer, we know that the native layer relies on epoll to drive event processing. Here we first retain the general image, and then analyze it in detail.

2、 Using messagequeue

1 write message in Android, you can write messages to messagequeue either in the Java layer or in the native layer. Let's take a look at the corresponding operation flow.

1.1 Java layer writes messages Java layer writes messages to messagequeue, which depends on enqueuemessage function:

The above code is relatively simple. It mainly inserts the newly added message into the original queue according to the execution time, and then calls the nativeawake function according to the situation.

Let's follow up on nativeawake:

When initializing the looper of the native layer, we mentioned that the looper of the native layer will use epoll to drive events, and the constructed epoll handle listens to mwakeeventfd. In fact, when fetching data from the messagequeue, if no data arrives, epoll will be used to wait; Therefore, when the Java layer writes a message, it will wake up the waiting messagequeue. This problem will be analyzed again later when extracting messages from messagequeue.

1.2 message writing in the native layer message writing in the native layer depends on the SendMessage function of the native layer looper:

The above is the main process of adding messages to the messagequeue. Next, let's take a look at the process of extracting messages from the messagequeue.

2. Extract message when the loop object of the Java layer calls the loop function, the messagequeue is used to extract the message:

Here, let's take a look at the next function of messagequeue:

The whole process of extracting messages is roughly as shown in the figure above. You can see that in the Java layer, in addition to fetching messages from the messagequeue, looper also executes the functions defined by idlehandler during the idle period of the queue.

2.1 the only doubt about nativepollonce now is how nativepollonce handles native layer data. Let's look at the corresponding native function:

Take a look at the pollonce function of loop in the native layer:

Follow up the pollinner function:

Done:

To be honest, the code of the native layer is written in a mess, and the function has many functions. As shown in the figure above, epoll is used in nativepollonce to monitor whether there is data coming, and then process the native message and native response.

Finally, let's see how to add request in the native layer.

3. Add a monitoring request. The native layer adds a request that depends on the looper's interface addfd:

Combined with the above operation of polling queue in the native layer, we can roughly know that the purpose of addfd is to let the looper of the native layer monitor whether a specified event occurs on the newly added FD. If the specified event occurs, the callback function and parameters are used to construct the corresponding response. When the looper of the native layer processes the response, it can execute the corresponding callback function.

Look at the actual code:

The processing of join monitoring requests has been analyzed when the pollinner function is introduced above, and will not be repeated here.

3、 Summary

1. Process summary

The whole process of messagequeue includes Java part and native part. It can be seen from the figure that the proportion of native layer is still large. Let's recall the corresponding processing flow of the whole messagequeue in combination with the above figure: 1. When the looper object is created in the Java layer, the messagequeue of the Java layer will be created; When the messagequeue of the Java layer is initialized, the messagequeue of the native layer will be created using the native function.

2. After the messagequeue of the native layer is initialized, the corresponding native looper object will be created. When the native object is initialized, the corresponding epollfd and wakeeventfd are created. Among them, epollfd will be used as the listening handle of epoll. Initially, epollfd only listens to wakeeventfd.

3. The red line in the figure shows the flow direction of processing logic when looper fetches messages from messagequeue. 3.1 when looper of Java layer starts to loop, first call native looper through JNI function to perform pollonce operation.

3.2 after the native looper starts running, wait for epollfd to wake up. When epollfd waits for a timeout or the listening handle has an event, the native looper can start processing the event.

3.3 in the native layer, the native looper will first process the messages in the native messagequeue, and then call the callback function corresponding to the response.

3.4 in this cycle, the message of messagequeue in Java layer is processed only after the event of native layer is processed. If there is no message to be processed in messagequeue and idlehandler exists in messagequeue, the processing function defined by idlehandler will be called.

The blue part in the figure shows the corresponding function call: in the Java layer: use the addidlehandler of messagequeue to add idlehandler for messagequeue; Using enqueuemessage of messagequeue, messages can be added to messagequeue; If necessary, the native function will be used to write a message to wakeeventfd of the native layer to wake up epollfd.

In the native layer: using looper: SendMessage, you can add messages to the native messagequeue; Similarly, a message will be written to wakeeventfd of the native layer to wake up epollfd; Using looper: addfd, you can register a listening request with native looper. The listening request includes FD to listen, events to listen and corresponding callback functions. FD corresponding to the listening request will become the object of epollfd listening. When the monitored FD has a corresponding event, epollfd will be awakened. At this time, a corresponding response will be generated and added to the response list for processing. Once the response is processed, the corresponding callback function is called.

2. Note: messagequeue has its own storage structure in Java layer and native layer, and messages can be added respectively. From the perspective of processing logic, the message of the native layer will be processed first, then the response generated by the native layer, and finally the message of the Java layer.

The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support programming tips.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>