diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index f0f3333bb7f..5ce695d846c 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -1356,6 +1356,7 @@ FILE: ../../../flutter/shell/platform/android/android_surface_software.cc FILE: ../../../flutter/shell/platform/android/android_surface_software.h FILE: ../../../flutter/shell/platform/android/apk_asset_provider.cc FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h +FILE: ../../../flutter/shell/platform/android/apk_asset_provider_unittests.cc FILE: ../../../flutter/shell/platform/android/context/android_context.cc FILE: ../../../flutter/shell/platform/android/context/android_context.h FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc diff --git a/engine/src/flutter/shell/platform/android/BUILD.gn b/engine/src/flutter/shell/platform/android/BUILD.gn index ef89fe201b2..edb78d40445 100644 --- a/engine/src/flutter/shell/platform/android/BUILD.gn +++ b/engine/src/flutter/shell/platform/android/BUILD.gn @@ -41,6 +41,7 @@ executable("flutter_shell_native_unittests") { sources = [ "android_context_gl_unittests.cc", "android_shell_holder_unittests.cc", + "apk_asset_provider_unittests.cc", "flutter_shell_native_unittests.cc", ] public_configs = [ "//flutter:config" ] diff --git a/engine/src/flutter/shell/platform/android/android_shell_holder.cc b/engine/src/flutter/shell/platform/android/android_shell_holder.cc index 675c92a660e..3537de3ea20 100644 --- a/engine/src/flutter/shell/platform/android/android_shell_holder.cc +++ b/engine/src/flutter/shell/platform/android/android_shell_holder.cc @@ -259,8 +259,7 @@ std::unique_ptr AndroidShellHolder::Spawn( // TODO(xster): could be worth tracing this to investigate whether // the IsolateConfiguration could be cached somewhere. - auto config = BuildRunConfiguration(asset_manager_, entrypoint, libraryUrl, - entrypoint_args); + auto config = BuildRunConfiguration(entrypoint, libraryUrl, entrypoint_args); if (!config) { // If the RunConfiguration was null, the kernel blob wasn't readable. // Fail the whole thing. @@ -277,7 +276,7 @@ std::unique_ptr AndroidShellHolder::Spawn( } void AndroidShellHolder::Launch( - std::shared_ptr asset_manager, + std::unique_ptr apk_asset_provider, const std::string& entrypoint, const std::string& libraryUrl, const std::vector& entrypoint_args) { @@ -285,9 +284,8 @@ void AndroidShellHolder::Launch( return; } - asset_manager_ = asset_manager; - auto config = BuildRunConfiguration(asset_manager, entrypoint, libraryUrl, - entrypoint_args); + apk_asset_provider_ = std::move(apk_asset_provider); + auto config = BuildRunConfiguration(entrypoint, libraryUrl, entrypoint_args); if (!config) { return; } @@ -314,7 +312,6 @@ void AndroidShellHolder::NotifyLowMemoryWarning() { } std::optional AndroidShellHolder::BuildRunConfiguration( - std::shared_ptr asset_manager, const std::string& entrypoint, const std::string& libraryUrl, const std::vector& entrypoint_args) const { @@ -333,8 +330,8 @@ std::optional AndroidShellHolder::BuildRunConfiguration( IsolateConfiguration::CreateForKernel(std::move(kernel_blob)); } - RunConfiguration config(std::move(isolate_configuration), - std::move(asset_manager)); + RunConfiguration config(std::move(isolate_configuration)); + config.AddAssetResolver(apk_asset_provider_->Clone()); { if (!entrypoint.empty() && !libraryUrl.empty()) { diff --git a/engine/src/flutter/shell/platform/android/android_shell_holder.h b/engine/src/flutter/shell/platform/android/android_shell_holder.h index c8c52602677..bf14db6a242 100644 --- a/engine/src/flutter/shell/platform/android/android_shell_holder.h +++ b/engine/src/flutter/shell/platform/android/android_shell_holder.h @@ -15,6 +15,7 @@ #include "flutter/shell/common/run_configuration.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/android/apk_asset_provider.h" #include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "flutter/shell/platform/android/platform_message_handler_android.h" #include "flutter/shell/platform/android/platform_view_android.h" @@ -83,7 +84,7 @@ class AndroidShellHolder { const std::string& initial_route, const std::vector& entrypoint_args) const; - void Launch(std::shared_ptr asset_manager, + void Launch(std::unique_ptr apk_asset_provider, const std::string& entrypoint, const std::string& libraryUrl, const std::vector& entrypoint_args); @@ -95,8 +96,6 @@ class AndroidShellHolder { Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, bool base64_encode); - void UpdateAssetManager(fml::RefPtr asset_manager); - void NotifyLowMemoryWarning(); const std::shared_ptr& GetPlatformMessageHandler() @@ -112,7 +111,7 @@ class AndroidShellHolder { std::unique_ptr shell_; bool is_valid_ = false; uint64_t next_pointer_flow_id_ = 0; - std::shared_ptr asset_manager_; + std::unique_ptr apk_asset_provider_; //---------------------------------------------------------------------------- /// @brief Constructor with its components injected. @@ -132,7 +131,6 @@ class AndroidShellHolder { const fml::WeakPtr& platform_view); static void ThreadDestructCallback(void* value); std::optional BuildRunConfiguration( - std::shared_ptr asset_manager, const std::string& entrypoint, const std::string& libraryUrl, const std::vector& entrypoint_args) const; diff --git a/engine/src/flutter/shell/platform/android/apk_asset_provider.cc b/engine/src/flutter/shell/platform/android/apk_asset_provider.cc index 79372684f41..f0670fa8480 100644 --- a/engine/src/flutter/shell/platform/android/apk_asset_provider.cc +++ b/engine/src/flutter/shell/platform/android/apk_asset_provider.cc @@ -13,29 +13,6 @@ namespace flutter { -APKAssetProvider::APKAssetProvider(JNIEnv* env, - jobject jassetManager, - std::string directory) - : java_asset_manager_(env, jassetManager), - directory_(std::move(directory)) { - assetManager_ = AAssetManager_fromJava(env, jassetManager); -} - -APKAssetProvider::~APKAssetProvider() = default; - -bool APKAssetProvider::IsValid() const { - return true; -} - -bool APKAssetProvider::IsValidAfterAssetManagerChange() const { - return true; -} - -// |AssetResolver| -AssetResolver::AssetResolverType APKAssetProvider::GetType() const { - return AssetResolver::AssetResolverType::kApkAssetProvider; -} - class APKAssetMapping : public fml::Mapping { public: explicit APKAssetMapping(AAsset* asset) : asset_(asset) {} @@ -56,17 +33,73 @@ class APKAssetMapping : public fml::Mapping { FML_DISALLOW_COPY_AND_ASSIGN(APKAssetMapping); }; -std::unique_ptr APKAssetProvider::GetAsMapping( - const std::string& asset_name) const { - std::stringstream ss; - ss << directory_.c_str() << "/" << asset_name; - AAsset* asset = - AAssetManager_open(assetManager_, ss.str().c_str(), AASSET_MODE_BUFFER); - if (!asset) { - return nullptr; +class APKAssetProviderImpl : public APKAssetProviderInternal { + public: + explicit APKAssetProviderImpl(JNIEnv* env, + jobject jassetManager, + std::string directory) + : java_asset_manager_(env, jassetManager), + directory_(std::move(directory)) { + asset_manager_ = AAssetManager_fromJava(env, jassetManager); } - return std::make_unique(asset); + ~APKAssetProviderImpl() = default; + + std::unique_ptr GetAsMapping( + const std::string& asset_name) const override { + std::stringstream ss; + ss << directory_.c_str() << "/" << asset_name; + AAsset* asset = AAssetManager_open(asset_manager_, ss.str().c_str(), + AASSET_MODE_BUFFER); + if (!asset) { + return nullptr; + } + + return std::make_unique(asset); + }; + + private: + fml::jni::ScopedJavaGlobalRef java_asset_manager_; + AAssetManager* asset_manager_; + const std::string directory_; + + FML_DISALLOW_COPY_AND_ASSIGN(APKAssetProviderImpl); +}; + +APKAssetProvider::APKAssetProvider(JNIEnv* env, + jobject assetManager, + std::string directory) + : impl_(std::make_shared(env, + assetManager, + std::move(directory))) {} + +APKAssetProvider::APKAssetProvider( + std::shared_ptr impl) + : impl_(impl) {} + +// |AssetResolver| +bool APKAssetProvider::IsValid() const { + return true; +} + +// |AssetResolver| +bool APKAssetProvider::IsValidAfterAssetManagerChange() const { + return true; +} + +// |AssetResolver| +AssetResolver::AssetResolverType APKAssetProvider::GetType() const { + return AssetResolver::AssetResolverType::kApkAssetProvider; +} + +// |AssetResolver| +std::unique_ptr APKAssetProvider::GetAsMapping( + const std::string& asset_name) const { + return impl_->GetAsMapping(asset_name); +} + +std::unique_ptr APKAssetProvider::Clone() const { + return std::make_unique(impl_); } } // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/apk_asset_provider.h b/engine/src/flutter/shell/platform/android/apk_asset_provider.h index d1e7e2f707a..d11ee049a91 100644 --- a/engine/src/flutter/shell/platform/android/apk_asset_provider.h +++ b/engine/src/flutter/shell/platform/android/apk_asset_provider.h @@ -14,17 +14,37 @@ namespace flutter { +class APKAssetProviderInternal { + public: + virtual std::unique_ptr GetAsMapping( + const std::string& asset_name) const = 0; + + protected: + virtual ~APKAssetProviderInternal() = default; +}; + class APKAssetProvider final : public AssetResolver { public: explicit APKAssetProvider(JNIEnv* env, jobject assetManager, std::string directory); - ~APKAssetProvider() override; + + explicit APKAssetProvider(std::shared_ptr impl); + + ~APKAssetProvider() = default; + + // Returns a new 'std::unique_ptr' with the same 'impl_' as + // this provider. + std::unique_ptr Clone() const; + + // Obtain a raw pointer to the APKAssetProviderInternal. + // + // This method is intended for use in tests. Callers must not + // delete the returned pointer. + APKAssetProviderInternal* GetImpl() const { return impl_.get(); } private: - fml::jni::ScopedJavaGlobalRef java_asset_manager_; - AAssetManager* assetManager_; - const std::string directory_; + std::shared_ptr impl_; // |flutter::AssetResolver| bool IsValid() const override; diff --git a/engine/src/flutter/shell/platform/android/apk_asset_provider_unittests.cc b/engine/src/flutter/shell/platform/android/apk_asset_provider_unittests.cc new file mode 100644 index 00000000000..888e70b3743 --- /dev/null +++ b/engine/src/flutter/shell/platform/android/apk_asset_provider_unittests.cc @@ -0,0 +1,25 @@ +#include "flutter/shell/platform/android/apk_asset_provider.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +class MockAPKAssetProviderImpl : public APKAssetProviderInternal { + public: + MOCK_CONST_METHOD1( + GetAsMapping, + std::unique_ptr(const std::string& asset_name)); +}; + +TEST(APKAssetProvider, Clone) { + auto first_provider = std::make_unique( + std::make_shared()); + auto second_provider = std::make_unique( + std::make_shared()); + auto third_provider = first_provider->Clone(); + + ASSERT_NE(first_provider->GetImpl(), second_provider->GetImpl()); + ASSERT_EQ(first_provider->GetImpl(), third_provider->GetImpl()); +} +} // namespace testing +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc b/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc index 79bea738b6a..6f79175c8f8 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc +++ b/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc @@ -241,20 +241,17 @@ static void RunBundleAndSnapshotFromLibrary(JNIEnv* env, jstring jLibraryUrl, jobject jAssetManager, jobject jEntrypointArgs) { - auto asset_manager = std::make_shared(); - - asset_manager->PushBack(std::make_unique( - env, // jni environment - jAssetManager, // asset manager - fml::jni::JavaStringToString(env, jBundlePath)) // apk asset dir + auto apk_asset_provider = std::make_unique( + env, // jni environment + jAssetManager, // asset manager + fml::jni::JavaStringToString(env, jBundlePath) // apk asset dir ); - auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint); auto libraryUrl = fml::jni::JavaStringToString(env, jLibraryUrl); auto entrypoint_args = fml::jni::StringListToVector(env, jEntrypointArgs); - ANDROID_SHELL_HOLDER->Launch(asset_manager, entrypoint, libraryUrl, - entrypoint_args); + ANDROID_SHELL_HOLDER->Launch(std::move(apk_asset_provider), entrypoint, + libraryUrl, entrypoint_args); } static jobject LookupCallbackInformation(JNIEnv* env,