Android UI系统2
我们在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信号来了,开始触发视图的重新渲染。