Android Native Looper 机制

本文摘自写给应用开发的 Android Framework 教程,完整教程请查阅:

yuandaimaahao.gitee.io/androidfram...

更为详细的视频教程与答疑服务,请联系微信 zzh0838

本文基于 aosp android-12.0.0_r26 分支讲解

一个简单的 main 函数执行完毕后,整个进程也就结束了,为了让一个进程长时间的运行下去,就需要无限循环加事件通知的机制,这类机制的伪代码描述如下:

cpp 复制代码
int main()
{
    while(true)
    {
        1. 线程进入休眠状态,等待通知;
        2. 其它地方给当前线程发送通知,线程从休眠中唤醒,读取通知,处理通知
        3. 进入下一个循环
    }

    return 0;
}

用一张图片表示就是这样:

不同的平台会采用不同的技术来实现该功能,Android 平台的这类机制称为 Looper,通过 eventfd + epoll 的方式来实现了休眠与唤醒的功能,这部分不清楚的同学请提前查阅前面的教程:

Android Looper 机制如下图所示:

接下来,我们就深入源码来解析 Android Native 层的 Looper 机制,关注的重点是:

  • 如何实现休眠与唤醒
  • 如何封装通知

Native Looper 的使用

Looper 相关的 API 如下:

cpp 复制代码
// 创建Looper对象
sp<Looper> mLooper = Looper::prepare(false /*allowNonCallbacks*/);

// 添加/删除要检测的文件描述符,可以添加一个回调对象,当对应事件发生时,调用回调对象中的回调函数
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
mLooper->removeFd(inputChannel->getFd());

// 进入休眠状态等待回调、超时或唤醒
mLooper->pollAll(timeoutMillis);

// 主动唤醒
mLooper->wake();

// 发送、删除消息
mLooper->sendMessage(handler, message);

首先我们从 frameworks/native/cmds/servicemanager/main.cpp 中截取 Looper 相关的代码,来看看 Looper 具体是怎么使用的:

cpp 复制代码
// frameworks/native/cmds/servicemanager/main.cpp

// 只摘取了 Looper 相关代码
int main(int argc, char** argv) {

    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);

    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);

    while(true) {
        // 进入休眠状态等待回调、超时或唤醒
        looper->pollAll(-1);
    }
}

// 绑定 binder 对应的 fd,当 binder fd 可读时,唤醒 epoll,调用回调函数
static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
    sp<BinderCallback> cb = sp<BinderCallback>::make();

    int binder_fd = -1;
    IPCThreadState::self()->setupPolling(&binder_fd);
    LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);

    int ret = looper->addFd(binder_fd,
                            Looper::POLL_CALLBACK,
                            Looper::EVENT_INPUT,
                            cb,
                            nullptr /*data*/);
    LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");

    return cb;
}

// 绑定一个 timerfd,每间隔 5 秒,epoll 唤醒一次,调用回调函数
static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) {
    sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager);

    int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/);
    LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno);

    itimerspec timespec {
        // 设置超时间隔
        .it_interval = {
            .tv_sec = 5,
            .tv_nsec = 0,
        },
        //第一次超时时间
        .it_value = {
            .tv_sec = 5,
            .tv_nsec = 0,
            },
    };

    int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, &timespec, nullptr);
    LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno);

    int addRes = looper->addFd(fdTimer,
                                Looper::POLL_CALLBACK,
                                Looper::EVENT_INPUT,
                                cb,
                                nullptr);
    LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper");
    return cb;
}

从源码总结一下 Native 层 Looper 的使用:

  • Looper::prepare 完成初始化工作
  • looper->addFd 添加需要关注的 fd (可选)
  • looper->pollAll 进入休眠状态等待回调、超时或唤醒
  • 其他线程调用 mLooper->sendMessage 发送消息,looper 线程从休眠中唤醒,处理收到的 message,调用回调函数

Native Looper 源码分析

Looper 的初始化

Looper 的初始化,主要任务是初始化一个 Looper 出来,初始化过程中,主要完成以下几个工作:

  • 构造一个 eventfd
  • 构建一个 epoll
  • 把 eventfd 放到 epoll 池中
  • 把 mRequests 中保存的 fd 放到 epoll 池中,初始化时, mRequests 为空,所以这步可以暂时忽略
cpp 复制代码
// system/core/libutils/Looper.cpp
sp<Looper> Looper::prepare(int opts) {
    bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
    // Looper 是一个线程特有数据,这里获取到当前线程的 Looper 对象
    sp<Looper> looper = Looper::getForThread();
    if (looper == nullptr) { // 没有就 new 一个,并保存起来
        // 调用构造函数初始化
        looper = new Looper(allowNonCallbacks);
        Looper::setForThread(looper);
    }
    if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
        ALOGW("Looper already prepared for this thread with a different value for the "
                "LOOPER_PREPARE_ALLOW_NON_CALLBACKS option.");
    }
    return looper;
}

// Looper 构造函数
// 构造一个 eventfd
// 构建一个 epoll
// 把 eventfd 放到 epoll 池中
// 把 mRequests 中保存的 fd 放到 epoll 池中,mRequests 哪里来的
Looper::Looper(bool allowNonCallbacks)
    : mAllowNonCallbacks(allowNonCallbacks),
      mSendingMessage(false),
      mPolling(false),
      mEpollRebuildRequired(false),
      mNextRequestSeq(0),
      mResponseIndex(0),
      mNextMessageUptime(LLONG_MAX) {
    // 构造一个 eventfd 并保存在 mWakeEventFd 中
    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

    AutoMutex _l(mLock);
    rebuildEpollLocked();
}

// epoll 相关的初始化
void Looper::rebuildEpollLocked() {
    // Close old epoll instance if we have one.
    if (mEpollFd >= 0) {
#if DEBUG_CALLBACKS
        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endif
        mEpollFd.reset();
    }

    // 构建一个 epoll fd 并保存在 mEpollFd 中
    mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
    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.get();
    // epoll 监听上面构建的 eventfd 的可读事件 
    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                        strerror(errno));


    // 监听 mRequests 中保存的 fd
    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.get(), 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));
        }
    }
}

addFd 的流程

addFd 主要工作是添加一个额外的 fd (eventfd 以外的)给 epoll 监听:

cpp 复制代码
//addFd 的使用示例
int ret = looper->addFd(binder_fd,
                            Looper::POLL_CALLBACK,
                            Looper::EVENT_INPUT,
                            cb,
                            nullptr /*data*/);

//system/core/libutils/Looper.cpp

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 = 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;
        request.data = data;
        if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1

        struct epoll_event eventItem;
        request.initEventItem(&eventItem);

        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) { // fd 未在 epoll 池中
            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
            if (epollResult < 0) {
                ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
                return -1;
            }
            // fd request 插入 mRequests
            mRequests.add(fd, request);
        } else { // fd 已在 epoll 池中
            int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
            if (epollResult < 0) {
                if (errno == ENOENT) {
                    epollResult = epoll_ctl(mEpollFd.get(), 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);
        }
    } 
    return 1;
}

addfd 主要完成了两项工作:

  • 根据插入的 fd 回调对象等参数构建一个 Request 对象
  • 把参数中的 fd 加入到 epoll 池中
  • 把新构建的 Request 对象插入到 mRequests 中

sendMessage

示例中没有 sendMessage,但是其他线程是可以通过 sendMessage 给 Looper 所在线程发送消息的:

cpp 复制代码
// system/core/libutils/Looper.cpp

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) {
    
    // 构建一个 MessageEnvelope 对象,根据时间顺序插入 Vector<MessageEnvelope> mMessageEnvelopes
    size_t i = 0;
    { 
        AutoMutex _l(mLock);

        size_t messageCount = mMessageEnvelopes.size();
        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
            i += 1;
        }

        MessageEnvelope messageEnvelope(uptime, handler, message);
        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);

        if (mSendingMessage) {
            return;
        }
    } 

    if (i == 0) { // 如果是插入头部位置,唤醒 epoll
        wake();
    }
}

// eventfd 写数据,唤醒 epoll
void Looper::wake() {
    uint64_t inc = 1;
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
                             mWakeEventFd.get(), nWrite, strerror(errno));
        }
    }
}

sendMessage 主要完成了两项工作:

  • 将 message 截止时间 回调对象 三个参数包装为 MessageEnvelope 对象,并插入 mMessageEnvelopes
  • 调用 wake 函数,给 eventfd 写数据,唤醒 epoll

pollAll

cpp 复制代码
// 使用示例
while(true) {
    // 进入休眠状态等待回调、超时或唤醒
    looper->pollAll(-1);
}


// system/core/libutils/Looper.cpp
inline int pollAll(int timeoutMillis) {
    return pollAll(timeoutMillis, nullptr, nullptr, nullptr);
}

int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    if (timeoutMillis <= 0) {
        int result;
        do { 
            //走这个路径
            result = pollOnce(timeoutMillis, outFd, outEvents, outData);
        } while (result == POLL_CALLBACK);
        return result;
    } else {
        nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
                + milliseconds_to_nanoseconds(timeoutMillis);

        for (;;) {
            int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
            if (result != POLL_CALLBACK) {
                return result;
            }

            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
            if (timeoutMillis == 0) {
                return POLL_TIMEOUT;
            }
        }
    }
}

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        // 刚开始  mResponses 为空,暂时不管
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;

                if (outFd != nullptr) *outFd = fd;
                if (outEvents != nullptr) *outEvents = events;
                if (outData != nullptr) *outData = data;
                return ident;
            }
        }

        if (result != 0) {
            if (outFd != nullptr) *outFd = 0;
            if (outEvents != nullptr) *outEvents = 0;
            if (outData != nullptr) *outData = nullptr;
            return result;
        }

        result = pollInner(timeoutMillis);
    }
}

int Looper::pollInner(int timeoutMillis) {

    //......

    // Poll.
    int result = POLL_WAKE;
    mResponses.clear(); //上面已经处理了,就 clear 掉
    mResponseIndex = 0;

    // We are about to idle.
    mPolling = true;

    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    
    // 休眠 等待事件来临
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // No longer idling.
    mPolling = false;

    // Acquire lock.
    mLock.lock();

    // ......

    // Check for poll error.
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
        result = POLL_ERROR;
        goto Done;
    }

    // Check for poll timeout.
    if (eventCount == 0) {
        result = POLL_TIMEOUT;
        goto Done;
    }


    //读出发生的事件,将发生的事件包装为 Response 对象,并保存到 mResponses 中
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd.get()) {
            if (epollEvents & EPOLLIN) {
                awoken(); // 把 eventfd 的数据读掉
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {
            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;
                // 收到的事件会包装成 Response 对象,并保存到 Vector<Response> 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) {
            // Remove the envelope from the list.
            // We keep a strong reference to the handler until the call to handleMessage
            // finishes.  Then we drop it so that the handler can be deleted *before*
            // we reacquire our lock.
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();
                handler->handleMessage(message);
            } // release handler

            mLock.lock();
            mSendingMessage = false;
            result = POLL_CALLBACK;
        } else {
            // The last message left at the head of the queue determines the next wakeup time.
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }

    // Release lock.
    mLock.unlock();

    // 处理 Response,并回调 addfd 时传入的回调函数
    // Invoke all response callbacks.
    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;
}

pollAll 涉及的代码比较多,但是核心功能都聚集于 pollInner 函数中:

  • 调用 epoll_wait 进入休眠状态
  • 当 IO 事件到来时,读取事件,将发生的事件包装为 Response 对象,并保存到 mResponses 中
  • 处理收到的 message,并调用回调函数
  • 处理所有的 Response,并回调 addfd 时传入的回调函数

参考资料

关于

我叫阿豪,2015 年本科毕业于国防科学技术大学指挥信息系统专业,毕业后从事信息化装备的研发工作,主要研究方向是 Android Framework 与 Linux Kernel。

如果你对 Android Framework 感兴趣或者正在学习 Android Framework,可以关注我的微信公众号和抖音,我会持续分享我的学习经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。

相关推荐
烬奇小云2 小时前
认识一下Unicorn
android·python·安全·系统安全
顾北川_野15 小时前
Android 进入浏览器下载应用,下载的是bin文件无法安装,应为apk文件
android
CYRUS STUDIO15 小时前
Android 下内联汇编,Android Studio 汇编开发
android·汇编·arm开发·android studio·arm
右手吉他15 小时前
Android ANR分析总结
android
PenguinLetsGo17 小时前
关于 Android15 GKI2407R40 导致梆梆加固软件崩溃
android·linux
杨武博19 小时前
音频格式转换
android·音视频
音视频牛哥21 小时前
Android音视频直播低延迟探究之:WLAN低延迟模式
android·音视频·实时音视频·大牛直播sdk·rtsp播放器·rtmp播放器·android rtmp
ChangYan.21 小时前
CondaError: Run ‘conda init‘ before ‘conda activate‘解决办法
android·conda
二流小码农21 小时前
鸿蒙开发:ForEach中为什么键值生成函数很重要
android·ios·harmonyos
夏非夏1 天前
Android 生成并加载PDF文件
android