AndroidQ 應用層Vsync信號的註冊與接收(上)

上一篇文章我們分析了UI刷新機制,知道了Android UI刷新是在接收到Vsync信號之後才進行的,接着我準備繼續分析Vsync如何向native層註冊以及native層如何將Vsync發到上層,這部分比較複雜,我準備分兩篇文章來分析,主要就是兩個native函數:nativeInit和nativeScheduleVsync

根據上一篇文章,我們知道每當UI請求重繪時會調用Choreographer中的DisplayEventReceiver類的nativeScheduleVsync向native層註冊監聽Vsync,並且當下一個Vsync到來時會回調DisplayEventReceiver的onVsync方法,可以看出來DisplayEventReceiver這個類就是處理Vsync相關的核心

我們就從DisplayEventReceiver的創建開始分析,DisplayEventReceiver是個抽象類,它的實現類FrameDisplayEventReceiver在Choreographer的構造方法中初始化的

Choreographer

private Choreographer(Looper looper, int vsyncSource) {
        //UI線程的looper
        mLooper = looper;
        mHandler = new FrameHandler(looper);
        //USE_VSYNC爲true,使用VSYNC
        mDisplayEventReceiver = USE_VSYNC
                ? new FrameDisplayEventReceiver(looper, vsyncSource)
                : null;
        mLastFrameTimeNanos = Long.MIN_VALUE;
        //Android默認60FPS,mFrameIntervalNanos爲16.6
        mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
        mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
        for (int i = 0; i <= CALLBACK_LAST; i++) {
            mCallbackQueues[i] = new CallbackQueue();
        }
        // b/68769804: For low FPS experiments.
        setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
    }

Choreographer構造中做一些重要的初始化工作,我們這裏注意一下vsyncSource這個值

DisplayEventReceiver中定義瞭如下兩個常量,代表VSYNC的兩種使用,APP和SurfaceFlinger,這裏傳遞到native層的是VSYNC_SOURCE_APP這種,即APP層請求的VSYNC

 /**
     * When retrieving vsync events, this specifies that the vsync event should happen at the normal
     * vsync-app tick.
     * <p>
     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
     */
    public static final int VSYNC_SOURCE_APP = 0;

    /**
     * When retrieving vsync events, this specifies that the vsync event should happen whenever
     * Surface Flinger is processing a frame.
     * <p>
     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
     */
    public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;

FrameDisplayEventReceiver的構造方法中顯式調用了父類DisplayEventReceiver的構造方法:

public DisplayEventReceiver(Looper looper, int vsyncSource) {
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
                vsyncSource);

        mCloseGuard.open("dispose");
    }

調用nativeInit,將主線程的MessageQueue傳遞了過去

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj, jint vsyncSource) {
        //根據java層messageQueue的到native層messageQueue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    //步驟1
    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue, vsyncSource);
    //步驟2
    status_t status = receiver->initialize();
    if (status) {
        String8 message;
        message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return 0;
    }

    receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
    return reinterpret_cast<jlong>(receiver.get());
}

這個方法重點就兩部分,步驟1:創建NativeDisplayEventReceiver,步驟2:調用其initialize方法

我們首先看步驟1:

NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
        jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource) :
        DisplayEventDispatcher(messageQueue->getLooper(),
                static_cast<ISurfaceComposer::VsyncSource>(vsyncSource)),
        mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
        mMessageQueue(messageQueue) {
    ALOGV("receiver %p ~ Initializing display event receiver.", this);
}

NativeDisplayEventReceiver構造方法中調用了父類DisplayEventDispatcher的構造方法,並且將java層傳遞下來的VSYNC_SOURCE_APP強轉爲了ISurfaceComposer::VsyncSource傳遞給了DisplayEventDispatcher,
VsyncSource是枚舉類型,VSYNC_SOURCE_APP爲0,所以就相當於強轉爲了eVsyncSourceApp,代表由APP層請求的Vsync

class ISurfaceComposer: public IInterface {
			...
	enum VsyncSource {
        eVsyncSourceApp = 0,
        eVsyncSourceSurfaceFlinger = 1
    };
			...
}

我們看DisplayEventDispatcher構造方法中將vsyncSource賦值給了mReceiver

DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
        ISurfaceComposer::VsyncSource vsyncSource) :
        mLooper(looper), mReceiver(vsyncSource), mWaitingForVsync(false) {
    ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}

mReceiver是DisplayEventReceiver類型,這裏相當與調用DisplayEventReceiver的構造函數進行初始化

DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
    //步驟1
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr) {
        //步驟2
        mEventConnection = sf->createDisplayEventConnection(vsyncSource);
        if (mEventConnection != nullptr) {
            //步驟3
            mDataChannel = std::make_unique<gui::BitTube>();
               //步驟4
            mEventConnection->stealReceiveChannel(mDataChannel.get());
        }
    }
}

DisplayEventReceiver的構造函數做的事情非常重要,且比較複雜,主要是建立應用層與SurfaceFlinger的連接,這裏分爲四個步驟來分析

步驟1:獲取SurfaceFlinger服務

sp<ISurfaceComposer> sf(ComposerService::getComposerService());

ComposerService::getComposerService()

/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
    ComposerService& instance = ComposerService::getInstance();
    Mutex::Autolock _l(instance.mLock);
    if (instance.mComposerService == nullptr) {
        ComposerService::getInstance().connectLocked();
        assert(instance.mComposerService != nullptr);
        ALOGD("ComposerService reconnected");
    }
    return instance.mComposerService;
}

這個函數定義在SurfaceComposerClient.cpp中,這個函數中調用了ComposerService的connectLocked函數

connectLocked

void ComposerService::connectLocked() {
    const String16 name("SurfaceFlinger");
    while (getService(name, &mComposerService) != NO_ERROR) {
        usleep(250000);
    }
    assert(mComposerService != nullptr);

    // 創建死亡回調
    ......
}

connectLocked函數的作用很簡單,獲取SurfaceFlinger服務,保存在ComposerService的mComposerService中,其實獲取的是SurfaceFlinger的Bp端BpSurfaceComposer,SurfaceFlinger的是它的Bn端BnSurfaceComposer的子類

接着看步驟2:通過Binder實現跨進程調用,最終到SurfaceFlinger中,
mEventConnection = sf->createDisplayEventConnection(vsyncSource);

createDisplayEventConnection

virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource)
    {
        .....
        err = remote()->transact(
                BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
                data, &reply);
       ......
       lt = interface_cast<IDisplayEventConnection>(reply.readStrongBinder());
        return result;
    }

需要注意最終從SurfaceFlinger返回的也是EventThreadConnection的Bp端BpDisplayEventConnection,EventThreadConnection繼承自BnDisplayEventConnection

好了,來看SurfaceFlinger的createDisplayEventConnection函數,傳遞的參數是eVsyncSourceApp = 0,應用層請求的Vsync
mEventConnection = sf->createDisplayEventConnection(vsyncSource);

createDisplayEventConnection

sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
        ISurfaceComposer::VsyncSource vsyncSource) {
    auto resyncCallback = mScheduler->makeResyncCallback([this] {
        Mutex::Autolock lock(mStateLock);
        return getVsyncPeriod();
    });
    
    const auto& handle =
            vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;

    return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
}

這個函數我們首先來看mScheduler->makeResyncCallback,mScheduler是Scheduler類型,在SurfaceFlinger的init中創建的,這裏會創建一個resyncCallback,類型爲ResyncCallback,定義在EventThread.cpp中,std::function這是個新API

using ResyncCallback = std::function<void()>;

大致功能是將一段可執行代碼封裝到ResyncCallback中,僅從功能上看,和函數指針作用類似

ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
    std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
    return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
        if (const auto vsync = ptr.lock()) {
            vsync->resync(getVsyncPeriod);
        }
    };
}

接着得到handle的類型,因爲一開始傳遞的就是App請求的Vsync,所以handle爲mAppConnectionHandle,它的類型爲sp<Scheduler::ConnectionHandle> mAppConnectionHandle;看名字這是用來處理Vsync到APP的連接的,它也是在SurfaceFlinger的init中創建的,我們來大概看看它的創建:

void SurfaceFlinger::init() {
	......
	mScheduler =
            getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
                                         mRefreshRateConfigs);
    auto resyncCallback =
            mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));

    mAppConnectionHandle =
            mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
                                         resyncCallback,
                                         impl::EventThread::InterceptVSyncsCallback());
	......	
}

調用mScheduler的createConnection函數創建的,它的名字是"app",

createConnection

sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
        const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
    //id從0累加
    const int64_t id = sNextId++;
    ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
     //創建對應connectionName名字的EventThread
    std::unique_ptr<EventThread> eventThread =
            makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
                            std::move(interceptCallback));
    //創建EventThreadConnection
    auto eventThreadConnection =
            createConnectionInternal(eventThread.get(), std::move(resyncCallback));
    //創建ConnectionHandle,與id對應
    mConnections.emplace(id,
                         std::make_unique<Connection>(new ConnectionHandle(id),
                                                      eventThreadConnection,
                                                      std::move(eventThread)));
    //返回”app“的ConnectionHandle
    return mConnections[id]->handle;
}

createConnection這個函數在SurfaceFlinger中調用了兩次,一次是創建"app"的Connection,一次是創建"sf"的Connection,我們可以理解爲創建兩套連接,一套給app使用,一套個surfaceFlinger使用,兩套連接的用connectionName以及id進行標識,(id爲0,connectionName等於”app“的)與(id爲1,connectionName等於”sf“的)

createConnection函數根據connectionName創建EventThread,根據EventThread創建EventThreadConnection,然後創建ConnectionHandle,根據ConnectionHandle,EventThreadConnection,EventThread最終創建Connection,並以id爲key,Connection爲value加入到mConnections的map中,最終返回”app“的ConnectionHandle,這些類的創建肯定初始化了很多重要過程,我們這裏不去一一分析,只要知道後面用的時候有創建過這些類

mAppConnectionHandle的創建過程我們大致看了下,知道了這是一個”app“的ConnectionHandle,

接着我們繼續看:mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));

sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
        const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
    RETURN_VALUE_IF_INVALID(nullptr);
    return createConnectionInternal(mConnections[handle->id]->thread.get(),
                                    std::move(resyncCallback));
}

調用createConnectionInternal,handle->id用於標識這套連接是app還是surfaceFlinger

createConnectionInternal

sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
                                                              ResyncCallback&& resyncCallback) {
    return eventThread->createEventConnection(std::move(resyncCallback));
}

調用EventThread的createEventConnection函數

createEventConnection

sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
    return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
}

創建了一個EventThreadConnection對象,看下它的構造函數

EventThreadConnection::EventThreadConnection(EventThread* eventThread,
                                             ResyncCallback resyncCallback)
      : resyncCallback(std::move(resyncCallback)),
        mEventThread(eventThread),
        mChannel(gui::BitTube::DefaultSize) {}

構造函數中最重要的就是創建了mChannel,mChannel是gui::BitTube類型
接着看gui::BitTube的構造函數:這裏傳遞的DefaultSize爲4kb,
定義在BitTube.h中:
// creates a BitTube with a default (4KB) send buffer
struct DefaultSizeType {};
static constexpr DefaultSizeType DefaultSize{};


BitTube::BitTube(size_t bufsize) {
    init(bufsize, bufsize);
}

init

void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
        // since we don't use the "return channel", we keep it small...
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
        mReceiveFd.reset(sockets[0]);
        mSendFd.reset(sockets[1]);
    } else {
        mReceiveFd.reset();
        ALOGE("BitTube: pipe creation failed (%s)", strerror(errno));
    }
}

init函數主要是通過socketpair函數創建一對socket

socketpair()函數用於創建一對無名的、相互連接的socket
如果成功,則返回0,創建好的socket分別是sv[0]和sv[1];否則返回-1

  1. 這對socket可以用於全雙工通信,每一個socket既可以讀也可以寫。例如,可以往sv[0]中寫,從sv[1]中讀,或者從sv[1]中寫,從sv[0]中讀。
  2. 如果往一個socket(如sv[0])中寫入後,再從該socket讀時會阻塞,只能在另一個socket中(sv[1])上讀成功;
  3. 讀、寫操作可以位於同一個進程,也可以分別位於不同的進程。

通過socketpair創建好了一對socket之後,再通過setsockopt對socket進行設置,再調用fcntl函數針對socket描述符提供控制,不用管具體幹嘛的,
最後我們看mReceiveFd.reset(sockets[0]),mSendFd.reset(sockets[1]);建立Fd與socket的關聯,很明顯這一對sockets一個用來接受消息,一個用來發送消息,到這裏我們可以猜測,Vsync到來的時候通過mSendFd寫入消息,然後app監聽mReceiveFd接受消息,就完成了app對Vsync的接收,需要注意一點,此時的mReceiveFd依然還在SurfaceFlinger進程,app端要使用肯定是需要回傳回去的,但是步驟2的調用已經結束,沒看到那裏返回mReceiveFd的,那麼我們接着往後分析看看

我們總結一下步驟2:
mEventConnection = sf->createDisplayEventConnection(vsyncSource);
步驟2其實就是根據vsyncSource,得到此Vsync請求來自app,然後創建一套app的連接,其實最終就是創建一對socket用來進行進程間通信,類似的還有Input系統,也是通過一對socket來連接app和InputDispatcher

我們接着之前分了四個步驟的代碼進行分析:

DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
    //步驟1   獲取SurfaceFlinger服務
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr) {
        //步驟2  創建一對socket連接
        mEventConnection = sf->createDisplayEventConnection(vsyncSource);
        if (mEventConnection != nullptr) {
            //步驟3  獲得gui::BitTube對象
            mDataChannel = std::make_unique<gui::BitTube>();
               //步驟4
            mEventConnection->stealReceiveChannel(mDataChannel.get());
        }
    }
}

我們已經分析完了步驟1,步驟2,步驟3比較簡單,就是獲得gui::BitTube對象,來看步驟4:
mEventConnection->stealReceiveChannel(mDataChannel.get());

我們步驟2分析過mEventConnection是從SurfaceFlinger返回的Binder Bp端,BpDisplayEventConnection,那麼先看看Bp端的調用

stealReceiveChannel

class BpDisplayEventConnection : public SafeBpInterface<IDisplayEventConnection> {
public:
    ......
    status_t stealReceiveChannel(gui::BitTube* outChannel) override {
        return callRemote<decltype(
                &IDisplayEventConnection::stealReceiveChannel)>(Tag::STEAL_RECEIVE_CHANNEL,
                                                                outChannel);
    }
 }

這個方法裏面的語法我不太清楚,但既然是Binder通信,最終一定是調到BnDisplayEventConnection中去了,Tag爲STEAL_RECEIVE_CHANNEL,類似Binder的code,用來找對應方法的,我們來看看Bn端的具體實現:

status_t EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
    outChannel->setReceiveFd(mChannel.moveReceiveFd());
    return NO_ERROR;
}

mChannel保存的是gui::BitTube

base::unique_fd BitTube::moveReceiveFd() {
    return std::move(mReceiveFd);
}
void BitTube::setReceiveFd(base::unique_fd&& receiveFd) {
    mReceiveFd = std::move(receiveFd);
}

所以stealReceiveChannel就等價於
outChannel.mReceiveFd = mChannel.mReceiveFd
這什麼意思呢?其實就相當於將步驟2在surfaceFlinger進程中創建的mReceiveFd傳遞到app進程中去,app進程有了mReceiveFd,surfaceFlinger進程有了mSendFd就能夠實現通信了

到此我們已經分析完了DisplayEventReceiver構造函數中的四個步驟,把代碼再貼出來看下

DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
    //步驟1
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr) {
        //步驟2
        mEventConnection = sf->createDisplayEventConnection(vsyncSource);
        if (mEventConnection != nullptr) {
            //步驟3
            mDataChannel = std::make_unique<gui::BitTube>();
               //步驟4
            mEventConnection->stealReceiveChannel(mDataChannel.get());
        }
    }
}

我們對這四個步驟進行總結:

  1. 獲取surfaceFlinger的Bp端,以便與surfaceFlinger進行Binder通信
  2. 獲取EventThread::EventThreadConnection的Bp端,在創建EventThread::EventThreadConnection又創建了gui::BitTube對象,在gui::BitTube的init函數中創建了一對socket,並建立mReceiveFd,mSendFd和socket的關聯,以便在監聽mReceiveFd時能夠收到mSendFd寫入的消息
  3. 在app端創建一個gui::BitTube
  4. 通過stealReceiveChannel函數將app端的gui::BitTube傳遞到surfaceFlinger進程,目的是將surfaceFlinger進程的mReceiveFd傳遞到app端

到現在爲止我們僅僅分析了最開始的nativeInit函數的步驟1

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
     ......
    //步驟1
    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue, vsyncSource);
    //步驟2
    status_t status = receiver->initialize();
    ......
    return reinterpret_cast<jlong>(receiver.get());
}

我們接這來看看步驟2:receiver->initialize,它的實現在DisplayEventDispatcher中:

initialize

status_t DisplayEventDispatcher::initialize() {
    //檢查mReceiver是否異常
    status_t result = mReceiver.initCheck();
    ...
    int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
            this, NULL);
    if (rc < 0) {
        return UNKNOWN_ERROR;
    }
    return OK;
}

這個函數就比較簡單了,調用Looper的addFd將我們前面得到的mReceiveFd添加到Handler進行監聽,關於Handler的native層的消息機制可以參考我以前分析過的AndroidQ Handler消息機制(native層),我們這裏就大概說一下,Handler消息機制可以處理三種消息,java層msg,native層msg,以及通過addFd創建的request,request中包含監聽的fd以及收到消息時的回調handleEvent

所以這裏監聽了mReceiveFd之後,當mSendFd寫入數據時就能收到消息,並回調DisplayEventDispatcher的handleEvent函數

限於篇幅,這篇文章就分析到這裏,主要就是分析了nativeInit這一個native的函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章