From cd9045e33bfb0a1fba58c41f68dd4c1fb77fc1f1 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 13 Aug 2020 01:25:20 -0700 Subject: [PATCH 1/8] Start --- shell/platform/android/flutter_main.cc | 7 +++++-- .../android/io/flutter/embedding/engine/FlutterJNI.java | 3 ++- .../io/flutter/embedding/engine/loader/FlutterLoader.java | 6 +++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/shell/platform/android/flutter_main.cc b/shell/platform/android/flutter_main.cc index 1493bf4f0d161..596eda600bb44 100644 --- a/shell/platform/android/flutter_main.cc +++ b/shell/platform/android/flutter_main.cc @@ -63,7 +63,8 @@ void FlutterMain::Init(JNIEnv* env, jstring kernelPath, jstring appStoragePath, jstring engineCachesPath, - jlong initTimeMillis) { + jlong initTimeMillis, + jlong oldGenHeapSizeBytes) { std::vector args; args.push_back("flutter"); for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) { @@ -120,6 +121,8 @@ void FlutterMain::Init(JNIEnv* env, make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize); #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG + settings.old_gen_heap_size = static_cast(oldGenHeapSizeBytes); + // Not thread safe. Will be removed when FlutterMain is refactored to no // longer be a singleton. g_flutter_main.reset(new FlutterMain(std::move(settings))); @@ -166,7 +169,7 @@ bool FlutterMain::Register(JNIEnv* env) { { .name = "nativeInit", .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/" - "lang/String;Ljava/lang/String;Ljava/lang/String;J)V", + "lang/String;Ljava/lang/String;Ljava/lang/String;J;J)V", .fnPtr = reinterpret_cast(&Init), }, { diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 59fa7132e3008..3f809e569a932 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -111,7 +111,8 @@ public static native void nativeInit( @Nullable String bundlePath, @NonNull String appStoragePath, @NonNull String engineCachesPath, - long initTimeMillis); + long initTimeMillis, + long oldGenHeapSizeBytes); /** * Prefetch the default font manager provided by SkFontMgr::RefDefault() which is a process-wide diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 9156a64ef061e..cbd79a3d37598 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -244,13 +244,17 @@ public void ensureInitializationComplete( } } + ActivityManager activityManager = (ActivityManager)getSystemService(ACTIVITY_SERVICE); + long oldGenHeapSizeBytes = activityManager.getLargeMemoryClass(); + FlutterJNI.nativeInit( applicationContext, shellArgs.toArray(new String[0]), kernelPath, result.appStoragePath, result.engineCachesPath, - initTimeMillis); + initTimeMillis, + oldGenHeapSizeBytes); initialized = true; } catch (Exception e) { From de357b2efa3423ee46e9a92f741b3213d3d2c4fb Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 13 Aug 2020 01:30:08 -0700 Subject: [PATCH 2/8] bytes --- .../io/flutter/embedding/engine/loader/FlutterLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index cbd79a3d37598..8fc970d3805d0 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -245,7 +245,7 @@ public void ensureInitializationComplete( } ActivityManager activityManager = (ActivityManager)getSystemService(ACTIVITY_SERVICE); - long oldGenHeapSizeBytes = activityManager.getLargeMemoryClass(); + long oldGenHeapSizeBytes = activityManager.getLargeMemoryClass() * 1000000; FlutterJNI.nativeInit( applicationContext, From 834417bfe2fc03284411cf549ad552a975e0c34b Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 13 Aug 2020 01:32:36 -0700 Subject: [PATCH 3/8] .. --- .../android/io/flutter/embedding/engine/FlutterJNI.java | 2 +- .../io/flutter/embedding/engine/loader/FlutterLoader.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 3f809e569a932..8cd8139120cc1 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -112,7 +112,7 @@ public static native void nativeInit( @NonNull String appStoragePath, @NonNull String engineCachesPath, long initTimeMillis, - long oldGenHeapSizeBytes); + long oldGenHeapSizeMegaBytes); /** * Prefetch the default font manager provided by SkFontMgr::RefDefault() which is a process-wide diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 8fc970d3805d0..e4e02dfa1e21a 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -245,7 +245,7 @@ public void ensureInitializationComplete( } ActivityManager activityManager = (ActivityManager)getSystemService(ACTIVITY_SERVICE); - long oldGenHeapSizeBytes = activityManager.getLargeMemoryClass() * 1000000; + long oldGenHeapSizeMegaBytes = activityManager.getLargeMemoryClass(); FlutterJNI.nativeInit( applicationContext, @@ -254,7 +254,7 @@ public void ensureInitializationComplete( result.appStoragePath, result.engineCachesPath, initTimeMillis, - oldGenHeapSizeBytes); + oldGenHeapSizeMegaBytes); initialized = true; } catch (Exception e) { From 5bebd55cc9f6f5fd9a92c55e4f929db0eefda0c9 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Fri, 18 Sep 2020 11:52:52 -0700 Subject: [PATCH 4/8] testss --- shell/platform/android/flutter_main.cc | 6 +- shell/platform/android/flutter_main.h | 3 +- .../android/io/flutter/FlutterInjector.java | 30 +-------- .../flutter/embedding/engine/FlutterJNI.java | 64 ++++++++++++++++--- .../engine/loader/FlutterLoader.java | 43 ++++++++----- .../test/io/flutter/FlutterInjectorTest.java | 3 - .../embedding/engine/PluginComponentTest.java | 8 ++- .../engine/loader/FlutterLoaderTest.java | 37 ++++++++--- 8 files changed, 122 insertions(+), 72 deletions(-) diff --git a/shell/platform/android/flutter_main.cc b/shell/platform/android/flutter_main.cc index 596eda600bb44..690e57fb76f6a 100644 --- a/shell/platform/android/flutter_main.cc +++ b/shell/platform/android/flutter_main.cc @@ -64,7 +64,7 @@ void FlutterMain::Init(JNIEnv* env, jstring appStoragePath, jstring engineCachesPath, jlong initTimeMillis, - jlong oldGenHeapSizeBytes) { + jint oldGenHeapSizeMegaBytes) { std::vector args; args.push_back("flutter"); for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) { @@ -121,7 +121,7 @@ void FlutterMain::Init(JNIEnv* env, make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize); #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - settings.old_gen_heap_size = static_cast(oldGenHeapSizeBytes); + settings.old_gen_heap_size = static_cast(oldGenHeapSizeMegaBytes); // Not thread safe. Will be removed when FlutterMain is refactored to no // longer be a singleton. @@ -169,7 +169,7 @@ bool FlutterMain::Register(JNIEnv* env) { { .name = "nativeInit", .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/" - "lang/String;Ljava/lang/String;Ljava/lang/String;J;J)V", + "lang/String;Ljava/lang/String;Ljava/lang/String;J;I)V", .fnPtr = reinterpret_cast(&Init), }, { diff --git a/shell/platform/android/flutter_main.h b/shell/platform/android/flutter_main.h index 171800b3ec500..db86c6b971bef 100644 --- a/shell/platform/android/flutter_main.h +++ b/shell/platform/android/flutter_main.h @@ -36,7 +36,8 @@ class FlutterMain { jstring kernelPath, jstring appStoragePath, jstring engineCachesPath, - jlong initTimeMillis); + jlong initTimeMillis, + jint oldGenHeapSizeMegaBytes); void SetupObservatoryUriCallback(JNIEnv* env); diff --git a/shell/platform/android/io/flutter/FlutterInjector.java b/shell/platform/android/io/flutter/FlutterInjector.java index 7d944785c4f45..0fe80e058e17a 100644 --- a/shell/platform/android/io/flutter/FlutterInjector.java +++ b/shell/platform/android/io/flutter/FlutterInjector.java @@ -62,23 +62,12 @@ public static void reset() { instance = null; } - private FlutterInjector(boolean shouldLoadNative, @NonNull FlutterLoader flutterLoader) { - this.shouldLoadNative = shouldLoadNative; + private FlutterInjector(@NonNull FlutterLoader flutterLoader) { this.flutterLoader = flutterLoader; } - private boolean shouldLoadNative; private FlutterLoader flutterLoader; - /** - * Returns whether the Flutter Android engine embedding should load the native C++ engine. - * - *

Useful for testing since JVM tests via Robolectric can't load native libraries. - */ - public boolean shouldLoadNative() { - return shouldLoadNative; - } - /** Returns the {@link FlutterLoader} instance to use for the Flutter Android engine embedding. */ @NonNull public FlutterLoader flutterLoader() { @@ -92,20 +81,6 @@ public FlutterLoader flutterLoader() { *

Non-overriden values have reasonable defaults. */ public static final class Builder { - - private boolean shouldLoadNative = true; - /** - * Sets whether the Flutter Android engine embedding should load the native C++ engine. - * - *

Useful for testing since JVM tests via Robolectric can't load native libraries. - * - *

Defaults to true. - */ - public Builder setShouldLoadNative(boolean shouldLoadNative) { - this.shouldLoadNative = shouldLoadNative; - return this; - } - private FlutterLoader flutterLoader; /** * Sets a {@link FlutterLoader} override. @@ -130,8 +105,7 @@ private void fillDefaults() { public FlutterInjector build() { fillDefaults(); - System.out.println("should load native is " + shouldLoadNative); - return new FlutterInjector(shouldLoadNative, flutterLoader); + return new FlutterInjector(flutterLoader); } } } diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 8cd8139120cc1..c6a5bc253a6d9 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -94,6 +94,58 @@ */ @Keep public class FlutterJNI { + public static class FlutterJNILoader { + /** + * Loads the libflutter.so library. + * + *

This must be called before any other native methods, and can be overridden by tests to + * avoid loading native libraries. + */ + public void loadLibrary() { + System.loadLibrary("flutter"); + } + + /** + * Prefetch the default font manager provided by SkFontMgr::RefDefault() which is a process-wide + * singleton owned by Skia. Note that, the first call to SkFontMgr::RefDefault() will take + * noticeable time, but later calls will return a reference to the preexisting font manager. + */ + public void prefetchDefaultFontManager() { + FlutterJNI.nativePrefetchDefaultFontManager(); + } + + /** + * Perform one time initialization of the Dart VM and Flutter engine. + * + *

This method must be called only once. + * + * @param context The application context. + * @param args Arguments to the Dart VM/Flutter engine. + * @param bundlePath For JIT runtimes, the path to the Dart kernel file for the application. + * @param appStoragePath The path to the application data directory. + * @param engineCachesPath The path to the application cache directory. + * @param initTimeMillis The time, in milliseconds, taken for initialization. + * @param oldGenHeapSizeMegaBytes The maximum size for the old gen heap size. + */ + public void nativeInit( + @NonNull Context context, + @NonNull String[] args, + @Nullable String bundlePath, + @NonNull String appStoragePath, + @NonNull String engineCachesPath, + long initTimeMillis, + int oldGenHeapSizeMegaBytes) { + FlutterJNI.nativeInit( + context, + args, + bundlePath, + appStoragePath, + engineCachesPath, + initTimeMillis, + oldGenHeapSizeMegaBytes); + } + } + private static final String TAG = "FlutterJNI"; @Nullable private static AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate; @@ -104,22 +156,16 @@ public class FlutterJNI { // This is set from native code via JNI. @Nullable private static String observatoryUri; - // TODO(mattcarroll): add javadocs - public static native void nativeInit( + private static native void nativeInit( @NonNull Context context, @NonNull String[] args, @Nullable String bundlePath, @NonNull String appStoragePath, @NonNull String engineCachesPath, long initTimeMillis, - long oldGenHeapSizeMegaBytes); + int oldGenHeapSizeMegaBytes); - /** - * Prefetch the default font manager provided by SkFontMgr::RefDefault() which is a process-wide - * singleton owned by Skia. Note that, the first call to SkFontMgr::RefDefault() will take - * noticeable time, but later calls will return a reference to the preexisting font manager. - */ - public static native void nativePrefetchDefaultFontManager(); + private static native void nativePrefetchDefaultFontManager(); private native boolean nativeGetIsSoftwareRenderingEnabled(); diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 8c29ee62f1e44..64ba5e69cf6ec 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -4,6 +4,7 @@ package io.flutter.embedding.engine.loader; +import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -15,7 +16,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import io.flutter.BuildConfig; -import io.flutter.FlutterInjector; import io.flutter.embedding.engine.FlutterJNI; import io.flutter.util.PathUtils; import io.flutter.view.VsyncWaiter; @@ -60,10 +60,22 @@ public static FlutterLoader getInstance() { return instance; } + public FlutterLoader() { + this(null); + } + + public FlutterLoader(@Nullable FlutterJNI.FlutterJNILoader flutterJNILoader) { + if (flutterJNILoader == null) { + flutterJNILoader = new FlutterJNI.FlutterJNILoader(); + } + this.flutterJNILoader = flutterJNILoader; + } + private boolean initialized = false; @Nullable private Settings settings; private long initStartTimestampMillis; private FlutterApplicationInfo flutterApplicationInfo; + private FlutterJNI.FlutterJNILoader flutterJNILoader; private static class InitResult { final String appStoragePath; @@ -125,9 +137,7 @@ public void startInitialization(@NonNull Context applicationContext, @NonNull Se public InitResult call() { ResourceExtractor resourceExtractor = initResources(appContext); - if (FlutterInjector.instance().shouldLoadNative()) { - System.loadLibrary("flutter"); - } + flutterJNILoader.loadLibrary(); // Prefetch the default font manager as soon as possible on a background thread. // It helps to reduce time cost of engine setup that blocks the platform thread. @@ -136,7 +146,7 @@ public InitResult call() { new Runnable() { @Override public void run() { - FlutterJNI.nativePrefetchDefaultFontManager(); + flutterJNILoader.prefetchDefaultFontManager(); } }); @@ -225,21 +235,20 @@ public void ensureInitializationComplete( shellArgs.add("--log-tag=" + settings.getLogTag()); } - ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); - long oldGenHeapSizeMegaBytes = activityManager.getLargeMemoryClass(); + ActivityManager activityManager = + (ActivityManager) applicationContext.getSystemService(Context.ACTIVITY_SERVICE); + int oldGenHeapSizeMegaBytes = activityManager.getLargeMemoryClass(); long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis; - if (FlutterInjector.instance().shouldLoadNative()) { - FlutterJNI.nativeInit( - applicationContext, - shellArgs.toArray(new String[0]), - kernelPath, - result.appStoragePath, - result.engineCachesPath, - initTimeMillis, - oldGenHeapSizeMegaBytes); - } + flutterJNILoader.nativeInit( + applicationContext, + shellArgs.toArray(new String[0]), + kernelPath, + result.appStoragePath, + result.engineCachesPath, + initTimeMillis, + oldGenHeapSizeMegaBytes); initialized = true; } catch (Exception e) { diff --git a/shell/platform/android/test/io/flutter/FlutterInjectorTest.java b/shell/platform/android/test/io/flutter/FlutterInjectorTest.java index 225c24959e136..9809095a0746d 100644 --- a/shell/platform/android/test/io/flutter/FlutterInjectorTest.java +++ b/shell/platform/android/test/io/flutter/FlutterInjectorTest.java @@ -7,7 +7,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; import io.flutter.embedding.engine.loader.FlutterLoader; import org.junit.Before; @@ -35,7 +34,6 @@ public void itHasSomeReasonableDefaults() { // Implicitly builds when first accessed. FlutterInjector injector = FlutterInjector.instance(); assertNotNull(injector.flutterLoader()); - assertTrue(injector.shouldLoadNative()); } @Test @@ -44,7 +42,6 @@ public void canPartiallyOverride() { new FlutterInjector.Builder().setFlutterLoader(mockFlutterLoader).build()); FlutterInjector injector = FlutterInjector.instance(); assertEquals(injector.flutterLoader(), mockFlutterLoader); - assertTrue(injector.shouldLoadNative()); } @Test() diff --git a/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java b/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java index 71f47890245bc..d800eaf095fe2 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java @@ -32,11 +32,15 @@ public void setUp() { @Test public void pluginsCanAccessFlutterAssetPaths() { // Setup test. - FlutterInjector.setInstance(new FlutterInjector.Builder().setShouldLoadNative(false).build()); + FlutterJNI.FlutterJNILoader mockFlutterJNILoader = mock(FlutterJNI.FlutterJNILoader.class); + FlutterInjector.setInstance( + new FlutterInjector.Builder() + .setFlutterLoader(new FlutterLoader(mockFlutterJNILoader)) + .build()); FlutterJNI flutterJNI = mock(FlutterJNI.class); when(flutterJNI.isAttached()).thenReturn(true); - FlutterLoader flutterLoader = new FlutterLoader(); + FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNILoader); // Execute behavior under test. FlutterEngine flutterEngine = diff --git a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java index 4ffd848d855b7..214887b5fe303 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java @@ -4,11 +4,21 @@ package io.flutter.embedding.engine.loader; +import static android.os.Looper.getMainLooper; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.robolectric.Shadows.shadowOf; -import io.flutter.FlutterInjector; -import org.junit.Before; +import android.app.ActivityManager; +import android.content.Context; +import io.flutter.embedding.engine.FlutterJNI; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -18,10 +28,6 @@ @Config(manifest = Config.NONE) @RunWith(RobolectricTestRunner.class) public class FlutterLoaderTest { - @Before - public void setUp() { - FlutterInjector.reset(); - } @Test public void itReportsUninitializedAfterCreating() { @@ -31,13 +37,26 @@ public void itReportsUninitializedAfterCreating() { @Test public void itReportsInitializedAfterInitializing() { - FlutterInjector.setInstance(new FlutterInjector.Builder().setShouldLoadNative(false).build()); - FlutterLoader flutterLoader = new FlutterLoader(); + FlutterJNI.FlutterJNILoader mockFlutterJNILoader = mock(FlutterJNI.FlutterJNILoader.class); + FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNILoader); assertFalse(flutterLoader.initialized()); flutterLoader.startInitialization(RuntimeEnvironment.application); flutterLoader.ensureInitializationComplete(RuntimeEnvironment.application, null); + shadowOf(getMainLooper()).idle(); assertTrue(flutterLoader.initialized()); - FlutterInjector.reset(); + verify(mockFlutterJNILoader, times(1)).loadLibrary(); + + ActivityManager activityManager = + (ActivityManager) RuntimeEnvironment.application.getSystemService(Context.ACTIVITY_SERVICE); + verify(mockFlutterJNILoader, times(1)) + .nativeInit( + eq(RuntimeEnvironment.application), + any(), + anyString(), + anyString(), + anyString(), + anyLong(), + eq(activityManager.getLargeMemoryClass())); } } From 0847dcd011c5fb9865e8a09d9efebc8cc1073619 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Fri, 18 Sep 2020 15:33:03 -0700 Subject: [PATCH 5/8] shell args --- shell/common/switches.cc | 6 ++++++ shell/common/switches.h | 3 +++ shell/platform/android/flutter_main.cc | 7 ++----- shell/platform/android/flutter_main.h | 3 +-- .../io/flutter/embedding/engine/FlutterJNI.java | 15 +++------------ .../embedding/engine/loader/FlutterLoader.java | 4 ++-- .../engine/loader/FlutterLoaderTest.java | 12 ++++++++---- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/shell/common/switches.cc b/shell/common/switches.cc index 1b2398b942ff0..80ac59ade511e 100644 --- a/shell/common/switches.cc +++ b/shell/common/switches.cc @@ -401,6 +401,12 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) { settings.purge_persistent_cache = command_line.HasOption(FlagForSwitch(Switch::PurgePersistentCache)); + if (command_line.HasOption(FlagForSwitch(Switch::OldGenHeapSize))) { + std::string old_gen_heap_size; + command_line.GetOptionValue(FlagForSwitch(Switch::OldGenHeapSize), + &old_gen_heap_size); + settings.old_gen_heap_size = std::stoi(old_gen_heap_size); + } return settings; } diff --git a/shell/common/switches.h b/shell/common/switches.h index f33e2722403df..9d292e1759b5f 100644 --- a/shell/common/switches.h +++ b/shell/common/switches.h @@ -196,6 +196,9 @@ DEF_SWITCH( "Uses separate threads for the platform, UI, GPU and IO task runners. " "By default, a single thread is used for all task runners. Only available " "in the flutter_tester.") +DEF_SWITCH(OldGenHeapSize, + "old-gen-heap-size", + "The size limit in megabytes for the Dart VM old gen heap space.") DEF_SWITCHES_END diff --git a/shell/platform/android/flutter_main.cc b/shell/platform/android/flutter_main.cc index 690e57fb76f6a..1493bf4f0d161 100644 --- a/shell/platform/android/flutter_main.cc +++ b/shell/platform/android/flutter_main.cc @@ -63,8 +63,7 @@ void FlutterMain::Init(JNIEnv* env, jstring kernelPath, jstring appStoragePath, jstring engineCachesPath, - jlong initTimeMillis, - jint oldGenHeapSizeMegaBytes) { + jlong initTimeMillis) { std::vector args; args.push_back("flutter"); for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) { @@ -121,8 +120,6 @@ void FlutterMain::Init(JNIEnv* env, make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize); #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - settings.old_gen_heap_size = static_cast(oldGenHeapSizeMegaBytes); - // Not thread safe. Will be removed when FlutterMain is refactored to no // longer be a singleton. g_flutter_main.reset(new FlutterMain(std::move(settings))); @@ -169,7 +166,7 @@ bool FlutterMain::Register(JNIEnv* env) { { .name = "nativeInit", .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/" - "lang/String;Ljava/lang/String;Ljava/lang/String;J;I)V", + "lang/String;Ljava/lang/String;Ljava/lang/String;J)V", .fnPtr = reinterpret_cast(&Init), }, { diff --git a/shell/platform/android/flutter_main.h b/shell/platform/android/flutter_main.h index db86c6b971bef..171800b3ec500 100644 --- a/shell/platform/android/flutter_main.h +++ b/shell/platform/android/flutter_main.h @@ -36,8 +36,7 @@ class FlutterMain { jstring kernelPath, jstring appStoragePath, jstring engineCachesPath, - jlong initTimeMillis, - jint oldGenHeapSizeMegaBytes); + jlong initTimeMillis); void SetupObservatoryUriCallback(JNIEnv* env); diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index c6a5bc253a6d9..cf32313b30dba 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -125,7 +125,6 @@ public void prefetchDefaultFontManager() { * @param appStoragePath The path to the application data directory. * @param engineCachesPath The path to the application cache directory. * @param initTimeMillis The time, in milliseconds, taken for initialization. - * @param oldGenHeapSizeMegaBytes The maximum size for the old gen heap size. */ public void nativeInit( @NonNull Context context, @@ -133,16 +132,9 @@ public void nativeInit( @Nullable String bundlePath, @NonNull String appStoragePath, @NonNull String engineCachesPath, - long initTimeMillis, - int oldGenHeapSizeMegaBytes) { + long initTimeMillis) { FlutterJNI.nativeInit( - context, - args, - bundlePath, - appStoragePath, - engineCachesPath, - initTimeMillis, - oldGenHeapSizeMegaBytes); + context, args, bundlePath, appStoragePath, engineCachesPath, initTimeMillis); } } @@ -162,8 +154,7 @@ private static native void nativeInit( @Nullable String bundlePath, @NonNull String appStoragePath, @NonNull String engineCachesPath, - long initTimeMillis, - int oldGenHeapSizeMegaBytes); + long initTimeMillis); private static native void nativePrefetchDefaultFontManager(); diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 64ba5e69cf6ec..0d5950d916929 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -238,6 +238,7 @@ public void ensureInitializationComplete( ActivityManager activityManager = (ActivityManager) applicationContext.getSystemService(Context.ACTIVITY_SERVICE); int oldGenHeapSizeMegaBytes = activityManager.getLargeMemoryClass(); + shellArgs.add("--old-gen-heap-size=" + oldGenHeapSizeMegaBytes); long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis; @@ -247,8 +248,7 @@ public void ensureInitializationComplete( kernelPath, result.appStoragePath, result.engineCachesPath, - initTimeMillis, - oldGenHeapSizeMegaBytes); + initTimeMillis); initialized = true; } catch (Exception e) { diff --git a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java index 214887b5fe303..36ab7c9bcce6f 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java @@ -7,7 +7,6 @@ import static android.os.Looper.getMainLooper; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; -import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.eq; @@ -19,8 +18,10 @@ import android.app.ActivityManager; import android.content.Context; import io.flutter.embedding.engine.FlutterJNI; +import java.util.*; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -49,14 +50,17 @@ public void itReportsInitializedAfterInitializing() { ActivityManager activityManager = (ActivityManager) RuntimeEnvironment.application.getSystemService(Context.ACTIVITY_SERVICE); + final String oldGenHeapArg = "--old-gen-heap-size=" + activityManager.getLargeMemoryClass(); + ArgumentCaptor shellArgsCaptor = ArgumentCaptor.forClass(String[].class); verify(mockFlutterJNILoader, times(1)) .nativeInit( eq(RuntimeEnvironment.application), - any(), + shellArgsCaptor.capture(), anyString(), anyString(), anyString(), - anyLong(), - eq(activityManager.getLargeMemoryClass())); + anyLong()); + List arguments = Arrays.asList(shellArgsCaptor.getValue()); + assertTrue(arguments.contains(oldGenHeapArg)); } } From f2a9f8488e1bbf9693e331262916cdca5caa3b08 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Mon, 21 Sep 2020 11:57:38 -0700 Subject: [PATCH 6/8] make it simpler --- .../flutter/embedding/engine/FlutterJNI.java | 90 ++++++++++--------- .../engine/loader/FlutterLoader.java | 8 +- .../embedding/engine/PluginComponentTest.java | 2 +- .../engine/loader/FlutterLoaderTest.java | 4 +- 4 files changed, 54 insertions(+), 50 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index cf32313b30dba..c41d0a668538b 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -94,51 +94,51 @@ */ @Keep public class FlutterJNI { - public static class FlutterJNILoader { - /** - * Loads the libflutter.so library. - * - *

This must be called before any other native methods, and can be overridden by tests to - * avoid loading native libraries. - */ - public void loadLibrary() { - System.loadLibrary("flutter"); - } + private static final String TAG = "FlutterJNI"; - /** - * Prefetch the default font manager provided by SkFontMgr::RefDefault() which is a process-wide - * singleton owned by Skia. Note that, the first call to SkFontMgr::RefDefault() will take - * noticeable time, but later calls will return a reference to the preexisting font manager. - */ - public void prefetchDefaultFontManager() { - FlutterJNI.nativePrefetchDefaultFontManager(); - } + // BEGIN Methods related to loading for FlutterLoader. + /** + * Loads the libflutter.so library. + * + *

This must be called before any other native methods, and can be overridden by tests to avoid + * loading native libraries. + */ + public void loadLibrary() { + System.loadLibrary("flutter"); + } - /** - * Perform one time initialization of the Dart VM and Flutter engine. - * - *

This method must be called only once. - * - * @param context The application context. - * @param args Arguments to the Dart VM/Flutter engine. - * @param bundlePath For JIT runtimes, the path to the Dart kernel file for the application. - * @param appStoragePath The path to the application data directory. - * @param engineCachesPath The path to the application cache directory. - * @param initTimeMillis The time, in milliseconds, taken for initialization. - */ - public void nativeInit( - @NonNull Context context, - @NonNull String[] args, - @Nullable String bundlePath, - @NonNull String appStoragePath, - @NonNull String engineCachesPath, - long initTimeMillis) { - FlutterJNI.nativeInit( - context, args, bundlePath, appStoragePath, engineCachesPath, initTimeMillis); - } + /** + * Prefetch the default font manager provided by SkFontMgr::RefDefault() which is a process-wide + * singleton owned by Skia. Note that, the first call to SkFontMgr::RefDefault() will take + * noticeable time, but later calls will return a reference to the preexisting font manager. + */ + public void prefetchDefaultFontManager() { + FlutterJNI.nativePrefetchDefaultFontManager(); } - private static final String TAG = "FlutterJNI"; + /** + * Perform one time initialization of the Dart VM and Flutter engine. + * + *

This method must be called only once. + * + * @param context The application context. + * @param args Arguments to the Dart VM/Flutter engine. + * @param bundlePath For JIT runtimes, the path to the Dart kernel file for the application. + * @param appStoragePath The path to the application data directory. + * @param engineCachesPath The path to the application cache directory. + * @param initTimeMillis The time, in milliseconds, taken for initialization. + */ + public void init( + @NonNull Context context, + @NonNull String[] args, + @Nullable String bundlePath, + @NonNull String appStoragePath, + @NonNull String engineCachesPath, + long initTimeMillis) { + FlutterJNI.nativeInit( + context, args, bundlePath, appStoragePath, engineCachesPath, initTimeMillis); + } + // END methods related to FlutterLoader @Nullable private static AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate; // This should also be updated by FlutterView when it is attached to a Display. @@ -148,7 +148,9 @@ public void nativeInit( // This is set from native code via JNI. @Nullable private static String observatoryUri; - private static native void nativeInit( + /** @deprecated Use {@link #init(Context, String[], String, String, String, long)} instead. */ + @Deprecated + public static native void nativeInit( @NonNull Context context, @NonNull String[] args, @Nullable String bundlePath, @@ -156,7 +158,9 @@ private static native void nativeInit( @NonNull String engineCachesPath, long initTimeMillis); - private static native void nativePrefetchDefaultFontManager(); + /** @deprecated Use {@link #prefetchDefaultFontManager()} instead. */ + @Deprecated + public static native void nativePrefetchDefaultFontManager(); private native boolean nativeGetIsSoftwareRenderingEnabled(); diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 0d5950d916929..47bd1523078d8 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -64,9 +64,9 @@ public FlutterLoader() { this(null); } - public FlutterLoader(@Nullable FlutterJNI.FlutterJNILoader flutterJNILoader) { + public FlutterLoader(@Nullable FlutterJNI flutterJNILoader) { if (flutterJNILoader == null) { - flutterJNILoader = new FlutterJNI.FlutterJNILoader(); + flutterJNILoader = new FlutterJNI(); } this.flutterJNILoader = flutterJNILoader; } @@ -75,7 +75,7 @@ public FlutterLoader(@Nullable FlutterJNI.FlutterJNILoader flutterJNILoader) { @Nullable private Settings settings; private long initStartTimestampMillis; private FlutterApplicationInfo flutterApplicationInfo; - private FlutterJNI.FlutterJNILoader flutterJNILoader; + private FlutterJNI flutterJNILoader; private static class InitResult { final String appStoragePath; @@ -242,7 +242,7 @@ public void ensureInitializationComplete( long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis; - flutterJNILoader.nativeInit( + flutterJNILoader.init( applicationContext, shellArgs.toArray(new String[0]), kernelPath, diff --git a/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java b/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java index d800eaf095fe2..7d76914bc295c 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java @@ -32,7 +32,7 @@ public void setUp() { @Test public void pluginsCanAccessFlutterAssetPaths() { // Setup test. - FlutterJNI.FlutterJNILoader mockFlutterJNILoader = mock(FlutterJNI.FlutterJNILoader.class); + FlutterJNI mockFlutterJNILoader = mock(FlutterJNI.class); FlutterInjector.setInstance( new FlutterInjector.Builder() .setFlutterLoader(new FlutterLoader(mockFlutterJNILoader)) diff --git a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java index 36ab7c9bcce6f..f09719d1ae88a 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java @@ -38,7 +38,7 @@ public void itReportsUninitializedAfterCreating() { @Test public void itReportsInitializedAfterInitializing() { - FlutterJNI.FlutterJNILoader mockFlutterJNILoader = mock(FlutterJNI.FlutterJNILoader.class); + FlutterJNI mockFlutterJNILoader = mock(FlutterJNI.class); FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNILoader); assertFalse(flutterLoader.initialized()); @@ -53,7 +53,7 @@ public void itReportsInitializedAfterInitializing() { final String oldGenHeapArg = "--old-gen-heap-size=" + activityManager.getLargeMemoryClass(); ArgumentCaptor shellArgsCaptor = ArgumentCaptor.forClass(String[].class); verify(mockFlutterJNILoader, times(1)) - .nativeInit( + .init( eq(RuntimeEnvironment.application), shellArgsCaptor.capture(), anyString(), From 0a345dd311fcdec4f1f652b7828bb8925b8954de Mon Sep 17 00:00:00 2001 From: Dan Field Date: Mon, 21 Sep 2020 21:44:49 -0700 Subject: [PATCH 7/8] xster review --- .../flutter/embedding/engine/FlutterJNI.java | 2 +- .../engine/loader/FlutterLoader.java | 24 +++++++++++-------- .../embedding/engine/PluginComponentTest.java | 8 +++---- .../engine/loader/FlutterLoaderTest.java | 22 +++++++++++++---- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index c41d0a668538b..f566b2210ce70 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -98,7 +98,7 @@ public class FlutterJNI { // BEGIN Methods related to loading for FlutterLoader. /** - * Loads the libflutter.so library. + * Loads the libflutter.so C++ library. * *

This must be called before any other native methods, and can be overridden by tests to avoid * loading native libraries. diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 47bd1523078d8..44c0ae3dabbff 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -60,22 +60,26 @@ public static FlutterLoader getInstance() { return instance; } + /** Creates a {@code FlutterLoader} that uses a default constructed {@link FlutterJNI}. */ public FlutterLoader() { - this(null); + this(new FlutterJNI()); } - public FlutterLoader(@Nullable FlutterJNI flutterJNILoader) { - if (flutterJNILoader == null) { - flutterJNILoader = new FlutterJNI(); - } - this.flutterJNILoader = flutterJNILoader; + /** + * Creates a {@code FlutterLoader} with the specified {@link FlutterJNI}. + * + * @param flutterJNI The {@link FlutterJNI} instance to use for loading the libflutter.so C++ + * library, setting up the font manager, and calling into C++ initalization. + */ + public FlutterLoader(@NonNull FlutterJNI flutterJNI) { + this.flutterJNI = flutterJNI; } private boolean initialized = false; @Nullable private Settings settings; private long initStartTimestampMillis; private FlutterApplicationInfo flutterApplicationInfo; - private FlutterJNI flutterJNILoader; + private FlutterJNI flutterJNI; private static class InitResult { final String appStoragePath; @@ -137,7 +141,7 @@ public void startInitialization(@NonNull Context applicationContext, @NonNull Se public InitResult call() { ResourceExtractor resourceExtractor = initResources(appContext); - flutterJNILoader.loadLibrary(); + flutterJNI.loadLibrary(); // Prefetch the default font manager as soon as possible on a background thread. // It helps to reduce time cost of engine setup that blocks the platform thread. @@ -146,7 +150,7 @@ public InitResult call() { new Runnable() { @Override public void run() { - flutterJNILoader.prefetchDefaultFontManager(); + flutterJNI.prefetchDefaultFontManager(); } }); @@ -242,7 +246,7 @@ public void ensureInitializationComplete( long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis; - flutterJNILoader.init( + flutterJNI.init( applicationContext, shellArgs.toArray(new String[0]), kernelPath, diff --git a/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java b/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java index 7d76914bc295c..138e36c766f0c 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/PluginComponentTest.java @@ -32,15 +32,13 @@ public void setUp() { @Test public void pluginsCanAccessFlutterAssetPaths() { // Setup test. - FlutterJNI mockFlutterJNILoader = mock(FlutterJNI.class); + FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); FlutterInjector.setInstance( - new FlutterInjector.Builder() - .setFlutterLoader(new FlutterLoader(mockFlutterJNILoader)) - .build()); + new FlutterInjector.Builder().setFlutterLoader(new FlutterLoader(mockFlutterJNI)).build()); FlutterJNI flutterJNI = mock(FlutterJNI.class); when(flutterJNI.isAttached()).thenReturn(true); - FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNILoader); + FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI); // Execute behavior under test. FlutterEngine flutterEngine = diff --git a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java index f09719d1ae88a..f188118d56f23 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java @@ -18,7 +18,8 @@ import android.app.ActivityManager; import android.content.Context; import io.flutter.embedding.engine.FlutterJNI; -import java.util.*; +import java.util.Arrays; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -38,21 +39,32 @@ public void itReportsUninitializedAfterCreating() { @Test public void itReportsInitializedAfterInitializing() { - FlutterJNI mockFlutterJNILoader = mock(FlutterJNI.class); - FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNILoader); + FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); + FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI); assertFalse(flutterLoader.initialized()); flutterLoader.startInitialization(RuntimeEnvironment.application); flutterLoader.ensureInitializationComplete(RuntimeEnvironment.application, null); shadowOf(getMainLooper()).idle(); assertTrue(flutterLoader.initialized()); - verify(mockFlutterJNILoader, times(1)).loadLibrary(); + verify(mockFlutterJNI, times(1)).loadLibrary(); + } + + @Test + public void itSetsTheOldGenHeapSizeAppropriately() { + FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); + FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI); + + assertFalse(flutterLoader.initialized()); + flutterLoader.startInitialization(RuntimeEnvironment.application); + flutterLoader.ensureInitializationComplete(RuntimeEnvironment.application, null); + shadowOf(getMainLooper()).idle(); ActivityManager activityManager = (ActivityManager) RuntimeEnvironment.application.getSystemService(Context.ACTIVITY_SERVICE); final String oldGenHeapArg = "--old-gen-heap-size=" + activityManager.getLargeMemoryClass(); ArgumentCaptor shellArgsCaptor = ArgumentCaptor.forClass(String[].class); - verify(mockFlutterJNILoader, times(1)) + verify(mockFlutterJNI, times(1)) .init( eq(RuntimeEnvironment.application), shellArgsCaptor.capture(), From a118c90091272eb3849e5e9fea4d120fb6189f93 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 12 Nov 2020 11:39:57 -0800 Subject: [PATCH 8/8] Use totalMem and allow it to be overridden in manifest --- .../engine/loader/FlutterLoader.java | 25 ++++++++++++++++--- .../engine/loader/FlutterLoaderTest.java | 7 ++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 7643fc415e801..95e96d3473e05 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -6,8 +6,10 @@ import android.app.ActivityManager; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; @@ -29,6 +31,9 @@ public class FlutterLoader { private static final String TAG = "FlutterLoader"; + private static final String OLD_GEN_HEAP_SIZE_META_DATA_KEY = + "io.flutter.embedding.android.OldGenHeapSize"; + // Must match values in flutter::switches static final String AOT_SHARED_LIBRARY_NAME = "aot-shared-library-name"; static final String SNAPSHOT_ASSET_PATH_KEY = "snapshot-asset-path"; @@ -239,9 +244,23 @@ public void ensureInitializationComplete( shellArgs.add("--log-tag=" + settings.getLogTag()); } - ActivityManager activityManager = - (ActivityManager) applicationContext.getSystemService(Context.ACTIVITY_SERVICE); - int oldGenHeapSizeMegaBytes = activityManager.getLargeMemoryClass(); + ApplicationInfo applicationInfo = + applicationContext + .getPackageManager() + .getApplicationInfo( + applicationContext.getPackageName(), PackageManager.GET_META_DATA); + Bundle metaData = applicationInfo.metaData; + int oldGenHeapSizeMegaBytes = + metaData != null ? metaData.getInt(OLD_GEN_HEAP_SIZE_META_DATA_KEY) : 0; + if (oldGenHeapSizeMegaBytes == 0) { + // default to half of total memory. + ActivityManager activityManager = + (ActivityManager) applicationContext.getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); + activityManager.getMemoryInfo(memInfo); + oldGenHeapSizeMegaBytes = (int) (memInfo.totalMem / 1e6 / 2); + } + shellArgs.add("--old-gen-heap-size=" + oldGenHeapSizeMegaBytes); long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis; diff --git a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java index f188118d56f23..c7c6c3afd39ec 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java @@ -51,7 +51,7 @@ public void itReportsInitializedAfterInitializing() { } @Test - public void itSetsTheOldGenHeapSizeAppropriately() { + public void itDefaultsTheOldGenHeapSizeAppropriately() { FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); FlutterLoader flutterLoader = new FlutterLoader(mockFlutterJNI); @@ -62,7 +62,10 @@ public void itSetsTheOldGenHeapSizeAppropriately() { ActivityManager activityManager = (ActivityManager) RuntimeEnvironment.application.getSystemService(Context.ACTIVITY_SERVICE); - final String oldGenHeapArg = "--old-gen-heap-size=" + activityManager.getLargeMemoryClass(); + ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); + activityManager.getMemoryInfo(memInfo); + int oldGenHeapSizeMegaBytes = (int) (memInfo.totalMem / 1e6 / 2); + final String oldGenHeapArg = "--old-gen-heap-size=" + oldGenHeapSizeMegaBytes; ArgumentCaptor shellArgsCaptor = ArgumentCaptor.forClass(String[].class); verify(mockFlutterJNI, times(1)) .init(