hi,同學們大家好!
這些天有學員再群里問起了Handler中有個資料監聽相關問題,學員有的認為Handler資料傳遞是靠流傳遞,誤認為是epoll中監聽的fd進行傳遞的,這個其實有必要更正這個學員的一個觀點:
1、handler的資料傳遞完全是在自己行程中,所以完全不需要什么fd的流來傳遞,就相當于一個全域變數一樣,你需要通過什么socket什么來傳遞資料么,你直接記憶體變數就可以訪問到
2、那么學員就有疑問,那么handler looper說是基于epoll檢測fd方式,epoll只是來監聽回呼通知作用,那么它監聽的fd到底是個什么東西,如果不是流傳遞
這里我們就來揭開handler中looper的epoll監聽的fd到底是什么型別的:
其實在我們android跨行程通訊實戰課程中原來也講解過Looper,其實Looper在java層就是一個簡單的包裝,真正干活在Loop.cpp中,而且這個Looper.cpp不在framework路徑下面,
其實實在system/core路徑下面:
test@test-Lenovo:~/xiaomi5/system/core$ find -name Loop*
./libutils/Looper.cpp
./libutils/Looper_test.cpp
./libutils/include/utils/Looper.h
下面我們從Loop.java開始一步步追:
public static void loop() {
//省略部分
for (;;) {
Message msg = queue.next(); // might block
//省略部分
}
}
可以看出loop是一個死回圈在呼叫queue.next(),這樣來一直源源不斷取訊息:
來看看queue.next():
frameworks/base/core/java/android/os/MessageQueue.java
Message next() {
//省略部分
for (;;) {
nativePollOnce(ptr, nextPollTimeoutMillis);
//省略部分
}
}
這里呼叫是nativePollOnce,是一個native方法,即到達了native,來看看nativePollOnce方法:
frameworks/base/core/jni/android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
這里呼叫是NativeMessageQueue的pollOnce,NativeMessageQueue本身也在android_os_MessageQueue類中,這里來看一下:
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollEnv = env;
mPollObj = pollObj;
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL;
if (mExceptionObj) {
env->Throw(mExceptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}
這里大家看一下呼叫了是 mLooper->pollOnce(timeoutMillis),看到了開頭說的Loop.cpp,它是在system/core/libutils目錄:
system/core/libutils/include/utils/Looper.h
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
}
這里呼叫是int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData)方法:
nt Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
//省略
result = pollInner(timeoutMillis);
}
}
這里又呼叫了pollInner:
int Looper::pollInner(int timeoutMillis) {
//省略部分
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//省略部分
return result;
}
這里大家是不是看到一個非常非常熟悉的epoll_wait,即它就是沒有訊息時候阻塞,有訊息時候喚醒的核心,也是handler是epoll的關鍵體現就是它,那么問題是它到達監聽是哪個fd的變化呢?
其實本質上喚醒的fd是mWakeEventFd,而這個又是由誰進行賦值呢?只要找到他的賦值就可以看出他是個什么樣的fd:
Looper::Looper(bool allowNonCallbacks)
: mAllowNonCallbacks(allowNonCallbacks),
mSendingMessage(false),
mPolling(false),
mEpollRebuildRequired(false),
mNextRequestSeq(0),
mResponseIndex(0),
mNextMessageUptime(LLONG_MAX) {
mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));//這里就是對mWakeEventFd進行賦值
LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));
AutoMutex _l(mLock);
rebuildEpollLocked();
}
可以看出mWakeEventFd本質是通過eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC),那么eventfd又是個什么呢?
這里我們Ubuntu使用man來看看它是什么:
VENTFD(2) Linux Programmer's Manual EVENTFD(2)
NAME
eventfd - create a file descriptor for event notification
SYNOPSIS
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
DESCRIPTION
eventfd() creates an "eventfd object" that can be used as an event wait/notify mechanism by user-space applications, and by the kernel to notify user-space applications of events. The ob‐
ject contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the kernel. This counter is initialized with the value specified in the argument initval.
As its return value, eventfd() returns a new file descriptor that can be used to refer to the eventfd object.
The following values may be bitwise ORed in flags to change the behavior of eventfd():
EFD_CLOEXEC (since Linux 2.6.27)
Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor. See the description of the O_CLOEXEC flag in open(2) for reasons why this may be useful.
EFD_NONBLOCK (since Linux 2.6.27)
Set the O_NONBLOCK file status flag on the open file description (see open(2)) referred to by the new file descriptor. Using this flag saves extra calls to fcntl(2) to achieve the
same result.
EFD_SEMAPHORE (since Linux 2.6.30)
Provide semaphore-like semantics for reads from the new file descriptor. See below.
In Linux up to version 2.6.26, the flags argument is unused, and must be specified as zero.
The following operations can be performed on the file descriptor returned by eventfd():
read(2)
Each successful read(2) returns an 8-byte integer. A read(2) fails with the error EINVAL if the size of the supplied buffer is less than 8 bytes.
The value returned by read(2) is in host byte order—that is, the native byte order for integers on the host machine.
The semantics of read(2) depend on whether the eventfd counter currently has a nonzero value and whether the EFD_SEMAPHORE flag was specified when creating the eventfd file descrip‐
tor:
* If EFD_SEMAPHORE was not specified and the eventfd counter has a nonzero value, then a read(2) returns 8 bytes containing that value, and the counter's value is reset to zero.
* If EFD_SEMAPHORE was specified and the eventfd counter has a nonzero value, then a read(2) returns 8 bytes containing the value 1, and the counter's value is decremented by 1.
* If the eventfd counter is zero at the time of the call to read(2), then the call either blocks until the counter becomes nonzero (at which time, the read(2) proceeds as described
above) or fails with the error EAGAIN if the file descriptor has been made nonblocking.
write(2)
A write(2) call adds the 8-byte integer value supplied in its buffer to the counter. The maximum value that may be stored in the counter is the largest unsigned 64-bit value minus 1
(i.e., 0xfffffffffffffffe). If the addition would cause the counter's value to exceed the maximum, then the write(2) either blocks until a read(2) is performed on the file descrip‐
tor, or fails with the error EAGAIN if the file descriptor has been made nonblocking.
A write(2) fails with the error EINVAL if the size of the supplied buffer is less than 8 bytes, or if an attempt is made to write the value 0xffffffffffffffff.
大致就是說:
eventfd - create a file descriptor for event notification
即專門用來創建事件通知檔案描述符fd的一個方法,即他僅僅作用就是通知事件這種,不是平常見到的socket fd那種
好了到這里基本上解密了handler的fd到底是什么fd,它既不是 大家想的那種socket流fd,管道流fd,就是linux上專門系統方法evnetfd創建的事件通知fd
如果需要學習更多framework只是和視頻可以b站關注:千里馬學框架,購買課程最好加入422901085群里找千里馬要優惠和答疑
課程答疑和新課資訊:QQ交流群:422901085進行課程討論,加群主qq享受 優惠
FrameWork入門課視頻鏈接:https://edu.csdn.net/course/detail/30298
FrameWork實戰課1視頻鏈接:https://edu.csdn.net/course/detail/30275
FrameWork跨行程通信視頻鏈接:https://edu.csdn.net/course/detail/35911
專題博客系列:
Android 8.1 zygote 啟動程序原始碼
Android Framework實戰視頻–Zygote的fork行程篇
Android Framework實戰視頻–SystemServer啟動篇
Android Framework實戰視頻–SystemServer啟動FallbackHome篇
Android Framework實戰視頻–FallbackHome行程啟動及Activity啟動篇
Android Framework實戰視頻–FallbackHome結束啟動Launcher篇
Android Framework實戰視頻–BootAnimation的啟動原始碼分析(Android8.1)
Android Framework實戰視頻–init行程的bootanimation啟動原始碼分析(補充Android 10部分的BootAnimation的啟動原始碼分析)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/398708.html
標籤:其他
