Flutter vsync两种实现方式

333 阅读1分钟

前些日子,组里同事在做Flutter性能优化,但是遇到了一个问题,我们自己写的flutter  apk,Flutter 1.UI线程是被 SurfaceFlinger的app唤醒的。但是三方应用的是被主线程唤醒的。

我们看下trace:

第一种情况:flutter的1.ui被  SurfaceFlinger的app唤醒。

WechatIMG128.jpeg

第二种情况:flutter的1.ui被 ui主线程唤醒

WechatIMG129.jpeg

我们看下代码:

github.com/flutter/eng…


// |VsyncWaiter|

void VsyncWaiterAndroid::AwaitVSync() {

  if (use_ndk_choreographer_) {

    auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this());

    fml::TaskRunner::RunNowOrPostTask(

        task_runners_.GetUITaskRunner(), [weak_this]() {

          AndroidChoreographer::PostFrameCallback(&OnVsyncFromNDK, weak_this);

        });

  } else {

    // TODO(99798): Remove it when we drop support for API level < 29.

    auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this());

    jlong java_baton = reinterpret_cast<jlong>(weak_this);

    task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() {

      JNIEnv* env = fml::jni::AttachCurrentThread();

      env->CallStaticVoidMethod(g_vsync_waiter_class->obj(),     //

                                g_async_wait_for_vsync_method_,  //

                                java_baton                       //

      );

    });

  }

}

如果use_ndk_choreographer_, 就使用上面的AndroidChoreographer::PostFrameCallback,最终调用到cs.android.com/android/pla…


void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb,

                                             AChoreographer_frameCallback64 cb64,

                                             AChoreographer_vsyncCallback vsyncCallback, void* data,

                                             nsecs_t delay) {

    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

    FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay};

    {

        std::lock_guard<std::mutex> _l{mLock};

        mFrameCallbacks.push(callback);

    }

    if (callback.dueTime <= now) {

        if (std::this_thread::get_id() != mThreadId) {

            if (mLooper != nullptr) {

                Message m{MSG_SCHEDULE_VSYNC};

                mLooper->sendMessage(this, m);

            } else {

                scheduleVsync();

            }

        } else {

            scheduleVsync();

        }

    } else {

        if (mLooper != nullptr) {

            Message m{MSG_SCHEDULE_CALLBACKS};

            mLooper->sendMessageDelayed(delay, this, m);

        } else {

            scheduleCallbacks();

        }

    }

}

通过这种形式 scheduleVsync, 也就是需要SF的app信号来唤醒。

通过代码分析,use_ndk_choreographer_ = true的,逻辑是判断so里是不是包含一些符号表。那么为什么有的应用不是这样呢?

我们分析下 flutter engine的代码提交记录

github.com/flutter/eng…

WechatIMG130.jpeg

发现flutter2022年修改过这一块,左边是之前的代码,是通过jni调用了 java层的Choreographer.getInstance().postFrameCallback(obtainFrameCallback(cookie));来实现,这种会通过 主线程唤醒1.ui了。

      private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate =

      new FlutterJNI.AsyncWaitForVsyncDelegate() {

  


        private Choreographer.FrameCallback obtainFrameCallback(final long cookie) {

          if (frameCallback != null) {

            frameCallback.cookie = cookie;

            FrameCallback ret = frameCallback;

            frameCallback = null;

            return ret;

          }

          return new FrameCallback(cookie);

        }

  


        @Override

        public void asyncWaitForVsync(long cookie) {

          Choreographer.getInstance().postFrameCallback(obtainFrameCallback(cookie));

        }

      };