Android UI系统工作流程(二)

998 阅读8分钟

Android UI系统2

接上文:juejin.cn/post/700365…

我们在Jave层分析知道了,ViewRootImpl作为整个视图树的大管家,在requestLayout的时候,实际是往Choreographer中post一个Callback,而这个过程中因为requestLayout的发起方本来就是在主线程中,会调用到Choreographer的scheduleVsyncLocked,这其中实际是调用FrameDisplayEventReceiver的scheduleVsync,最终实现如下:

    public void scheduleVsync() {
        // ...
      nativeScheduleVsync(mReceiverPtr);
    }

nativeScheduleVsync的实际实现是:android_view_DisplayEventReceiver:

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
    status_t status = receiver->scheduleVsync();
    // ...
}

NativeDisplayEventReceiver继承自DisplayEventDispatcher,scheduleVsync的具体实现:

status_t DisplayEventDispatcher::scheduleVsync() {
    if (!mWaitingForVsync) {
        // ...
        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
                  ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
        }
				// 通过DisplayEventReceiver请求下一次Vsync
        status_t status = mReceiver.requestNextVsync();
        // ...
    }
    // ...
}

而requestNextVsync的核心就是调用IDisplayEventConnection的requestNextVsync方法:

status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != nullptr) {
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    // mEventConnection是在DisplayEventReceiver初始化的时候就构造完成的
    return NO_INIT;
}


分析到这里,其实都没什么内容,只知道Java层的scheduleVsync最终是调用到了IDisplayEventConnection的requestNextVsync,请求下一次Vsync信号到来的时候,可以做一些什么事儿。 接着往下看,需要知道mEventConnection是什么,在DisplayEventReceiver的构造函数中:

DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource,
                                           ISurfaceComposer::ConfigChanged configChanged) {
  	// 通过ComposerService获取到ISurfaceComposer的引用
  	// 实际上就是获取SurfaceFlinger进程的Binder句柄
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr) {
        // 通过SurfaceFlinger的binder句柄,调用SurfaceFlinger进程的createDisplayEventConnection。
        // 创建一个DisplayEventReceiver对象
        mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged);
        if (mEventConnection != nullptr) {
            // mDataChannel是应用进程与SurfaceFlinger进程数据交互的通道
            mDataChannel = std::make_unique<gui::BitTube>();
            // 下文再做分析
            mEventConnection->stealReceiveChannel(mDataChannel.get());
        }
    }
}

上面提到了BitTube这个class实际上就是存放了两个文件描述符:native/include/private/gui

private:
    // ...
    mutable base::unique_fd mSendFd;
    mutable base::unique_fd mReceiveFd;
    // ...
};

在BitTube的构造函数中,调用到了BitTube::init函数对这两个描述符初始化:

void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[2];
    // 在Linux中,可以通过socketpair创建一对套接字进行IPC。
    // 创建完成的两个套接字均能用来读写
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        // 省略一些设置socket套接字句柄的代码
        // 将两个套接字句柄分别赋值给两个文件描述符
        mReceiveFd.reset(sockets[0]);
        mSendFd.reset(sockets[1]);
    } else {
        mReceiveFd.reset();
        ALOGE("BitTube: pipe creation failed (%s)", strerror(errno));
    }
}

mSendFd和mReceiveFd是阻塞性质的,而设置的Buffer的size是4KB,举个例子,当A进程(线程)拿了mReceiveFd但是Buffer当中没有内容的时候,就会epoll阻塞,当B进程(线程)通过mSendFd往Buffer中写了数据的时候,那么A进程(线程)就会被唤醒,通过mRecerveFd读到B进程写入的内容。

继续回到createDisplayEventConnection,注意,下面这里是在SurfaceFlinger服务进程中进行的。

sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
        ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) {
    // 这里其实默认就是eVsyncSourceSurfaceFlinger
    // 具体可以看Choreographer的构造
    const auto& handle =
            vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
    return mScheduler->createDisplayEventConnection(handle, configChanged);
}

mScheduler->createDisplayEventConnection调用到

createConnectionInternal(mConnections[handle].thread.get(), configChanged);
-->
eventThread->createEventConnection([&] { resync(); }, configChanged);
-->
// 创建一个EventThreadConnection对象,所以EventConnection实际是EventThreadConnection对象
// 在EventThreadConnection的构造方法中,会创建一个mChannel对象(实际上就是一个BitTube对象)
new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
                                     configChanged);
// 那么上文中mEventConnection->requestNextVsync实际就是EventThreadConnection的相关方法:
mEventThread->requestNextVsync(this);
// mEventThread是EventThread对象,其requestNextVsync中,核心是:
// 将connection的vsyncRequest设置为Single类型,记住这一点,下文会再次提到
connection->vsyncRequest = VSyncRequest::Single;

在EventThreadConnection中,onFirstRef如下(RefBase::onFirstRef可以理解为第一次产生引用关系的时候会被调用):

void EventThreadConnection::onFirstRef() {
    mEventThread->registerDisplayEventConnection(this);
}
-->
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
    std::lock_guard<std::mutex> lock(mMutex);
		// ...
    // 将创建的EventThread添加到mDisplayEventConnections容器中
    mDisplayEventConnections.push_back(connection);
    // 通知因为condition_variable mCondition.wait而处于阻塞态的线程
    mCondition.notify_all();
    return NO_ERROR;
}

到这里我们先做一个小结,Choreographer请求下一次Vsync信号的最终通过EventThread的requestNextVsync方法,在调用的过程中会创建EventThreadConnection对象,代表和EventThread的连接对象,然后将EventThreadConnection的vsyncRequest置为Single类型。

来看下EventThread的创建:

在SurfaceFlinger进程启动以后,会调用SurfaceFlinger::init进行初始化,其中调用到SurfaceFlinger::processDisplayHotplugEventsLocked函数,会对调用initScheduler对Scheduler进行初始化。

void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) {
    // ...
    // start the EventThread
    mScheduler =
            getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
                                         *mRefreshRateConfigs, *this);
    mAppConnectionHandle =
            mScheduler->createConnection("app", mPhaseConfiguration->getCurrentOffsets().late.app,
                                         impl::EventThread::InterceptVSyncsCallback());
    // 创建EventConnection
    mSfConnectionHandle =
            mScheduler->createConnection("sf", mPhaseConfiguration->getCurrentOffsets().late.sf,
                                         [this](nsecs_t timestamp) {
                                             mInterceptor->saveVSyncEvent(timestamp);
                                         });
    mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
    // ...
}

Scheduler::ConnectionHandle Scheduler::createConnection(
        const char* connectionName, nsecs_t phaseOffsetNs,
        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
    // 创建Vsync信号源
    auto vsyncSource = makePrimaryDispSyncSource(connectionName, phaseOffsetNs);
    // 创建EventThread,然后将Vsync信号源传递给EventThread
    auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
                                                           std::move(interceptCallback));
    return createConnection(std::move(eventThread));
}

std::make_unique这个标准库函数会将入参传递给EventThread的构造函数,在EventThread的构造函数中:

EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
                         InterceptVSyncsCallback interceptVSyncsCallback)
      : mVSyncSource(std::move(vsyncSource)),
        mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
        mThreadName(mVSyncSource->getName()) {
    mVSyncSource->setCallback(this);
		// 创建一个线程,然后线程调用threadMain
    mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
        std::unique_lock<std::mutex> lock(mMutex);
        threadMain(lock);
    });
	// ...
}

threadMain中的逻辑比较长,重点分析如下:

void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
    DisplayEventConsumers consumers;
		// 一个死循环
    while (mState != State::Quit) {
        std::optional<DisplayEventReceiver::Event> event;
				// ... 先处理一些之前的事件
        if (!mPendingEvents.empty()) {
            event = mPendingEvents.front();
            mPendingEvents.pop_front();
						// ...
        }
        bool vsyncRequested = false;

        // 找到需要消费事件的connection
        auto it = mDisplayEventConnections.begin();
        while (it != mDisplayEventConnections.end()) {
            if (const auto connection = it->promote()) {
                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
                // shouldConsumeEvent中,如果事件类型是Vsync类型,且connection的vsyncRequest是Single类型
                // 就是我们上文提到的在requestNextVsync过程中会将connection.vsyncRequest置为Single
                // 那么就是返回true,同时将connection.vsyncRequest再置回None类型。
                if (event && shouldConsumeEvent(*event, connection)) {
                    // 将这些需要消费事件的connection放入consumer容器
                    consumers.push_back(connection);
                }
                ++it;
            } else {
                it = mDisplayEventConnections.erase(it);
            }
        }
				// 一圈找下来,确实有消费者connection
        if (!consumers.empty()) {
            // 将事件进行分发
            dispatchEvent(*event, consumers);
            consumers.clear();
        }
				// ...
        if (event) {
            continue;
        }
        // 如果EventThread的状态是空闲状态,那么就阻塞在这里
        // 一直等待到有mCondition.notifyXXX的调用然后唤醒
        // 而我们requestNextVsync的过程中,就会调用到notify,唤醒阻塞的EventThread
        if (mState == State::Idle) {
            mCondition.wait(lock);
        } else {
            // ...
        }
    }
}

找到可以消费Vsync信号的connection后,就是将事件分发给他们:

void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                const DisplayEventConsumers& consumers) {
    for (const auto& consumer : consumers) {
        // 调用postEvent将事件分发给每一个消费者,consumer就是一个个的EventThreadConnection对象啦
        switch (consumer->postEvent(event)) {
            // ...
            default:
                // 将消费者从mDisplayEventConnections中移除
                // 所以一个connection,是只会消费一次Vsync事件的。
                removeDisplayEventConnectionLocked(consumer);
        }
    }
}

EventThreadConnection::postEvent实现如下:

status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
    ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
    return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
// DisplayEventReceiver::sendEvents最终调用到:
ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
        Event const* events, size_t count)
{
    // 好像串联起来了!!!
    // 上文在构造DisplayEventReceiver的过程中,有创建一个DataChannel的BitTube对象
    return gui::BitTube::sendObjects(dataChannel, events, count);
}
// BitTube的sendObjects方法实现:
ssize_t BitTube::sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize) {
    const char* vaddr = reinterpret_cast<const char*>(events);
    // 通过BitTube的write方法,SurfaceFlinger进程往对应的Socket管道中,写入数据,
    // 那么应用进程中Socket的read端,就能唤醒并读到数据。
    ssize_t size = tube->write(vaddr, count * objSize);
		// ...
    return size < 0 ? size : size / static_cast<ssize_t>(objSize);
}

再往下分析,我们要先理清楚,Socket是如何让应用进程和SurfaceFlinger进程建立通信Socket渠道的。

回到DisplayEventReceiver的构造过程:

DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource,
                                           ISurfaceComposer::ConfigChanged configChanged) {
  	// 通过ComposerService获取到ISurfaceComposer的引用
  	// 实际上就是获取SurfaceFlinger进程的Binder句柄
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr) {
        // 通过SurfaceFlinger的binder句柄,创建一个DisplayEventReceiver对象
        mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged);
        if (mEventConnection != nullptr) {
            // mDataChannel是应用进程与SurfaceFlinger进程数据交互的通道
            mDataChannel = std::make_unique<gui::BitTube>();
            // 创建完了mDataChannel之后,调用stealReceiveChannel,完成两个进程通信的建立
            mEventConnection->stealReceiveChannel(mDataChannel.get());
        }
    }
}
// stealReceiveChannel实现如下,outChannel是在应用进程创建的BitTube对象,
// 而mChannel是SurfaceFlinger进程创建的BitTube对象,包含了SurfaceFlinger创建的Socket读写fd
status_t EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
    // 这样就将应用进程Socket的read端和SurfaceFlingerSocket的read端设成同一个fd
    // 那么,SurfaceFlinger进程在往Socket的write端写数据的时候,应用进程的Socket的read端就能读到数据
    outChannel->setReceiveFd(mChannel.moveReceiveFd());
    outChannel->setSendFd(base::unique_fd(dup(mChannel.getSendFd())));
    return NO_ERROR;
}

到此,我们知道可SurfaceFlinger进程是如何告诉应用进程Vsync信号来了这个事件,但是应用进程是如何接收这个事件的呢?

我们下面来看,应用进程Choreographer对象的创建过程:

    private Choreographer(Looper looper, int vsyncSource) {
        mLooper = looper;
        mHandler = new FrameHandler(looper);
        // Java层的DisplayEventReceiver对象,USE_VSYNC是true,那么创建的就是FrameDisplayEventReceiver
        // 这里looper就是主线程的Looper。
        mDisplayEventReceiver = USE_VSYNC
                ? new FrameDisplayEventReceiver(looper, vsyncSource)
                : null;
       	// ...
    }

		// FrameDisplayEventReceiver继承自DisplayEventReceiver
    public DisplayEventReceiver(Looper looper, int vsyncSource, int configChanged) {
				// 拿到应用进程主线程的MessageQueue
        mMessageQueue = looper.getQueue();
        // mReceiverPtr还有印象吗?在scheduleVsyncLock请求下一次Vsync信号的时候,会通过它
        // 进入Native的处理逻辑,这里把主线程的MessageQueue传递给了nativeInit方法
        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
                vsyncSource, configChanged);

        mCloseGuard.open("dispose");
    }

nativeInit方法:

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj, jint vsyncSource, jint configChanged) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    // ...
  	// NativeDisplayEventReceiver创建过程中会将messageQueue赋值给mMessageQueue字段
    // 这样NativeDisplayEventReceiver就能直接获取主线程的消息队列(Native层的消息队列)
    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue, vsyncSource, configChanged);
    status_t status = receiver->initialize();
    // ...
}
// receiver继承自DisplayEventDispatcher,receiver->initialize()如下:
status_t DisplayEventDispatcher::initialize() {
    // ...
    if (mLooper != nullptr) {
        // 核心就是往主线程的Looper中添加一个文件描述符,这个文件描述符,
        // 就是上面SurfaceFlinger创建的SocketPair并返回给应用进程的Read端的fd
        int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
        if (rc < 0) {
            return UNKNOWN_ERROR;
        }
    }
    return OK;
}

再往下就是消息机制那一套了,我们可以再看下Looper中添加文件描述符做了什么事儿:

int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : nullptr, data);
}

int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
  // 这里我只留下了重点逻辑,创建一个Request并将传过来的fd,与Epoll机制绑定,
  // 这样当传入的fd有数据写入的时候,Epoll机制能唤醒阻塞的Looper取到Request进行执行。
  Request request;
	request.fd = fd;
	request.events = events;
	request.callback = callback;
  // 往Looper的mRequests中add或者replace上面创建的Request结构体
}

而前面我们对Android消息机制的分析知道,在Looper的pollInner函数中,会去处理Native侧的Request列表,先将其push到mResponse列表中,然后:

    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;
						// 执行Callback的handleEvent方法
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            // 如果返回0,将fd从Looper中移除,后续Looper就不会再监听这个fd了
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);
            }
						// ...
        }
    }
    return result;
}

handleEvent的实现是谁?这里就是NativeDisplayerEventReceiver(继承自DisplayEventDispatcher)的handleEvent嘛:

int DisplayEventDispatcher::handleEvent(int, int events, void*) {
    // ...
    // 如果有vsync事件的Receiver,那么这里就是true
    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
       	// ...
        // 分发Vsync事件
        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
    }
		// 这里return 1,希望Looper能继续监听这个fd
    return 1; // keep the callback
}
// dispatchVsync如下
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
                                               uint32_t count) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();

    ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
    if (receiverObj.get()) {
        ALOGV("receiver %p ~ Invoking vsync handler.", this);
        // 调用Java层DisplayEventReceiver.java对象的dispatchVsync方法。
        env->CallVoidMethod(receiverObj.get(),
                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId, count);
        ALOGV("receiver %p ~ Returned from vsync handler.", this);
    }

    mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}

回到Java层,dispatchVsync调用到onVsync,然后Choreographer就可以知道Vsync信号来了,开始触发视图的重新渲染。