diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e87ee01ef7089..d7f0d1c76d2d6 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -6290,8 +6290,6 @@ ORIGIN: ../../../flutter/shell/gpu/gpu_surface_vulkan_delegate.h + ../../../flut ORIGIN: ../../../flutter/shell/gpu/gpu_surface_vulkan_impeller.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/gpu/gpu_surface_vulkan_impeller.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/AndroidManifest.xml + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/android/android_choreographer.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/android/android_choreographer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/android_context_gl_impeller.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/android_context_gl_impeller.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/android_context_gl_skia.cc + ../../../flutter/LICENSE @@ -9130,8 +9128,6 @@ FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan_delegate.h FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan_impeller.cc FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan_impeller.h FILE: ../../../flutter/shell/platform/android/AndroidManifest.xml -FILE: ../../../flutter/shell/platform/android/android_choreographer.cc -FILE: ../../../flutter/shell/platform/android/android_choreographer.h FILE: ../../../flutter/shell/platform/android/android_context_gl_impeller.cc FILE: ../../../flutter/shell/platform/android/android_context_gl_impeller.h FILE: ../../../flutter/shell/platform/android/android_context_gl_skia.cc diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index f850d83ab8f0b..21429607f2435 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -78,8 +78,6 @@ source_set("flutter_shell_native_src") { visibility = [ ":*" ] sources = [ - "android_choreographer.cc", - "android_choreographer.h", "android_context_gl_impeller.cc", "android_context_gl_impeller.h", "android_context_gl_skia.cc", diff --git a/shell/platform/android/android_choreographer.cc b/shell/platform/android/android_choreographer.cc deleted file mode 100644 index f72787f423920..0000000000000 --- a/shell/platform/android/android_choreographer.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/android/android_choreographer.h" - -#include "flutter/fml/native_library.h" - -// Only avialalbe on API 24+ -typedef void AChoreographer; -// Only available on API 29+ or API 24+ if the architecture is 64-bit. -typedef void (*AChoreographer_frameCallback)(int64_t frameTimeNanos, - void* data); -// Only avialalbe on API 24+ -typedef AChoreographer* (*AChoreographer_getInstance_FPN)(); -typedef void (*AChoreographer_postFrameCallback_FPN)( - AChoreographer* choreographer, - AChoreographer_frameCallback callback, - void* data); -static AChoreographer_getInstance_FPN AChoreographer_getInstance; -static AChoreographer_postFrameCallback_FPN AChoreographer_postFrameCallback; - -namespace flutter { - -bool AndroidChoreographer::ShouldUseNDKChoreographer() { - static std::optional use_ndk_choreographer; - if (use_ndk_choreographer) { - return use_ndk_choreographer.value(); - } - auto libandroid = fml::NativeLibrary::Create("libandroid.so"); - FML_DCHECK(libandroid); - auto get_instance_fn = - libandroid->ResolveFunction( - "AChoreographer_getInstance"); - auto post_frame_callback_fn = - libandroid->ResolveFunction( - "AChoreographer_postFrameCallback64"); -#if FML_ARCH_CPU_64_BITS - if (!post_frame_callback_fn) { - post_frame_callback_fn = - libandroid->ResolveFunction( - "AChoreographer_postFrameCallback"); - } -#endif - if (get_instance_fn && post_frame_callback_fn) { - AChoreographer_getInstance = get_instance_fn.value(); - AChoreographer_postFrameCallback = post_frame_callback_fn.value(); - use_ndk_choreographer = true; - } else { - use_ndk_choreographer = false; - } - return use_ndk_choreographer.value(); -} - -void AndroidChoreographer::PostFrameCallback(OnFrameCallback callback, - void* data) { - AChoreographer* choreographer = AChoreographer_getInstance(); - AChoreographer_postFrameCallback(choreographer, callback, data); -} - -} // namespace flutter diff --git a/shell/platform/android/android_choreographer.h b/shell/platform/android/android_choreographer.h deleted file mode 100644 index 632bc77479e48..0000000000000 --- a/shell/platform/android/android_choreographer.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CHOREOGRAPHER_H_ -#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CHOREOGRAPHER_H_ - -#include "flutter/fml/macros.h" - -#include - -namespace flutter { - -//------------------------------------------------------------------------------ -/// The Android Choreographer is used by `VsyncWaiterAndroid` to await vsync -/// signal. It's only available on API 29+ or API 24+ if the architecture is -/// 64-bit. -/// -class AndroidChoreographer { - public: - typedef void (*OnFrameCallback)(int64_t frame_time_nanos, void* data); - static bool ShouldUseNDKChoreographer(); - static void PostFrameCallback(OnFrameCallback callback, void* data); - - FML_DISALLOW_COPY_AND_ASSIGN(AndroidChoreographer); -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CHOREOGRAPHER_H_ diff --git a/shell/platform/android/flutter_main.cc b/shell/platform/android/flutter_main.cc index 042e5fd769bae..8a2e9eaca5e66 100644 --- a/shell/platform/android/flutter_main.cc +++ b/shell/platform/android/flutter_main.cc @@ -24,6 +24,7 @@ #include "flutter/runtime/dart_vm.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/switches.h" +#include "flutter/shell/platform/android/ndk_helpers.h" #include "third_party/dart/runtime/include/dart_tools_api.h" #include "txt/platform.h" @@ -39,21 +40,6 @@ extern const intptr_t kPlatformStrongDillSize; namespace { -// This is only available on API 23+, so dynamically look it up. -// This method is only called once at shell creation. -// Do this in C++ because the API is available at level 23 here, but only 29+ in -// Java. -bool IsATraceEnabled() { - auto libandroid = fml::NativeLibrary::Create("libandroid.so"); - FML_CHECK(libandroid); - auto atrace_fn = - libandroid->ResolveFunction("ATrace_isEnabled"); - if (atrace_fn) { - return atrace_fn.value()(); - } - return false; -} - fml::jni::ScopedJavaGlobalRef* g_flutter_jni_class = nullptr; } // anonymous namespace @@ -95,7 +81,7 @@ void FlutterMain::Init(JNIEnv* env, // Turn systracing on if ATrace_isEnabled is true and the user did not already // request systracing if (!settings.trace_systrace) { - settings.trace_systrace = IsATraceEnabled(); + settings.trace_systrace = NDKHelpers::ATrace_isEnabled(); if (settings.trace_systrace) { __android_log_print( ANDROID_LOG_INFO, "Flutter", diff --git a/shell/platform/android/library_loader.cc b/shell/platform/android/library_loader.cc index 646f232e8bc4b..103a3aeb2a111 100644 --- a/shell/platform/android/library_loader.cc +++ b/shell/platform/android/library_loader.cc @@ -14,6 +14,9 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { // Initialize the Java VM. fml::jni::InitJavaVM(vm); + // Registery dlsym lookups for NDK functions + flutter::NDKHelpers::Init(); + JNIEnv* env = fml::jni::AttachCurrentThread(); bool result = false; diff --git a/shell/platform/android/ndk_helpers.cc b/shell/platform/android/ndk_helpers.cc index 8a11cc50fea0f..65fc9368c8ad3 100644 --- a/shell/platform/android/ndk_helpers.cc +++ b/shell/platform/android/ndk_helpers.cc @@ -25,6 +25,18 @@ typedef void (*fp_AHardwareBuffer_describe)(AHardwareBuffer* buffer, typedef void (*fp_AHardwareBuffer_getId)(AHardwareBuffer* buffer, uint64_t* outId); +typedef bool (*fp_ATrace_isEnabled)(void); + +typedef AChoreographer* (*fp_AChoreographer_getInstance)(void); +typedef void (*fp_AChoreographer_postFrameCallback)( + AChoreographer* choreographer, + AChoreographer_frameCallback callbackk, + void* data); +typedef void (*fp_AChoreographer_postFrameCallback64)( + AChoreographer* choreographer, + AChoreographer_frameCallback64 callbackk, + void* data); + typedef EGLClientBuffer (*fp_eglGetNativeClientBufferANDROID)( AHardwareBuffer* buffer); @@ -37,6 +49,17 @@ void (*_AHardwareBuffer_describe)(AHardwareBuffer* buffer, AHardwareBuffer_Desc* desc) = nullptr; void (*_AHardwareBuffer_getId)(AHardwareBuffer* buffer, uint64_t* outId) = nullptr; +bool (*_ATrace_isEnabled)() = nullptr; +AChoreographer* (*_AChoreographer_getInstance)() = nullptr; +void (*_AChoreographer_postFrameCallback)( + AChoreographer* choreographer, + AChoreographer_frameCallback callbackk, + void* data) = nullptr; +void (*_AChoreographer_postFrameCallback64)( + AChoreographer* choreographer, + AChoreographer_frameCallback64 callbackk, + void* data) = nullptr; + EGLClientBuffer (*_eglGetNativeClientBufferANDROID)(AHardwareBuffer* buffer) = nullptr; @@ -75,6 +98,32 @@ void InitOnceCallback() { ->ResolveFunction( "AHardwareBuffer_describe") .value_or(nullptr); + + _ATrace_isEnabled = + android->ResolveFunction("ATrace_isEnabled") + .value_or(nullptr); + + _AChoreographer_getInstance = + android + ->ResolveFunction( + "AChoreographer_getInstance") + .value_or(nullptr); + if (_AChoreographer_getInstance) { + _AChoreographer_postFrameCallback64 = + android + ->ResolveFunction( + "AChoreographer_postFrameCallback64") + .value_or(nullptr); +#if FML_ARCH_CPU_64_BITS + if (!_AChoreographer_postFrameCallback64) { + _AChoreographer_postFrameCallback = + android + ->ResolveFunction( + "AChoreographer_postFrameCallback") + .value_or(nullptr); + } +#endif + } } } // namespace @@ -83,8 +132,45 @@ void NDKHelpers::Init() { std::call_once(init_once, InitOnceCallback); } +bool NDKHelpers::ATrace_isEnabled() { + if (_ATrace_isEnabled) { + return _ATrace_isEnabled(); + } + return false; +} + +ChoreographerSupportStatus NDKHelpers::ChoreographerSupported() { + if (_AChoreographer_postFrameCallback64) { + return ChoreographerSupportStatus::kSupported64; + } + if (_AChoreographer_postFrameCallback) { + return ChoreographerSupportStatus::kSupported32; + } + return ChoreographerSupportStatus::kUnsupported; +} + +AChoreographer* NDKHelpers::AChoreographer_getInstance() { + FML_CHECK(_AChoreographer_getInstance); + return _AChoreographer_getInstance(); +} + +void NDKHelpers::AChoreographer_postFrameCallback( + AChoreographer* choreographer, + AChoreographer_frameCallback callback, + void* data) { + FML_CHECK(_AChoreographer_postFrameCallback); + return _AChoreographer_postFrameCallback(choreographer, callback, data); +} + +void NDKHelpers::AChoreographer_postFrameCallback64( + AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, + void* data) { + FML_CHECK(_AChoreographer_postFrameCallback64); + return _AChoreographer_postFrameCallback64(choreographer, callback, data); +} + bool NDKHelpers::HardwareBufferSupported() { - NDKHelpers::Init(); const bool r = _AHardwareBuffer_fromHardwareBuffer != nullptr; return r; } @@ -92,33 +178,28 @@ bool NDKHelpers::HardwareBufferSupported() { AHardwareBuffer* NDKHelpers::AHardwareBuffer_fromHardwareBuffer( JNIEnv* env, jobject hardwareBufferObj) { - NDKHelpers::Init(); FML_CHECK(_AHardwareBuffer_fromHardwareBuffer != nullptr); return _AHardwareBuffer_fromHardwareBuffer(env, hardwareBufferObj); } void NDKHelpers::AHardwareBuffer_acquire(AHardwareBuffer* buffer) { - NDKHelpers::Init(); FML_CHECK(_AHardwareBuffer_acquire != nullptr); _AHardwareBuffer_acquire(buffer); } void NDKHelpers::AHardwareBuffer_release(AHardwareBuffer* buffer) { - NDKHelpers::Init(); FML_CHECK(_AHardwareBuffer_release != nullptr); _AHardwareBuffer_release(buffer); } void NDKHelpers::AHardwareBuffer_describe(AHardwareBuffer* buffer, AHardwareBuffer_Desc* desc) { - NDKHelpers::Init(); FML_CHECK(_AHardwareBuffer_describe != nullptr); _AHardwareBuffer_describe(buffer, desc); } std::optional NDKHelpers::AHardwareBuffer_getId( AHardwareBuffer* buffer) { - NDKHelpers::Init(); if (_AHardwareBuffer_getId == nullptr) { return std::nullopt; } @@ -129,7 +210,6 @@ std::optional NDKHelpers::AHardwareBuffer_getId( EGLClientBuffer NDKHelpers::eglGetNativeClientBufferANDROID( AHardwareBuffer* buffer) { - NDKHelpers::Init(); FML_CHECK(_eglGetNativeClientBufferANDROID != nullptr); return _eglGetNativeClientBufferANDROID(buffer); } diff --git a/shell/platform/android/ndk_helpers.h b/shell/platform/android/ndk_helpers.h index 0c7885758d6a5..5b7856aa6e241 100644 --- a/shell/platform/android/ndk_helpers.h +++ b/shell/platform/android/ndk_helpers.h @@ -10,16 +10,44 @@ #include "flutter/impeller/toolkit/egl/egl.h" +#include #include +#include +#include namespace flutter { using HardwareBufferKey = uint64_t; +enum class ChoreographerSupportStatus { + // Unavailable, API level < 24. + kUnsupported, + // Available, but only with postFrameCallback. + kSupported32, + // Available, but only with postFrameCallback64. + kSupported64, +}; + // A collection of NDK functions that are available depending on the version of // the Android SDK we are linked with at runtime. class NDKHelpers { public: + // Safe to call multiple times. + // Normally called from JNI_OnLoad. + static void Init(); + + // API Version 23 + static bool ATrace_isEnabled(); + + // API Version 24 + static ChoreographerSupportStatus ChoreographerSupported(); + static AChoreographer* AChoreographer_getInstance(); + // Deprecated in 29, available since 24. + static void AChoreographer_postFrameCallback( + AChoreographer* choreographer, + AChoreographer_frameCallback callback, + void* data); + // API Version 26 static bool HardwareBufferSupported(); static AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer( @@ -32,14 +60,17 @@ class NDKHelpers { static EGLClientBuffer eglGetNativeClientBufferANDROID( AHardwareBuffer* buffer); + // API Version 29 + static void AChoreographer_postFrameCallback64( + AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, + void* data); + // API Version 31 // Returns std::nullopt on API version 26 - 30. static std::optional AHardwareBuffer_getId( AHardwareBuffer* buffer); - - private: - static void Init(); }; } // namespace flutter diff --git a/shell/platform/android/vsync_waiter_android.cc b/shell/platform/android/vsync_waiter_android.cc index defde4340e443..7b7f136257ce2 100644 --- a/shell/platform/android/vsync_waiter_android.cc +++ b/shell/platform/android/vsync_waiter_android.cc @@ -13,7 +13,7 @@ #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/size.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/platform/android/android_choreographer.h" +#include "flutter/shell/platform/android/ndk_helpers.h" namespace flutter { @@ -22,34 +22,53 @@ static jmethodID g_async_wait_for_vsync_method_ = nullptr; static std::atomic_uint g_refresh_rate_ = 60; VsyncWaiterAndroid::VsyncWaiterAndroid(const flutter::TaskRunners& task_runners) - : VsyncWaiter(task_runners), - use_ndk_choreographer_( - AndroidChoreographer::ShouldUseNDKChoreographer()) {} + : VsyncWaiter(task_runners) {} VsyncWaiterAndroid::~VsyncWaiterAndroid() = default; // |VsyncWaiter| void VsyncWaiterAndroid::AwaitVSync() { - if (use_ndk_choreographer_) { - auto* weak_this = new std::weak_ptr(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(shared_from_this()); - jlong java_baton = reinterpret_cast(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 // - ); - }); + switch (NDKHelpers::ChoreographerSupported()) { + case ChoreographerSupportStatus::kSupported32: { + auto* weak_this = new std::weak_ptr(shared_from_this()); + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetUITaskRunner(), [weak_this]() { + NDKHelpers::AChoreographer_postFrameCallback( + NDKHelpers::AChoreographer_getInstance(), &OnVsyncFromNDK32, + weak_this); + }); + } break; + case ChoreographerSupportStatus::kSupported64: { + auto* weak_this = new std::weak_ptr(shared_from_this()); + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetUITaskRunner(), [weak_this]() { + NDKHelpers::AChoreographer_postFrameCallback64( + NDKHelpers::AChoreographer_getInstance(), &OnVsyncFromNDK, + weak_this); + }); + } break; + case ChoreographerSupportStatus::kUnsupported: { + // TODO(99798): Remove it when we drop support for API level < 29. + auto* weak_this = new std::weak_ptr(shared_from_this()); + jlong java_baton = reinterpret_cast(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 // + ); + }); + } break; } } +// static +void VsyncWaiterAndroid::OnVsyncFromNDK32( + long frame_nanos, // NOLINT to match a deprecated NDK interface. + void* data) { + OnVsyncFromNDK(frame_nanos, data); +} + // static void VsyncWaiterAndroid::OnVsyncFromNDK(int64_t frame_nanos, void* data) { auto frame_time = fml::TimePoint::FromEpochDelta( diff --git a/shell/platform/android/vsync_waiter_android.h b/shell/platform/android/vsync_waiter_android.h index dcc1657175534..69c3ad912839c 100644 --- a/shell/platform/android/vsync_waiter_android.h +++ b/shell/platform/android/vsync_waiter_android.h @@ -29,6 +29,9 @@ class VsyncWaiterAndroid final : public VsyncWaiter { void AwaitVSync() override; static void OnVsyncFromNDK(int64_t frame_nanos, void* data); + // This needs to match a deprecated NDK interface. + static void OnVsyncFromNDK32(long frame_nanos, // NOLINT + void* data); static void OnVsyncFromJava(JNIEnv* env, jclass jcaller, @@ -44,7 +47,6 @@ class VsyncWaiterAndroid final : public VsyncWaiter { jclass jcaller, jfloat refresh_rate); - const bool use_ndk_choreographer_; FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterAndroid); };