From 7a06558bd9db3ca6868018414395d4e1bde20846 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:05:52 -0700 Subject: [PATCH] Replace `System.loadLibrary` with `ReLinker.loadLibrary()` in `FlutterJNI.loadLibrary()` (flutter/engine#55095) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Could fix? https://github.com/flutter/flutter/issues/83596 The communication on https://issuetracker.google.com/issues/346717090#comment2 recommends using [ReLinker](https://github.com/KeepSafe/ReLinker) to avoid a bug in how library loading interacts with the [Play delivery feature](https://developer.android.com/guide/playcore/feature-delivery) (used in turn by Flutter's deferred components). The ReLinker docs also suggest that if you have `minSdk` less than `23`, then you should be using ReLinker regardless, as `System.loadLibrary` is unreliable for other reasons. I don't have any strong evidence to suggest that either one of these two root causes is the definitive cause of https://github.com/flutter/flutter/issues/83596, but it probably wouldn't hurt 𤷠[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- DEPS | 2 +- engine/src/flutter/shell/platform/android/BUILD.gn | 1 + .../android/io/flutter/embedding/engine/FlutterJNI.java | 6 +++--- .../io/flutter/embedding/engine/loader/FlutterLoader.java | 2 +- .../flutter/embedding/engine/loader/FlutterLoaderTest.java | 4 ++-- engine/src/flutter/tools/androidx/README.md | 3 +++ engine/src/flutter/tools/androidx/files.json | 6 ++++++ 7 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 engine/src/flutter/tools/androidx/README.md diff --git a/DEPS b/DEPS index db9ecbdd18b..af4dc1ffa88 100644 --- a/DEPS +++ b/DEPS @@ -780,7 +780,7 @@ deps = { 'packages': [ { 'package': 'flutter/android/embedding_bundle', - 'version': 'last_updated:2024-06-18T12:13:41-0700' + 'version': 'last_updated:2024-09-10T16:32:16-0700' } ], 'condition': 'download_android_deps', diff --git a/engine/src/flutter/shell/platform/android/BUILD.gn b/engine/src/flutter/shell/platform/android/BUILD.gn index 65797086ff0..6f062431cf7 100644 --- a/engine/src/flutter/shell/platform/android/BUILD.gn +++ b/engine/src/flutter/shell/platform/android/BUILD.gn @@ -394,6 +394,7 @@ embedding_dependencies_jars = [ "//flutter/third_party/android_embedding_dependencies/lib/viewpager-1.0.0.jar", "//flutter/third_party/android_embedding_dependencies/lib/window-1.2.0.jar", "//flutter/third_party/android_embedding_dependencies/lib/window-java-1.2.0.jar", + "//flutter/third_party/android_embedding_dependencies/lib/relinker-1.4.5.jar", ] action("check_imports") { diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 3c966d2f4fa..389e866829f 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -24,6 +24,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.annotation.VisibleForTesting; +import com.getkeepsafe.relinker.ReLinker; import io.flutter.Log; import io.flutter.embedding.engine.FlutterEngine.EngineLifecycleListener; import io.flutter.embedding.engine.dart.PlatformMessageHandler; @@ -139,12 +140,11 @@ public class FlutterJNI { * *
This method should only be called once across all FlutterJNI instances. */ - public void loadLibrary() { + public void loadLibrary(Context context) { if (FlutterJNI.loadLibraryCalled) { Log.w(TAG, "FlutterJNI.loadLibrary called more than once"); } - - System.loadLibrary("flutter"); + ReLinker.loadLibrary(context, "flutter"); FlutterJNI.loadLibraryCalled = true; } diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 70302e7f42a..9416bf18ab5 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -182,7 +182,7 @@ public class FlutterLoader { ResourceExtractor resourceExtractor = initResources(appContext); try { - flutterJNI.loadLibrary(); + flutterJNI.loadLibrary(appContext); } catch (UnsatisfiedLinkError unsatisfiedLinkError) { String couldntFindVersion = "couldn't find \"libflutter.so\""; String notFoundVersion = "dlopen failed: library \"libflutter.so\" not found"; diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java index 98d60d4b784..e403668887d 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java @@ -58,7 +58,7 @@ public class FlutterLoaderTest { flutterLoader.ensureInitializationComplete(ctx, null); shadowOf(getMainLooper()).idle(); assertTrue(flutterLoader.initialized()); - verify(mockFlutterJNI, times(1)).loadLibrary(); + verify(mockFlutterJNI, times(1)).loadLibrary(ctx); verify(mockFlutterJNI, times(1)).updateRefreshRate(); } @@ -70,7 +70,7 @@ public class FlutterLoaderTest { Mockito.doThrow(new UnsatisfiedLinkError("couldn't find \"libflutter.so\"")) .when(mockFlutterJNI) - .loadLibrary(); + .loadLibrary(ctx); try { flutterLoader.startInitialization(ctx); } catch (UnsupportedOperationException e) { diff --git a/engine/src/flutter/tools/androidx/README.md b/engine/src/flutter/tools/androidx/README.md new file mode 100644 index 00000000000..1471d12954b --- /dev/null +++ b/engine/src/flutter/tools/androidx/README.md @@ -0,0 +1,3 @@ +Defines the additional Android build time dependencies downloaded by `engine/tools/cipd/android_embedding_bundle`, which then get uploaded to CIPD and pulled by `gclient sync` into `third_party/android_embedding_dependencies/lib/`. + +Despite the directory name, `files.json` actually includes one non-androidx dependency: [ReLinker](https://github.com/KeepSafe/ReLinker). \ No newline at end of file diff --git a/engine/src/flutter/tools/androidx/files.json b/engine/src/flutter/tools/androidx/files.json index 3150c046717..a6a284a2741 100644 --- a/engine/src/flutter/tools/androidx/files.json +++ b/engine/src/flutter/tools/androidx/files.json @@ -86,5 +86,11 @@ "out_file_name": "core-1.10.3.aar", "maven_dependency": "com.google.android.play:core:1.10.3", "provides": [] + }, + { + "url": "https://repo1.maven.org/maven2/com/getkeepsafe/relinker/relinker/1.4.5/relinker-1.4.5.aar", + "out_file_name": "relinker-1.4.5.aar", + "maven_dependency": "com.getkeepsafe.relinker:relinker:1.4.5", + "provides": ["com.getkeepsafe.relinker.ReLinker"] } ]