VSYNC信号是通过什么方式传递?

VSYNC信号是通过什么方式传递?

前两天在一个面试中遇到这个问题,其实自己当时是没有看过这块具体的源代码的,自己就回答了一个binder,后面翻了一下源代码果然错的离谱,今天就补上这一课。

Choreographer

我们知道上层当有绘制的需求时,会去申请vsync信号,信号的申请是从Choreographer开始,就从这里看起。

Java 复制代码
private void scheduleVsyncLocked() {
    try {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
        mDisplayEventReceiver.scheduleVsync();
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

这里没有什么好讲的,从ViewRootImpi中开始有绘制的动作申请信号兜兜转转就走到了这里。mDisplayEventReceiverFrameDisplayEventReceiver类。

Java 复制代码
/**
 * Schedules a single vertical sync pulse to be delivered when the next
 * display frame begins.
 */
@UnsupportedAppUsage
public void scheduleVsync() {
    if (mReceiverPtr == 0) {
        Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                + "receiver has already been disposed.");
    } else {
        nativeScheduleVsync(mReceiverPtr);
    }
}

nativeScheduleVsync是一个Native函数,

C++ 复制代码
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
            //这里,我们首先看下NativeDisplayEventReceiver是做什么的
    status_t status = receiver->scheduleVsync();
    if (status) {
        String8 message;
        message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
    }
}

DisplayEventDispatcher

C++ 复制代码
class NativeDisplayEventReceiver : public DisplayEventDispatcher {
public:
    NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
                               const sp<MessageQueue>& messageQueue, jint vsyncSource,
                               jint eventRegistration);

    void dispose();

protected:
    virtual ~NativeDisplayEventReceiver();

private:
    jobject mReceiverWeakGlobal;
    sp<MessageQueue> mMessageQueue;

    void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
                       VsyncEventData vsyncEventData) override;
    void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
    void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
                             nsecs_t vsyncPeriod) override;
    void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
                                    std::vector<FrameRateOverride> overrides) override;
    void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
};

scheduleVsyncNativeDisplayEventReceiver中没有定义,我们继续去跟踪它的父类DisplayEventDispatcher

C++ 复制代码
status_t DisplayEventDispatcher::scheduleVsync() {
    if (!mWaitingForVsync) {
        ALOGV("dispatcher %p ~ Scheduling vsync.", this);

        // Drain all pending events.
        nsecs_t vsyncTimestamp;
        PhysicalDisplayId vsyncDisplayId;
        uint32_t vsyncCount;
        VsyncEventData vsyncEventData;
        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
                  ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
        }
        //请求信号
        status_t status = mReceiver.requestNextVsync();
        if (status) {
            ALOGW("Failed to request next vsync, status=%d", status);
            return status;
        }

        mWaitingForVsync = true;
        mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
    }
    return OK;
}

mReceiver是在头文件中定义的,它对应的类是DisplayEventReceiver

C++ 复制代码
class DisplayEventDispatcher : public LooperCallback {
public:
    explicit DisplayEventDispatcher(
            const sp<Looper>& looper,
            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
            ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
    ...
private:
    sp<Looper> mLooper;
    DisplayEventReceiver mReceiver;
    bool mWaitingForVsync;
    uint32_t mLastVsyncCount;
    nsecs_t mLastScheduleVsyncTime;
    ...
}

createDisplayEventConnection函数在SurfaceFlinger中实现,BitTube是一个封装了SocketAPI

C++ 复制代码
DisplayEventReceiver::DisplayEventReceiver(
        ISurfaceComposer::VsyncSource vsyncSource,
        ISurfaceComposer::EventRegistrationFlags eventRegistration) {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr) {
        mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration);
        if (mEventConnection != nullptr) {
            mDataChannel = std::make_unique<gui::BitTube>();
            const auto status = mEventConnection->stealReceiveChannel(mDataChannel.get());
            if (!status.isOk()) {
                ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str());
                mInitError = std::make_optional<status_t>(status.transactionError());
                mDataChannel.reset();
                mEventConnection.clear();
            }
        }
    }
}


status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != nullptr) {
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    return mInitError.has_value() ? mInitError.value() : NO_INIT;
}
C++ 复制代码
class DisplayEventReceiver {
    private:
        //事件定义
        sp<IDisplayEventConnection> mEventConnection;
        //通道,这个就是对应的通信方式
        std::unique_ptr<gui::BitTube> mDataChannel;
        std::optional<status_t> mInitError;
    };
}

答案

代码追踪到了这里,答案就已经很明显了,最终采用过的是Socket方式进行通信。而不是Android中更常见的Binder

为什么?

为什么是socket不是binder呢,想了一下 inputEvent的传递也是通过Socket

那这里我们就总结一下这两者的共性

  • 1:都是毫秒为单位的高频通信场景。
  • 2:都有稳定长久的通信诉求,几乎伴随了整个设备的开机周期。
  • 3:有双向通信的需求。

如果高频率的通信也使用Binder的话,Binder的资源在Android中是有限的。直接就排除了使用Binder的可能性。

以上的所有使用的共性都会因为Binder资源的有限性导致Socket在这其中更为合适。

给我们的思考,在以后得开发过程中,假如我们有频繁,双通道或者稳定信息量较大的通信需求时,应该优先的考虑Socket

相关推荐
CYRUS_STUDIO17 分钟前
利用 Linux 信号机制(SIGTRAP)实现 Android 下的反调试
android·安全·逆向
CYRUS_STUDIO36 分钟前
Android 反调试攻防实战:多重检测手段解析与内核级绕过方案
android·操作系统·逆向
黄林晴4 小时前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我4 小时前
flutter 之真手势冲突处理
android·flutter
法的空间5 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止5 小时前
深入解析安卓 Handle 机制
android
恋猫de小郭5 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech5 小时前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
用户2018792831675 小时前
为何Handler的postDelayed不适合精准定时任务?
android
叽哥6 小时前
Kotlin学习第 8 课:Kotlin 进阶特性:简化代码与提升效率
android·java·kotlin