Android Looper(native)

1,815 阅读8分钟

looper循环器,loop环,poll调查。

Android Looper是使用Linux的IO事件处理机制epoll实现的。

Looper框架以so的形式提供给Android系统使用,源代码位于下面的路径:

system/core/libutils/include/utils/Looper.h system/core/libutils/Looper.cpp

Android的Looper框架,包括几个组件,分别是:Message、MessageHandler、Looper。Message是消息实体,MessageHandler是处理消息的回调,Looper是消息机制的核心。

Android的Java层的消息机制就是通过调用这个库实现的,所以Android的消息机制实际是使用Linux的IO事件处理机制epoll实现的。

使用方法

创建Looper对象

Looper mLooper = new Looper(false);

添加/删除要检测的文件描述符

mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); mLooper->removeFd(inputChannel->getFd());

等待回调、超时或唤醒

mLooper->pollOnce(timeoutMillis);

主动唤醒

mLooper->wake();

发送、删除消息

mLooper->sendMessage(handler, message);

Looper机制主逻辑

Loop构造方法

system/core/libutils/Looper.cpp

Looper::Looper(bool allowNonCallbacks) :
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
    // 创建一个文件句柄,用于唤醒
    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    // 
    rebuildEpollLocked();
}

void Looper::rebuildEpollLocked() {
    // 分配/创建 一个新的epoll实例
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(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 = mWakeEventFd;
    // 添加用于唤醒的文件句柄mWakeEventFd到epoll
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);

    // 添加所有request.fd到epoll
    for (size_t i = 0; i < mRequests.size(); i++) {
        const Request& request = mRequests.valueAt(i);
        struct epoll_event eventItem;
        request.initEventItem(&eventItem);

        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
        if (epollResult < 0) {
            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
                  request.fd, strerror(errno));
        }
    }
}

添加删除要检测的文件描述符

int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
    if (!callback.get()) {
        if (! mAllowNonCallbacks) {
            ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
            return -1;
        }

        if (ident < 0) {
            ALOGE("Invalid attempt to set NULL callback with ident < 0.");
            return -1;
        }
    } else {
        // 一般会走这里,ident=-2,callback不为空
        ident = POLL_CALLBACK;
    }

    { // acquire lock
        AutoMutex _l(mLock);
        // 根据传参,创建Request对象并赋值
        Request request;
        request.fd = fd;
        request.ident = ident;
        request.events = events;
        request.seq = mNextRequestSeq++;
        request.callback = callback;    // 这个回调需要留意,当这个fd上有事件触发时,就会调用这个callback
        request.data = data;
        if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1

        struct epoll_event eventItem;
        // 根据request参数初始化eventItem
        request.initEventItem(&eventItem);
        // 查看本次创建的request是否已经在mRequest中存在
        ssize_t requestIndex = mRequests.indexOfKey(fd);
        // 小于0表示不存在,然后将文件句柄加入epoll,并把request加入mRequest
        if (requestIndex < 0) {
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
            if (epollResult < 0) {
                ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
                return -1;
            }
            mRequests.add(fd, request);
        } else {
            // 大于等于0说明已经存在,修改epoll中的这个文件句柄,然后更新mRequest中的这个request
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
            if (epollResult < 0) {
                if (errno == ENOENT) {
                    // 修改失败,进行添加操作
                    epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
                    if (epollResult < 0) {
                        ALOGE("Error modifying or adding epoll events for fd %d: %s",
                                fd, strerror(errno));
                        return -1;
                    }
                    scheduleEpollRebuildLocked();
                } else {
                    ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
                    return -1;
                }
            }
            mRequests.replaceValueAt(requestIndex, request);
        }
    } // release lock
    return 1;
}

这个需要留意传入的参数LooperCallback,当fd上有事件触发的时候,这个callback就会被调用。

int Looper::removeFd(int fd, int seq) {
    { // acquire lock
        AutoMutex _l(mLock);
        // 检查fd是否在mRequest中,如果不存在,无需删除,直接返回
        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) {
            return 0;
        }

        // 如果设置了seq参数,需要检查和要删除的是否一致。不设置的话,会使用默认值-1
        if (seq != -1 && mRequests.valueAt(requestIndex).seq != seq) {
            return 0;
        }

        // 从mRequests中删除这个句柄的request
        mRequests.removeItemsAt(requestIndex);
        // 从epoll中删除这个句柄
        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
        if (epollResult < 0) {
            if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
                scheduleEpollRebuildLocked();
            } else {
                scheduleEpollRebuildLocked();
                return -1;
            }
        }
    } // release lock
    return 1;
}

等待回调、超时或唤醒

inline int pollOnce(int timeoutMillis) {
    return pollOnce(timeoutMillis, NULL, NULL, NULL);
}

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        result = pollInner(timeoutMillis);
    }
}

int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif

    // 计算调整timeout时间
    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
        if (messageTimeoutMillis >= 0
                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
            timeoutMillis = messageTimeoutMillis;
        }
    }

    // Poll.
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;

    // 设置标志变量mPolling,标志进入idle状态
    mPolling = true;

    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    // 进入等待状态
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // 设置标志变量mPolling,标志退出idle状态
    mPolling = false;

    // 如果返回的事件数量小于0,说明发生了错误,直接返回
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
        result = POLL_ERROR;
        goto Done;
    }

    // 如果返回的事件数量是0,说明超时了
    if (eventCount == 0) {
        result = POLL_TIMEOUT;
        goto Done;
    }

    for (int i = 0; i < eventCount; i++) {
        // 取得发生事件的文件句柄fd
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        // 如果文件句柄是用于唤醒epoll的mWakeEventFd
        if (fd == mWakeEventFd) {
            // 没有啥实际逻辑
            if (epollEvents & EPOLLIN) {
                awoken();
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {
            // else说明是request fd 事件返回了
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
                // 将返回的事件放入向量mResponses
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }
Done: ;

    // 处理message
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        // 如果消息的预计被处理时间已经到了
        if (messageEnvelope.uptime <= now) {
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();
                // 调用handler的回调方法handleMessage()处理消息
                handler->handleMessage(message);
            } // release handler

            mLock.lock();
            mSendingMessage = false;
            result = POLL_CALLBACK;
        // 如果消息的预计被处理时间还没到,就用这个消息的实际设置mNextMessageUptime(下一次唤醒epoll的时间),然后退出消息处理
        } else {
            // 消息队列的第一个消息决定epoll/Looper的唤醒时间
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }

    // Release lock.
    mLock.unlock();

    // 处理response,调用发生事件fd的callback
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
            // Invoke the callback.  Note that the file descriptor may be closed by
            // the callback (and potentially even reused) before the function returns so
            // we need to be a little careful when removing the file descriptor afterwards.
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);
            }

            // Clear the callback reference in the response structure promptly because we
            // will not clear the response vector itself until the next poll.
            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }
    return result;
}

这里需要关注epoll_wait的超时时间,这个时间不一定是方法传入参数的时间,也可以是下一个消息预计被处理的时间,哪个小就设置为超时时间。

主动唤醒

void Looper::wake() {
    uint64_t inc = 1;
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
}

通过向epoll监听的唤醒文件句柄mWakeEventFd里面写入1。

主动唤醒是应用程序发起的,超时和回调都是kernel发起的。

添加、删除消息

void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    sendMessageAtTime(now, handler, message);
}

void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
        const Message& message) {
    size_t i = 0;
    { // acquire lock
        AutoMutex _l(mLock);
        // mMessageEnvelopes是存放消息的数据结构,是一个向量容器
        size_t messageCount = mMessageEnvelopes.size();
        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
            i += 1;
        }
        // 创建一个messageEnvelope
        MessageEnvelope messageEnvelope(uptime, handler, message);
        // 按照时间顺序(由小到大)添加到mMessageEnvelopes
        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
    } // release lock

    // 如果在消息队里的开始的位置添加了一个消息,就唤醒Looper loop
    // 唤醒之后pollInner()方法的epoll_wait行会返回并继续执行,消息的处理逻辑就在后面
    if (i == 0) {
        wake();
    }
}

其它重要方法

sp<Looper> Looper::prepare(int opts) {
    bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
    sp<Looper> looper = Looper::getForThread();
    // 如果looper没有创建过,就创建一个;否则,直接返回
    if (looper == NULL) {
        looper = new Looper(allowNonCallbacks);
        Looper::setForThread(looper);
    }
    return looper;
}

void Looper::setForThread(const sp<Looper>& looper) {
    sp<Looper> old = getForThread(); // also has side-effect of initializing TLS

    if (looper != NULL) {
        looper->incStrong((void*)threadDestructor);
    }
    // 设置gTLSKey对应的looper
    pthread_setspecific(gTLSKey, looper.get());

    if (old != NULL) {
        old->decStrong((void*)threadDestructor);
    }
}

sp<Looper> Looper::getForThread() {
    // 同一个线程中,pthread_once只执行一次,执行initTLSKey()方法得到gTLSKey(thread looper static key)
    int result = pthread_once(& gTLSOnce, initTLSKey);
    LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
    // 取得gTLSKey对应的Looper
    return (Looper*)pthread_getspecific(gTLSKey);
}

void Looper::initTLSKey() {
    int result = pthread_key_create(& gTLSKey, threadDestructor);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
}

通过pthread_once和pthread_key_create保证一个线程中只生成一个thread looper static key(static);通过pthread_setspecific/pthread_getspecific来设置和取得thread looper static key对应的looper。即通过这里,可以保证一个线程只创建一个looper,并且looper和线程是绑定的,可以通过thread looper static key取得线程的looper。

涉及的数据结构

Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock

// Locked list of file descriptor monitoring requests.
KeyedVector<int, Request> mRequests;  // guarded by mLock

// This state is only used privately by pollOnce and does not require a lock since
// it runs on a single thread.
Vector<Response> mResponses;

Android Lopper涉及三个用来存储数据,都是向量。mRequests用来存储所有加入epoll的请求。mResponses存储所有epoll返回的事件。mMessageEnvelopes。

涉及的知识点

线程数据共享

pthread_getpecific和pthread_setspecific提供了在同一个线程中不同函数间共享数据即线程存储的一种方法。具体用法为:

  1. 调用pthread_key_create()来创建一个类型为pthread_key_t类型的变量

该函数有两个参数,第一个参数就是声明的pthread_key_t变量,第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。该函数指针可以设成NULL,这样系统将调用默认的清理函数。

  1. 调用pthread_setspcific()

当线程中需要存储特殊值的时候调用该函数,该函数有两个参数,第一个为前面声明的pthread_key_t变量,第二个为void*变量,用来存储任何类型的值。

  1. 如果需要取出所存储的值,调用pthread_getspecific()

该函数的参数为前面提到的pthread_key_t变量,该函数返回void*类型的值。

pthread_once

在多线程环境中,有些事仅需要执行一次。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库时,就不能在main里面初始化了,你可以用静态初始化,但使用一次初始化(pthread_once)会比较容易些。

int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));

功能:本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。 在多线程编程环境下,尽管pthread_once()调用会出现在多个线程中,init_routine()函数仅执行一次,究竟在哪个线程中执行是不定的,是由内核调度来决定。

epoll

最重要的知识点是Linux的IO事件处理机制epoll(暂缺)。