Merge branch 'fix_flutter_shell_args' into reland_flags

This commit is contained in:
Camille Simon 2026-02-17 11:34:02 -08:00
commit 3c8649f248
24 changed files with 859 additions and 795 deletions

View File

@ -9,7 +9,7 @@ All flags available on Android can be set via the command line **and** via
manifest metadata. See `src/flutter/shell/common/switches.cc` for
the list of all supported flags, and see
`src/flutter/shell/platform/android/io/flutter/embedding/engine/`
`FlutterShellArgs.java` for the list of flags that can be set for the
`FlutterEngineFlags.java` for the list of flags that can be set for the
Android shell.
## When to use manifest metadata versus the command line
@ -58,7 +58,7 @@ All manifest metadata keys must be prefixed with the package name
`io.flutter.embedding.android` and are suffixed with the metadata name for the
related command line flag as determined in
`src/flutter/shell/platform/android/io/flutter/embedding/engine/`
`FlutterShellArgs.java`. For example, the `--impeller-lazy-shader-mode=`
`FlutterEngineFlags.java`. For example, the `--impeller-lazy-shader-mode=`
command line flag corresponds to the metadata key
`io.flutter.embedding.android.ImpellerLazyShaderInitialization`.
@ -93,7 +93,7 @@ Set the `--enable-flutter-gpu` flag:
- Some flags are not allowed in release mode. The Android embedding enforces
this policy (see `src/flutter/shell/platform/android/io/flutter/
embedding/engine/FlutterShellArgs`, which marks allowed flags
embedding/engine/FlutterEngineFlags`, which marks allowed flags
with `allowedInRelease`). If a disallowed flag is set in release, it will
be ignored.
- If you need different behavior in release vs debug/profile mode, configure it

View File

@ -250,12 +250,12 @@ android_java_sources = [
"io/flutter/embedding/engine/FlutterEngine.java",
"io/flutter/embedding/engine/FlutterEngineCache.java",
"io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java",
"io/flutter/embedding/engine/FlutterEngineFlags.java",
"io/flutter/embedding/engine/FlutterEngineGroup.java",
"io/flutter/embedding/engine/FlutterEngineGroupCache.java",
"io/flutter/embedding/engine/FlutterJNI.java",
"io/flutter/embedding/engine/FlutterOverlaySurface.java",
"io/flutter/embedding/engine/FlutterShellArgs.java",
"io/flutter/embedding/engine/FlutterShellArgsIntentUtils.java",
"io/flutter/embedding/engine/dart/DartExecutor.java",
"io/flutter/embedding/engine/dart/DartMessenger.java",
"io/flutter/embedding/engine/dart/PlatformMessageHandler.java",

View File

@ -49,7 +49,7 @@ import androidx.lifecycle.LifecycleRegistry;
import io.flutter.Log;
import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterShellArgsIntentUtils;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.plugins.activity.ActivityControlSurface;
import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister;
import io.flutter.plugin.platform.PlatformPlugin;
@ -1042,8 +1042,8 @@ public class FlutterActivity extends Activity
*/
@NonNull
@Override
public String[] getFlutterShellArgs() {
return FlutterShellArgsIntentUtils.getFlutterShellCommandLineArgs(getIntent());
public FlutterShellArgs getFlutterShellArgs() {
return FlutterShellArgs.fromIntent(getIntent());
}
/**

View File

@ -29,6 +29,7 @@ import io.flutter.FlutterInjector;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.FlutterEngineFlags;
import io.flutter.embedding.engine.FlutterEngineGroup;
import io.flutter.embedding.engine.FlutterEngineGroupCache;
import io.flutter.embedding.engine.FlutterShellArgs;
@ -333,11 +334,9 @@ import java.util.Set;
+ " this FlutterFragment.");
warnIfEngineFlagsSetViaIntent(host.getActivity().getIntent());
String[] flutterShellArgs =
host.getFlutterShellArgs() == null ? new String[0] : host.getFlutterShellArgs();
FlutterEngineGroup group =
engineGroup == null
? new FlutterEngineGroup(host.getContext(), flutterShellArgs)
? new FlutterEngineGroup(host.getContext(), host.getFlutterShellArgs().toArray())
: engineGroup;
flutterEngine =
group.createAndRunEngine(
@ -360,13 +359,13 @@ import java.util.Set;
Set<String> extrasKeys = extras.keySet();
for (String extrasKey : extrasKeys) {
FlutterShellArgs.Flag flag = FlutterShellArgs.getFlagFromIntentKey(extrasKey);
FlutterEngineFlags.Flag flag = FlutterEngineFlags.getFlagFromIntentKey(extrasKey);
if (flag != null) {
Log.w(
TAG,
"Support for setting engine flags on Android via Intent will soon be dropped; see https://github.com/flutter/flutter/issues/180686 for more information on this breaking change. To migrate, set "
+ flag.commandLineArgument
+ " on the command line or see https://github.com/flutter/flutter/blob/main/docs/engine/Android-Flutter-Shell-Arguments.md for alternative methods.");
+ " on the command line or see https://github.com/flutter/flutter/blob/main/docs/engine/Android-Flutter-Engine-Flags.md for alternative methods.");
break;
}
}
@ -1119,7 +1118,7 @@ import java.util.Set;
Lifecycle getLifecycle();
@NonNull
String[] getFlutterShellArgs();
FlutterShellArgs getFlutterShellArgs();
/**
* Returns the ID of a statically cached {@link io.flutter.embedding.engine.FlutterEngine} to

View File

@ -27,6 +27,7 @@ import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Lifecycle;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
import io.flutter.plugin.platform.PlatformPlugin;
import io.flutter.plugin.view.SensitiveContentPlugin;
@ -255,7 +256,7 @@ public class FlutterFragment extends Fragment
private String initialRoute = "/";
private boolean handleDeeplinking = false;
private String appBundlePath = null;
private String[] shellArgs = null;
private FlutterShellArgs shellArgs = null;
private RenderMode renderMode = RenderMode.surface;
private TransparencyMode transparencyMode = TransparencyMode.transparent;
private boolean shouldAttachEngineToActivity = true;
@ -331,7 +332,7 @@ public class FlutterFragment extends Fragment
/** Any special configuration arguments for the Flutter engine */
@NonNull
public NewEngineFragmentBuilder flutterShellArgs(@NonNull String[] shellArgs) {
public NewEngineFragmentBuilder flutterShellArgs(@NonNull FlutterShellArgs shellArgs) {
this.shellArgs = shellArgs;
return this;
}
@ -458,8 +459,9 @@ public class FlutterFragment extends Fragment
dartEntrypointArgs != null ? new ArrayList(dartEntrypointArgs) : null);
// TODO(mattcarroll): determine if we should have an explicit FlutterTestFragment instead of
// conflating.
args.putStringArray(
ARG_FLUTTER_INITIALIZATION_ARGS, shellArgs == null ? new String[0] : shellArgs);
if (null != shellArgs) {
args.putStringArray(ARG_FLUTTER_INITIALIZATION_ARGS, shellArgs.toArray());
}
args.putString(
ARG_FLUTTERVIEW_RENDER_MODE,
renderMode != null ? renderMode.name() : RenderMode.surface.name());
@ -1351,9 +1353,10 @@ public class FlutterFragment extends Fragment
*/
@Override
@NonNull
public String[] getFlutterShellArgs() {
public FlutterShellArgs getFlutterShellArgs() {
String[] flutterShellArgsArray = getArguments().getStringArray(ARG_FLUTTER_INITIALIZATION_ARGS);
return flutterShellArgsArray == null ? new String[0] : flutterShellArgsArray;
return new FlutterShellArgs(
flutterShellArgsArray != null ? flutterShellArgsArray : new String[] {});
}
/**

View File

@ -43,7 +43,7 @@ import androidx.fragment.app.FragmentManager;
import io.flutter.Log;
import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterShellArgsIntentUtils;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister;
import io.flutter.plugin.platform.PlatformPlugin;
import java.util.ArrayList;
@ -591,7 +591,7 @@ public class FlutterFragmentActivity extends FragmentActivity
.dartEntrypointArgs(getDartEntrypointArgs())
.initialRoute(getInitialRoute())
.appBundlePath(getAppBundlePath())
.flutterShellArgs(FlutterShellArgsIntentUtils.getFlutterShellCommandLineArgs(getIntent()))
.flutterShellArgs(FlutterShellArgs.fromIntent(getIntent()))
.handleDeeplinking(shouldHandleDeeplinking())
.renderMode(renderMode)
.transparencyMode(transparencyMode)

View File

@ -177,7 +177,7 @@ public class FlutterEngine implements ViewUtils.DisplayUpdater {
* native library and start a Dart VM.
*
* <p>In order to pass Dart VM initialization arguments (see {@link
* io.flutter.embedding.engine.FlutterShellArgs} for all available flags) when creating the VM,
* io.flutter.embedding.engine.FlutterEngineFlags} for all available flags) when creating the VM,
* manually set the initialization arguments by calling {@link
* io.flutter.embedding.engine.loader.FlutterLoader#startInitialization(Context)} and {@link
* io.flutter.embedding.engine.loader.FlutterLoader#ensureInitializationComplete(Context,

View File

@ -334,8 +334,7 @@ import java.util.Set;
// https://github.com/flutter/flutter/issues/180686.
boolean useSoftwareRendering =
intent != null
? intent.getBooleanExtra(
FlutterShellArgsIntentUtils.ARG_KEY_ENABLE_SOFTWARE_RENDERING, false)
? intent.getBooleanExtra(FlutterShellArgs.ARG_KEY_ENABLE_SOFTWARE_RENDERING, false)
: false;
// As part of https://github.com/flutter/flutter/issues/172553, the ability to set
@ -347,8 +346,8 @@ import java.util.Set;
Log.w(
TAG,
"Support for setting engine flags on Android via Intent will soon be dropped; see https://github.com/flutter/flutter/issues/172553 for more information on this breaking change. To migrate, set the "
+ FlutterShellArgs.ENABLE_SOFTWARE_RENDERING.metadataKey
+ " metadata in the application manifest. See https://github.com/flutter/flutter/blob/main/docs/engine/Android-Flutter-Shell-Arguments.md for more info.");
+ FlutterEngineFlags.ENABLE_SOFTWARE_RENDERING.metadataKey
+ " metadata in the application manifest. See https://github.com/flutter/flutter/blob/main/docs/engine/Android-Flutter-Engine-Flags.md for more info.");
} else {
// Check manifest for software rendering configuration.
useSoftwareRendering = flutterLoader.getSofwareRenderingEnabledViaManifest();

View File

@ -0,0 +1,441 @@
// 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.
package io.flutter.embedding.engine;
import androidx.annotation.VisibleForTesting;
import java.util.*;
/**
* Arguments that can be delivered to the Flutter shell on Android.
*
* <p>The term "shell" refers to the native code that adapts Flutter to different platforms.
* Flutter's Android Java code initializes a native "shell" and passes these arguments to that
* native shell when it is initialized. See {@link
* io.flutter.embedding.engine.loader.FlutterLoader#ensureInitializationComplete(Context, String[])}
* for more information.
*
* <p>All of these flags map to a flag listed in shell/common/switches.cc, which contains the full
* list of flags that can be set across all platforms.
*
* <p>These flags can either be set via the manifest metadata in a Flutter component's
* AndroidManifest.xml or via the command line. See the inner {@code Flag} class for the
* specification of how to set each flag via the command line and manifest metadata.
*
* <p>If the same flag is provided both via command line arguments and via AndroidManifest.xml
* metadata, the command line value will take precedence at runtime.
*/
public final class FlutterEngineFlags {
private FlutterEngineFlags() {}
/** Represents a Flutter shell flag that can be set via manifest metadata or command line. */
public static class Flag {
/** The command line argument used to specify the flag. */
public final String commandLineArgument;
/**
* The metadata key name used to specify the flag in AndroidManifest.xml.
*
* <p>To specify a flag in a manifest, it should be prefixed with {@code
* io.flutter.embedding.android.}. This is enforced to avoid potential naming collisions with
* other metadata keys. The only exception are flags that have already been deprecated.
*/
public final String metadataKey;
/** Whether this flag is allowed to be set in release mode. */
public final boolean allowedInRelease;
/**
* Creates a new Flutter shell flag that is not allowed in release mode with the default flag
* prefix.
*/
private Flag(String commandLineArgument, String metaDataName) {
this(commandLineArgument, metaDataName, "io.flutter.embedding.android.", false);
}
/** Creates a new Flutter shell flag with the default flag prefix. */
private Flag(String commandLineArgument, String metaDataName, boolean allowedInRelease) {
this(commandLineArgument, metaDataName, "io.flutter.embedding.android.", allowedInRelease);
}
/**
* Creates a new Flutter shell flag.
*
* <p>{@param allowedInRelease} determines whether or not this flag is allowed in release mode.
* Whenever possible, it is recommended to NOT allow this flag in release mode. Many flags are
* designed for debugging purposes and if enabled in production, could expose sensitive
* application data or make the app vulnerable to malicious actors.
*
* <p>If creating a flag that will be allowed in release, please leave a comment in the Javadoc
* explaining why it should be allowed in release.
*/
private Flag(
String commandLineArgument,
String metaDataName,
String flagPrefix,
boolean allowedInRelease) {
this.commandLineArgument = commandLineArgument;
this.metadataKey = flagPrefix + metaDataName;
this.allowedInRelease = allowedInRelease;
}
/** Returns true if this flag requires a value to be specified. */
public boolean hasValue() {
return commandLineArgument.endsWith("=");
}
}
// Manifest flags allowed in release mode:
/**
* Specifies the path to the AOT shared library containing compiled Dart code.
*
* <p>The AOT shared library that the engine uses will default to the library set by this flag,
* but will fall back to the libraries set internally by the embedding if the path specified by
* this argument is invalid.
*
* <p>This is allowed in release to support the same AOT configuration regardless of build mode.
*/
public static final Flag AOT_SHARED_LIBRARY_NAME =
new Flag("--aot-shared-library-name=", "AOTSharedLibraryName", true);
/**
* Deprecated flag that specifies the path to the AOT shared library containing compiled Dart
* code.
*
* <p>Please use {@link AOT_SHARED_LIBRARY_NAME} instead.
*/
@Deprecated
public static final Flag DEPRECATED_AOT_SHARED_LIBRARY_NAME =
new Flag(
"--aot-shared-library-name=",
"aot-shared-library-name",
"io.flutter.embedding.engine.loader.FlutterLoader.",
true);
/**
* Sets the directory containing Flutter assets.
*
* <p>This is allowed in release to specify custom asset locations in production.
*/
public static final Flag FLUTTER_ASSETS_DIR =
new Flag("--flutter-assets-dir=", "FlutterAssetsDir", true);
/**
* The deprecated flag that sets the directory containing Flutter assets.
*
* <p>Please use {@link FLUTTER_ASSETS_DIR} instead.
*/
@Deprecated
public static final Flag DEPRECATED_FLUTTER_ASSETS_DIR =
new Flag(
"--flutter-assets-dir=",
"flutter-assets-dir",
"io.flutter.embedding.engine.loader.FlutterLoader.",
true);
/**
* Sets the old generation heap size for the Dart VM in megabytes.
*
* <p>This is allowed in release for performance tuning.
*/
public static final Flag OLD_GEN_HEAP_SIZE =
new Flag("--old-gen-heap-size=", "OldGenHeapSize", true);
/**
* Enables or disables the Impeller renderer.
*
* <p>This is allowed in release to control which rendering backend is used in production.
*/
private static final Flag ENABLE_IMPELLER =
new Flag("--enable-impeller=", "EnableImpeller", true);
/**
* Specifies the backend to use for Impeller rendering.
*
* <p>This is allowed in release to select a specific graphics backend for Impeller in production.
*/
private static final Flag IMPELLER_BACKEND =
new Flag("--impeller-backend=", "ImpellerBackend", true);
/**
* Enables Android SurfaceControl for rendering.
*
* <p>This is allowed in release to opt-in to this rendering feature in production.
*/
private static final Flag ENABLE_SURFACE_CONTROL =
new Flag("--enable-surface-control", "EnableSurfaceControl", true);
/**
* Enables the Flutter GPU backend.
*
* <p>This is allowed in release for developers to use the Flutter GPU backend in production.
*/
private static final Flag ENABLE_FLUTTER_GPU =
new Flag("--enable-flutter-gpu", "EnableFlutterGPU", true);
/**
* Enables lazy initialization of Impeller shaders.
*
* <p>This is allowed in release for performance tuning of the Impeller backend.
*/
private static final Flag IMPELLER_LAZY_SHADER_MODE =
new Flag("--impeller-lazy-shader-mode=", "ImpellerLazyShaderInitialization", true);
/**
* Enables antialiasing for lines in Impeller.
*
* <p>This is allowed in release to control rendering quality in production.
*/
private static final Flag IMPELLER_ANTIALIAS_LINES =
new Flag("--impeller-antialias-lines", "ImpellerAntialiasLines", true);
/**
* Specifies the path to the VM snapshot data file.
*
* <p>This is allowed in release to support different snapshot configurations.
*/
public static final Flag VM_SNAPSHOT_DATA =
new Flag("--vm-snapshot-data=", "VmSnapshotData", true);
/**
* Specifies the path to the isolate snapshot data file.
*
* <p>This is allowed in release to support different snapshot configurations.
*/
public static final Flag ISOLATE_SNAPSHOT_DATA =
new Flag("--isolate-snapshot-data=", "IsolateSnapshotData", true);
/**
* Enables Dart profiling for use with DevTools.
*
* <p>Allowed in release mode for testing purposes.
*/
private static final Flag ENABLE_DART_PROFILING =
new Flag("--enable-dart-profiling", "EnableDartProfiling", true);
// Manifest flags NOT allowed in release mode:
/** Ensures deterministic Skia rendering by skipping CPU feature swaps. */
private static final Flag SKIA_DETERMINISTIC_RENDERING =
new Flag("--skia-deterministic-rendering", "SkiaDeterministicRendering");
/** Use Skia software backend for rendering. */
public static final Flag ENABLE_SOFTWARE_RENDERING =
new Flag("--enable-software-rendering", "EnableSoftwareRendering");
/** Use the Ahem test font for font resolution. */
private static final Flag USE_TEST_FONTS = new Flag("--use-test-fonts", "UseTestFonts");
/** Sets the port for the Dart VM Service. */
private static final Flag VM_SERVICE_PORT = new Flag("--vm-service-port=", "VMServicePort");
/** Enables Vulkan validation layers if available. */
private static final Flag ENABLE_VULKAN_VALIDATION =
new Flag("--enable-vulkan-validation", "EnableVulkanValidation");
/** Enables GPU tracing for OpenGL. */
private static final Flag ENABLE_OPENGL_GPU_TRACING =
new Flag("--enable-opengl-gpu-tracing", "EnableOpenGLGPUTracing");
/** Enables GPU tracing for Vulkan. */
private static final Flag ENABLE_VULKAN_GPU_TRACING =
new Flag("--enable-vulkan-gpu-tracing", "EnableVulkanGPUTracing");
/**
* Set whether leave or clean up the VM after the last shell shuts down. It can be set from app's
* metadata in the application block in AndroidManifest.xml. Set it to true in to leave the Dart
* VM, set it to false to destroy VM.
*
* <p>If your want to let your app destroy the last shell and re-create shells more quickly, set
* it to true, otherwise if you want to clean up the memory of the leak VM, set it to false.
*
* <p>TODO(eggfly): Should it be set to false by default?
* https://github.com/flutter/flutter/issues/96843
*/
public static final Flag LEAK_VM = new Flag("--leak-vm=", "LeakVM");
/** Measures startup time and switches to an endless trace buffer. */
private static final Flag TRACE_STARTUP = new Flag("--trace-startup", "TraceStartup");
/** Pauses Dart code execution at launch until a debugger is attached. */
private static final Flag START_PAUSED = new Flag("--start-paused", "StartPaused");
/** Disables authentication codes for VM service communication. */
private static final Flag DISABLE_SERVICE_AUTH_CODES =
new Flag("--disable-service-auth-codes", "DisableServiceAuthCodes");
/** Enables an endless trace buffer for timeline events. */
private static final Flag ENDLESS_TRACE_BUFFER =
new Flag("--endless-trace-buffer", "EndlessTraceBuffer");
/** Discards new profiler samples once the buffer is full. */
private static final Flag PROFILE_STARTUP = new Flag("--profile-startup", "ProfileStartup");
/** Enables tracing of Skia GPU calls. */
private static final Flag TRACE_SKIA = new Flag("--trace-skia", "TraceSkia");
/** Only traces specified Skia event categories. */
private static final Flag TRACE_SKIA_ALLOWLIST =
new Flag("--trace-skia-allowlist=", "TraceSkiaAllowList");
/** Traces to the system tracer on supported platforms. */
private static final Flag TRACE_SYSTRACE = new Flag("--trace-systrace", "TraceSystrace");
/** Writes timeline trace to a file in Perfetto format. */
private static final Flag TRACE_TO_FILE = new Flag("--trace-to-file=", "TraceToFile");
/** Collects and logs information about microtasks. */
private static final Flag PROFILE_MICROTASKS =
new Flag("--profile-microtasks", "ProfileMicrotasks");
/** Dumps SKP files that trigger shader compilations. */
private static final Flag DUMP_SKP_ON_SHADER_COMPILATION =
new Flag("--dump-skp-on-shader-compilation", "DumpSkpOnShaderCompilation");
/** Removes all persistent cache files for debugging. */
private static final Flag PURGE_PERSISTENT_CACHE =
new Flag("--purge-persistent-cache", "PurgePersistentCache");
/** Enables logging at all severity levels. */
private static final Flag VERBOSE_LOGGING = new Flag("--verbose-logging", "VerboseLogging");
/**
* Passes additional flags to the Dart VM.
*
* <p>All flags provided with this argument are subject to filtering based on a list of allowed
* flags in shell/common/switches.cc. If any flag provided is not allowed, the process will
* immediately terminate.
*
* <p>Flags should be separated by a space, e.g. "--dart-flags=--flag-1 --flag-2=2".
*/
private static final Flag DART_FLAGS = new Flag("--dart-flags=", "DartFlags");
// Deprecated flags:
/** Disables the merging of the UI and platform threads. */
@VisibleForTesting
public static final Flag DISABLE_MERGED_PLATFORM_UI_THREAD =
new Flag("--no-enable-merged-platform-ui-thread", "DisableMergedPlatformUIThread");
@VisibleForTesting
public static final List<Flag> ALL_FLAGS =
Collections.unmodifiableList(
Arrays.asList(
VM_SERVICE_PORT,
USE_TEST_FONTS,
ENABLE_SOFTWARE_RENDERING,
SKIA_DETERMINISTIC_RENDERING,
AOT_SHARED_LIBRARY_NAME,
FLUTTER_ASSETS_DIR,
OLD_GEN_HEAP_SIZE,
ENABLE_IMPELLER,
IMPELLER_BACKEND,
ENABLE_SURFACE_CONTROL,
ENABLE_FLUTTER_GPU,
IMPELLER_LAZY_SHADER_MODE,
IMPELLER_ANTIALIAS_LINES,
VM_SNAPSHOT_DATA,
ISOLATE_SNAPSHOT_DATA,
ENABLE_VULKAN_VALIDATION,
ENABLE_OPENGL_GPU_TRACING,
ENABLE_VULKAN_GPU_TRACING,
LEAK_VM,
TRACE_STARTUP,
START_PAUSED,
DISABLE_SERVICE_AUTH_CODES,
ENDLESS_TRACE_BUFFER,
ENABLE_DART_PROFILING,
PROFILE_STARTUP,
TRACE_SKIA,
TRACE_SKIA_ALLOWLIST,
TRACE_SYSTRACE,
TRACE_TO_FILE,
PROFILE_MICROTASKS,
DUMP_SKP_ON_SHADER_COMPILATION,
PURGE_PERSISTENT_CACHE,
VERBOSE_LOGGING,
DART_FLAGS,
DISABLE_MERGED_PLATFORM_UI_THREAD,
DEPRECATED_AOT_SHARED_LIBRARY_NAME,
DEPRECATED_FLUTTER_ASSETS_DIR));
// Flags that have been turned off.
private static final List<Flag> DISABLED_FLAGS =
Collections.unmodifiableList(Arrays.asList(DISABLE_MERGED_PLATFORM_UI_THREAD));
// Lookup map for current flags that replace deprecated ones.
private static final Map<Flag, Flag> DEPRECATED_FLAGS_BY_REPLACEMENT =
new HashMap<Flag, Flag>() {
{
put(DEPRECATED_AOT_SHARED_LIBRARY_NAME, AOT_SHARED_LIBRARY_NAME);
put(DEPRECATED_FLUTTER_ASSETS_DIR, FLUTTER_ASSETS_DIR);
}
};
// Lookup map for retrieving the Flag corresponding to a specific command line argument.
private static final Map<String, Flag> FLAG_BY_COMMAND_LINE_ARG;
// Lookup map for retrieving the Flag corresponding to a specific metadata key.
private static final Map<String, Flag> FLAG_BY_META_DATA_KEY;
static {
Map<String, Flag> map = new HashMap<String, Flag>(ALL_FLAGS.size());
Map<String, Flag> metaMap = new HashMap<String, Flag>(ALL_FLAGS.size());
for (Flag flag : ALL_FLAGS) {
map.put(flag.commandLineArgument, flag);
metaMap.put(flag.metadataKey, flag);
}
FLAG_BY_COMMAND_LINE_ARG = Collections.unmodifiableMap(map);
FLAG_BY_META_DATA_KEY = Collections.unmodifiableMap(metaMap);
}
/** Looks up a {@link Flag} by its metadataKey. */
public static Flag getFlagByMetadataKey(String key) {
Flag flag = FLAG_BY_META_DATA_KEY.get(key);
Flag replacementFlag = getReplacementFlagIfDeprecated(flag);
return replacementFlag != null ? replacementFlag : flag;
}
/** Looks up a {@link Flag} by its commandLineArgument. */
public static Flag getFlagByCommandLineArgument(String arg) {
int equalsIndex = arg.indexOf('=');
Flag flag =
FLAG_BY_COMMAND_LINE_ARG.get(equalsIndex == -1 ? arg : arg.substring(0, equalsIndex + 1));
Flag replacementFlag = getReplacementFlagIfDeprecated(flag);
return replacementFlag != null ? replacementFlag : flag;
}
/**
* Looks up a {@link Flag} by its Intent key.
*
* <p>Previously, the Intent keys were used to set Flutter shell arguments via Intent. The Intent
* keys match the command line argument without the "--" prefix and "=" suffix if the argument
* takes a value.
*/
public static Flag getFlagFromIntentKey(String intentKey) {
for (Flag flag : ALL_FLAGS) {
String commandLineArg = flag.commandLineArgument;
String key = commandLineArg.startsWith("--") ? commandLineArg.substring(2) : commandLineArg;
if (key.endsWith("=")) {
key = key.substring(0, key.length() - 1);
}
if (key.equals(intentKey)) {
return flag;
}
}
return null;
}
/** Returns whether or not a flag is disabled and should raise an exception if used. */
public static boolean isDisabled(Flag flag) {
return DISABLED_FLAGS.contains(flag);
}
/** Returns the replacement flag of that given if it is deprecated. */
public static Flag getReplacementFlagIfDeprecated(Flag flag) {
return DEPRECATED_FLAGS_BY_REPLACEMENT.get(flag);
}
}

View File

@ -4,434 +4,213 @@
package io.flutter.embedding.engine;
import androidx.annotation.VisibleForTesting;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import java.util.*;
/**
* Arguments that can be delivered to the Flutter shell on Android.
* DEPRECATED. Please see {@link FlutterEngineFlags} for the list of arguments to use or update if
* you are adding a new flag.
*
* <p>Arguments that can be delivered to the Flutter shell when it is created.
*
* <p>The term "shell" refers to the native code that adapts Flutter to different platforms.
* Flutter's Android Java code initializes a native "shell" and passes these arguments to that
* native shell when it is initialized. See {@link
* io.flutter.embedding.engine.loader.FlutterLoader#ensureInitializationComplete(Context, String[])}
* for more information.
*
* <p>All of these flags map to a flag listed in shell/common/switches.cc, which contains the full
* list of flags that can be set across all platforms.
*
* <p>These flags can either be set via the manifest metadata in a Flutter component's
* AndroidManifest.xml or via the command line. See the inner {@code Flag} class for the
* specification of how to set each flag via the command line and manifest metadata.
*
* <p>If the same flag is provided both via command line arguments and via AndroidManifest.xml
* metadata, the command line value will take precedence at runtime.
*/
public final class FlutterShellArgs {
// TODO(camsim99): Delete this class when support for setting engine shell arguments via Intent
// is no longer supported. See https://github.com/flutter/flutter/issues/180686.
@SuppressWarnings({"WeakerAccess", "unused"})
@Deprecated
public class FlutterShellArgs {
public static final String ARG_KEY_TRACE_STARTUP = "trace-startup";
public static final String ARG_TRACE_STARTUP = "--trace-startup";
public static final String ARG_KEY_START_PAUSED = "start-paused";
public static final String ARG_START_PAUSED = "--start-paused";
public static final String ARG_KEY_DISABLE_SERVICE_AUTH_CODES = "disable-service-auth-codes";
public static final String ARG_DISABLE_SERVICE_AUTH_CODES = "--disable-service-auth-codes";
public static final String ARG_KEY_ENDLESS_TRACE_BUFFER = "endless-trace-buffer";
public static final String ARG_ENDLESS_TRACE_BUFFER = "--endless-trace-buffer";
public static final String ARG_KEY_USE_TEST_FONTS = "use-test-fonts";
public static final String ARG_USE_TEST_FONTS = "--use-test-fonts";
public static final String ARG_KEY_ENABLE_DART_PROFILING = "enable-dart-profiling";
public static final String ARG_ENABLE_DART_PROFILING = "--enable-dart-profiling";
public static final String ARG_KEY_PROFILE_STARTUP = "profile-startup";
public static final String ARG_PROFILE_STARTUP = "--profile-startup";
public static final String ARG_KEY_ENABLE_SOFTWARE_RENDERING = "enable-software-rendering";
public static final String ARG_ENABLE_SOFTWARE_RENDERING = "--enable-software-rendering";
public static final String ARG_KEY_SKIA_DETERMINISTIC_RENDERING = "skia-deterministic-rendering";
public static final String ARG_SKIA_DETERMINISTIC_RENDERING = "--skia-deterministic-rendering";
public static final String ARG_KEY_TRACE_SKIA = "trace-skia";
public static final String ARG_TRACE_SKIA = "--trace-skia";
public static final String ARG_KEY_TRACE_SKIA_ALLOWLIST = "trace-skia-allowlist";
public static final String ARG_TRACE_SKIA_ALLOWLIST = "--trace-skia-allowlist=";
public static final String ARG_KEY_TRACE_SYSTRACE = "trace-systrace";
public static final String ARG_TRACE_SYSTRACE = "--trace-systrace";
public static final String ARG_KEY_TRACE_TO_FILE = "trace-to-file";
public static final String ARG_TRACE_TO_FILE = "--trace-to-file";
public static final String ARG_KEY_PROFILE_MICROTASKS = "profile-microtasks";
public static final String ARG_PROFILE_MICROTASKS = "--profile-microtasks";
public static final String ARG_KEY_TOGGLE_IMPELLER = "enable-impeller";
public static final String ARG_ENABLE_IMPELLER = "--enable-impeller=true";
public static final String ARG_DISABLE_IMPELLER = "--enable-impeller=false";
public static final String ARG_KEY_ENABLE_VULKAN_VALIDATION = "enable-vulkan-validation";
public static final String ARG_ENABLE_VULKAN_VALIDATION = "--enable-vulkan-validation";
public static final String ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION =
"dump-skp-on-shader-compilation";
public static final String ARG_DUMP_SHADER_SKP_ON_SHADER_COMPILATION =
"--dump-skp-on-shader-compilation";
public static final String ARG_KEY_CACHE_SKSL = "cache-sksl";
public static final String ARG_CACHE_SKSL = "--cache-sksl";
public static final String ARG_KEY_PURGE_PERSISTENT_CACHE = "purge-persistent-cache";
public static final String ARG_PURGE_PERSISTENT_CACHE = "--purge-persistent-cache";
public static final String ARG_KEY_VERBOSE_LOGGING = "verbose-logging";
public static final String ARG_VERBOSE_LOGGING = "--verbose-logging";
public static final String ARG_KEY_VM_SERVICE_PORT = "vm-service-port";
public static final String ARG_VM_SERVICE_PORT = "--vm-service-port=";
public static final String ARG_KEY_DART_FLAGS = "dart-flags";
public static final String ARG_DART_FLAGS = "--dart-flags";
private FlutterShellArgs() {}
@NonNull
public static FlutterShellArgs fromIntent(@NonNull Intent intent) {
// Before adding more entries to this list, consider that arbitrary
// Android applications can generate intents with extra data and that
// there are many security-sensitive args in the binary.
ArrayList<String> args = new ArrayList<>();
/** Represents a Flutter shell flag that can be set via manifest metadata or command line. */
public static class Flag {
/** The command line argument used to specify the flag. */
public final String commandLineArgument;
/**
* The metadata key name used to specify the flag in AndroidManifest.xml.
*
* <p>To specify a flag in a manifest, it should be prefixed with {@code
* io.flutter.embedding.android.}. This is enforced to avoid potential naming collisions with
* other metadata keys. The only exception are flags that have already been deprecated.
*/
public final String metadataKey;
/** Whether this flag is allowed to be set in release mode. */
public final boolean allowedInRelease;
/**
* Creates a new Flutter shell flag that is not allowed in release mode with the default flag
* prefix.
*/
private Flag(String commandLineArgument, String metaDataName) {
this(commandLineArgument, metaDataName, "io.flutter.embedding.android.", false);
if (intent.getBooleanExtra(ARG_KEY_TRACE_STARTUP, false)) {
args.add(ARG_TRACE_STARTUP);
}
/** Creates a new Flutter shell flag with the default flag prefix. */
private Flag(String commandLineArgument, String metaDataName, boolean allowedInRelease) {
this(commandLineArgument, metaDataName, "io.flutter.embedding.android.", allowedInRelease);
if (intent.getBooleanExtra(ARG_KEY_START_PAUSED, false)) {
args.add(ARG_START_PAUSED);
}
/**
* Creates a new Flutter shell flag.
*
* <p>{@param allowedInRelease} determines whether or not this flag is allowed in release mode.
* Whenever possible, it is recommended to NOT allow this flag in release mode. Many flags are
* designed for debugging purposes and if enabled in production, could expose sensitive
* application data or make the app vulnerable to malicious actors.
*
* <p>If creating a flag that will be allowed in release, please leave a comment in the Javadoc
* explaining why it should be allowed in release.
*/
private Flag(
String commandLineArgument,
String metaDataName,
String flagPrefix,
boolean allowedInRelease) {
this.commandLineArgument = commandLineArgument;
this.metadataKey = flagPrefix + metaDataName;
this.allowedInRelease = allowedInRelease;
int vmServicePort = intent.getIntExtra(ARG_KEY_VM_SERVICE_PORT, 0);
if (vmServicePort > 0) {
args.add(ARG_VM_SERVICE_PORT + Integer.toString(vmServicePort));
}
/** Returns true if this flag requires a value to be specified. */
public boolean hasValue() {
return commandLineArgument.endsWith("=");
if (intent.getBooleanExtra(ARG_KEY_DISABLE_SERVICE_AUTH_CODES, false)) {
args.add(ARG_DISABLE_SERVICE_AUTH_CODES);
}
}
// Manifest flags allowed in release mode:
/**
* Specifies the path to the AOT shared library containing compiled Dart code.
*
* <p>The AOT shared library that the engine uses will default to the library set by this flag,
* but will fall back to the libraries set internally by the embedding if the path specified by
* this argument is invalid.
*
* <p>This is allowed in release to support the same AOT configuration regardless of build mode.
*/
public static final Flag AOT_SHARED_LIBRARY_NAME =
new Flag("--aot-shared-library-name=", "AOTSharedLibraryName", true);
/**
* Deprecated flag that specifies the path to the AOT shared library containing compiled Dart
* code.
*
* <p>Please use {@link AOT_SHARED_LIBRARY_NAME} instead.
*/
@Deprecated
public static final Flag DEPRECATED_AOT_SHARED_LIBRARY_NAME =
new Flag(
"--aot-shared-library-name=",
"aot-shared-library-name",
"io.flutter.embedding.engine.loader.FlutterLoader.",
true);
/**
* Sets the directory containing Flutter assets.
*
* <p>This is allowed in release to specify custom asset locations in production.
*/
public static final Flag FLUTTER_ASSETS_DIR =
new Flag("--flutter-assets-dir=", "FlutterAssetsDir", true);
/**
* The deprecated flag that sets the directory containing Flutter assets.
*
* <p>Please use {@link DEPRECATED_FLUTTER_ASSETS_DIR} instead.
*/
@Deprecated
public static final Flag DEPRECATED_FLUTTER_ASSETS_DIR =
new Flag(
"--flutter-assets-dir=",
"flutter-assets-dir",
"io.flutter.embedding.engine.loader.FlutterLoader.",
true);
/**
* Sets the old generation heap size for the Dart VM in megabytes.
*
* <p>This is allowed in release for performance tuning.
*/
public static final Flag OLD_GEN_HEAP_SIZE =
new Flag("--old-gen-heap-size=", "OldGenHeapSize", true);
/**
* Enables or disables the Impeller renderer.
*
* <p>This is allowed in release to control which rendering backend is used in production.
*/
private static final Flag ENABLE_IMPELLER =
new Flag("--enable-impeller=", "EnableImpeller", true);
/**
* Specifies the backend to use for Impeller rendering.
*
* <p>This is allowed in release to select a specific graphics backend for Impeller in production.
*/
private static final Flag IMPELLER_BACKEND =
new Flag("--impeller-backend=", "ImpellerBackend", true);
/**
* Enables Android SurfaceControl for rendering.
*
* <p>This is allowed in release to opt-in to this rendering feature in production.
*/
private static final Flag ENABLE_SURFACE_CONTROL =
new Flag("--enable-surface-control", "EnableSurfaceControl", true);
/**
* Enables the Flutter GPU backend.
*
* <p>This is allowed in release for developers to use the Flutter GPU backend in production.
*/
private static final Flag ENABLE_FLUTTER_GPU =
new Flag("--enable-flutter-gpu", "EnableFlutterGPU", true);
/**
* Enables lazy initialization of Impeller shaders.
*
* <p>This is allowed in release for performance tuning of the Impeller backend.
*/
private static final Flag IMPELLER_LAZY_SHADER_MODE =
new Flag("--impeller-lazy-shader-mode=", "ImpellerLazyShaderInitialization", true);
/**
* Enables antialiasing for lines in Impeller.
*
* <p>This is allowed in release to control rendering quality in production.
*/
private static final Flag IMPELLER_ANTIALIAS_LINES =
new Flag("--impeller-antialias-lines", "ImpellerAntialiasLines", true);
/**
* Specifies the path to the VM snapshot data file.
*
* <p>This is allowed in release to support different snapshot configurations.
*/
public static final Flag VM_SNAPSHOT_DATA =
new Flag("--vm-snapshot-data=", "VmSnapshotData", true);
/**
* Specifies the path to the isolate snapshot data file.
*
* <p>This is allowed in release to support different snapshot configurations.
*/
public static final Flag ISOLATE_SNAPSHOT_DATA =
new Flag("--isolate-snapshot-data=", "IsolateSnapshotData", true);
// Manifest flags NOT allowed in release mode:
/** Ensures deterministic Skia rendering by skipping CPU feature swaps. */
private static final Flag SKIA_DETERMINISTIC_RENDERING =
new Flag("--skia-deterministic-rendering", "SkiaDeterministicRendering");
/** Use Skia software backend for rendering. */
public static final Flag ENABLE_SOFTWARE_RENDERING =
new Flag("--enable-software-rendering", "EnableSoftwareRendering");
/** Use the Ahem test font for font resolution. */
private static final Flag USE_TEST_FONTS = new Flag("--use-test-fonts", "UseTestFonts");
/** Sets the port for the Dart VM Service. */
private static final Flag VM_SERVICE_PORT = new Flag("--vm-service-port=", "VMServicePort");
/** Enables Vulkan validation layers if available. */
private static final Flag ENABLE_VULKAN_VALIDATION =
new Flag("--enable-vulkan-validation", "EnableVulkanValidation");
/** Enables GPU tracing for OpenGL. */
private static final Flag ENABLE_OPENGL_GPU_TRACING =
new Flag("--enable-opengl-gpu-tracing", "EnableOpenGLGPUTracing");
/** Enables GPU tracing for Vulkan. */
private static final Flag ENABLE_VULKAN_GPU_TRACING =
new Flag("--enable-vulkan-gpu-tracing", "EnableVulkanGPUTracing");
/**
* Set whether leave or clean up the VM after the last shell shuts down. It can be set from app's
* metadata in the application block in AndroidManifest.xml. Set it to true in to leave the Dart
* VM, set it to false to destroy VM.
*
* <p>If your want to let your app destroy the last shell and re-create shells more quickly, set
* it to true, otherwise if you want to clean up the memory of the leak VM, set it to false.
*
* <p>TODO(eggfly): Should it be set to false by default?
* https://github.com/flutter/flutter/issues/96843
*/
public static final Flag LEAK_VM = new Flag("--leak-vm=", "LeakVM");
/** Measures startup time and switches to an endless trace buffer. */
private static final Flag TRACE_STARTUP = new Flag("--trace-startup", "TraceStartup");
/** Pauses Dart code execution at launch until a debugger is attached. */
private static final Flag START_PAUSED = new Flag("--start-paused", "StartPaused");
/** Disables authentication codes for VM service communication. */
private static final Flag DISABLE_SERVICE_AUTH_CODES =
new Flag("--disable-service-auth-codes", "DisableServiceAuthCodes");
/** Enables an endless trace buffer for timeline events. */
private static final Flag ENDLESS_TRACE_BUFFER =
new Flag("--endless-trace-buffer", "EndlessTraceBuffer");
/** Enables Dart profiling for use with DevTools. */
private static final Flag ENABLE_DART_PROFILING =
new Flag("--enable-dart-profiling", "EnableDartProfiling");
/** Discards new profiler samples once the buffer is full. */
private static final Flag PROFILE_STARTUP = new Flag("--profile-startup", "ProfileStartup");
/** Enables tracing of Skia GPU calls. */
private static final Flag TRACE_SKIA = new Flag("--trace-skia", "TraceSkia");
/** Only traces specified Skia event categories. */
private static final Flag TRACE_SKIA_ALLOWLIST =
new Flag("--trace-skia-allowlist=", "TraceSkiaAllowList");
/** Traces to the system tracer on supported platforms. */
private static final Flag TRACE_SYSTRACE = new Flag("--trace-systrace", "TraceSystrace");
/** Writes timeline trace to a file in Perfetto format. */
private static final Flag TRACE_TO_FILE = new Flag("--trace-to-file=", "TraceToFile");
/** Collects and logs information about microtasks. */
private static final Flag PROFILE_MICROTASKS =
new Flag("--profile-microtasks", "ProfileMicrotasks");
/** Dumps SKP files that trigger shader compilations. */
private static final Flag DUMP_SKP_ON_SHADER_COMPILATION =
new Flag("--dump-skp-on-shader-compilation", "DumpSkpOnShaderCompilation");
/** Removes all persistent cache files for debugging. */
private static final Flag PURGE_PERSISTENT_CACHE =
new Flag("--purge-persistent-cache", "PurgePersistentCache");
/** Enables logging at all severity levels. */
private static final Flag VERBOSE_LOGGING = new Flag("--verbose-logging", "VerboseLogging");
/**
* Passes additional flags to the Dart VM.
*
* <p>All flags provided with this argument are subject to filtering based on a list of allowed
* flags in shell/common/switches.cc. If any flag provided is not allowed, the process will
* immediately terminate.
*
* <p>Flags should be separated by a space, e.g. "--dart-flags=--flag-1 --flag-2=2".
*/
private static final Flag DART_FLAGS = new Flag("--dart-flags=", "DartFlags");
// Deprecated flags:
/** Disables the merging of the UI and platform threads. */
@VisibleForTesting
public static final Flag DISABLE_MERGED_PLATFORM_UI_THREAD =
new Flag("--no-enable-merged-platform-ui-thread", "DisableMergedPlatformUIThread");
@VisibleForTesting
public static final List<Flag> ALL_FLAGS =
Collections.unmodifiableList(
Arrays.asList(
VM_SERVICE_PORT,
USE_TEST_FONTS,
ENABLE_SOFTWARE_RENDERING,
SKIA_DETERMINISTIC_RENDERING,
AOT_SHARED_LIBRARY_NAME,
FLUTTER_ASSETS_DIR,
OLD_GEN_HEAP_SIZE,
ENABLE_IMPELLER,
IMPELLER_BACKEND,
ENABLE_SURFACE_CONTROL,
ENABLE_FLUTTER_GPU,
IMPELLER_LAZY_SHADER_MODE,
IMPELLER_ANTIALIAS_LINES,
VM_SNAPSHOT_DATA,
ISOLATE_SNAPSHOT_DATA,
ENABLE_VULKAN_VALIDATION,
ENABLE_OPENGL_GPU_TRACING,
ENABLE_VULKAN_GPU_TRACING,
LEAK_VM,
TRACE_STARTUP,
START_PAUSED,
DISABLE_SERVICE_AUTH_CODES,
ENDLESS_TRACE_BUFFER,
ENABLE_DART_PROFILING,
PROFILE_STARTUP,
TRACE_SKIA,
TRACE_SKIA_ALLOWLIST,
TRACE_SYSTRACE,
TRACE_TO_FILE,
PROFILE_MICROTASKS,
DUMP_SKP_ON_SHADER_COMPILATION,
PURGE_PERSISTENT_CACHE,
VERBOSE_LOGGING,
DART_FLAGS,
DISABLE_MERGED_PLATFORM_UI_THREAD,
DEPRECATED_AOT_SHARED_LIBRARY_NAME,
DEPRECATED_FLUTTER_ASSETS_DIR));
// Flags that have been turned off.
private static final List<Flag> DISABLED_FLAGS =
Collections.unmodifiableList(Arrays.asList(DISABLE_MERGED_PLATFORM_UI_THREAD));
// Lookup map for current flags that replace deprecated ones.
private static final Map<Flag, Flag> DEPRECATED_FLAGS_BY_REPLACEMENT =
new HashMap<Flag, Flag>() {
{
put(DEPRECATED_AOT_SHARED_LIBRARY_NAME, AOT_SHARED_LIBRARY_NAME);
put(DEPRECATED_FLUTTER_ASSETS_DIR, FLUTTER_ASSETS_DIR);
}
};
// Lookup map for retrieving the Flag corresponding to a specific command line argument.
private static final Map<String, Flag> FLAG_BY_COMMAND_LINE_ARG;
// Lookup map for retrieving the Flag corresponding to a specific metadata key.
private static final Map<String, Flag> FLAG_BY_META_DATA_KEY;
static {
Map<String, Flag> map = new HashMap<String, Flag>(ALL_FLAGS.size());
Map<String, Flag> metaMap = new HashMap<String, Flag>(ALL_FLAGS.size());
for (Flag flag : ALL_FLAGS) {
map.put(flag.commandLineArgument, flag);
metaMap.put(flag.metadataKey, flag);
if (intent.getBooleanExtra(ARG_KEY_ENDLESS_TRACE_BUFFER, false)) {
args.add(ARG_ENDLESS_TRACE_BUFFER);
}
FLAG_BY_COMMAND_LINE_ARG = Collections.unmodifiableMap(map);
FLAG_BY_META_DATA_KEY = Collections.unmodifiableMap(metaMap);
}
/** Looks up a {@link Flag} by its metadataKey. */
public static Flag getFlagByMetadataKey(String key) {
Flag flag = FLAG_BY_META_DATA_KEY.get(key);
Flag replacementFlag = getReplacementFlagIfDeprecated(flag);
return replacementFlag != null ? replacementFlag : flag;
}
/** Looks up a {@link Flag} by its commandLineArgument. */
public static Flag getFlagByCommandLineArgument(String arg) {
int equalsIndex = arg.indexOf('=');
Flag flag =
FLAG_BY_COMMAND_LINE_ARG.get(equalsIndex == -1 ? arg : arg.substring(0, equalsIndex + 1));
Flag replacementFlag = getReplacementFlagIfDeprecated(flag);
return replacementFlag != null ? replacementFlag : flag;
}
/**
* Looks up a {@link Flag} by its Intent key.
*
* <p>Previously, the Intent keys were used to set Flutter shell arguments via Intent. The Intent
* keys match the command line argument without the "--" prefix and "=" suffix if the argument
* takes a value.
*/
public static Flag getFlagFromIntentKey(String intentKey) {
for (Flag flag : ALL_FLAGS) {
String commandLineArg = flag.commandLineArgument;
String key = commandLineArg.startsWith("--") ? commandLineArg.substring(2) : commandLineArg;
if (key.endsWith("=")) {
key = key.substring(0, key.length() - 1);
}
if (key.equals(intentKey)) {
return flag;
if (intent.getBooleanExtra(ARG_KEY_USE_TEST_FONTS, false)) {
args.add(ARG_USE_TEST_FONTS);
}
if (intent.getBooleanExtra(ARG_KEY_ENABLE_DART_PROFILING, false)) {
args.add(ARG_ENABLE_DART_PROFILING);
}
if (intent.getBooleanExtra(ARG_KEY_PROFILE_STARTUP, false)) {
args.add(ARG_PROFILE_STARTUP);
}
if (intent.getBooleanExtra(ARG_KEY_ENABLE_SOFTWARE_RENDERING, false)) {
args.add(ARG_ENABLE_SOFTWARE_RENDERING);
}
if (intent.getBooleanExtra(ARG_KEY_SKIA_DETERMINISTIC_RENDERING, false)) {
args.add(ARG_SKIA_DETERMINISTIC_RENDERING);
}
if (intent.getBooleanExtra(ARG_KEY_TRACE_SKIA, false)) {
args.add(ARG_TRACE_SKIA);
}
String traceSkiaAllowlist = intent.getStringExtra(ARG_KEY_TRACE_SKIA_ALLOWLIST);
if (traceSkiaAllowlist != null) {
args.add(ARG_TRACE_SKIA_ALLOWLIST + traceSkiaAllowlist);
}
if (intent.getBooleanExtra(ARG_KEY_TRACE_SYSTRACE, false)) {
args.add(ARG_TRACE_SYSTRACE);
}
if (intent.hasExtra(ARG_KEY_TRACE_TO_FILE)) {
args.add(ARG_TRACE_TO_FILE + "=" + intent.getStringExtra(ARG_KEY_TRACE_TO_FILE));
}
if (intent.hasExtra(ARG_KEY_PROFILE_MICROTASKS)) {
args.add(ARG_PROFILE_MICROTASKS);
}
if (intent.hasExtra(ARG_KEY_TOGGLE_IMPELLER)) {
if (intent.getBooleanExtra(ARG_KEY_TOGGLE_IMPELLER, false)) {
args.add(ARG_ENABLE_IMPELLER);
} else {
args.add(ARG_DISABLE_IMPELLER);
}
}
return null;
if (intent.getBooleanExtra(ARG_KEY_ENABLE_VULKAN_VALIDATION, false)) {
args.add(ARG_ENABLE_VULKAN_VALIDATION);
}
if (intent.getBooleanExtra(ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION, false)) {
args.add(ARG_DUMP_SHADER_SKP_ON_SHADER_COMPILATION);
}
if (intent.getBooleanExtra(ARG_KEY_CACHE_SKSL, false)) {
args.add(ARG_CACHE_SKSL);
}
if (intent.getBooleanExtra(ARG_KEY_PURGE_PERSISTENT_CACHE, false)) {
args.add(ARG_PURGE_PERSISTENT_CACHE);
}
if (intent.getBooleanExtra(ARG_KEY_VERBOSE_LOGGING, false)) {
args.add(ARG_VERBOSE_LOGGING);
}
// NOTE: all flags provided with this argument are subject to filtering
// based on a list of allowed flags in shell/common/switches.cc. If any
// flag provided is not allowed, the process will immediately terminate.
if (intent.hasExtra(ARG_KEY_DART_FLAGS)) {
args.add(ARG_DART_FLAGS + "=" + intent.getStringExtra(ARG_KEY_DART_FLAGS));
}
return new FlutterShellArgs(args);
}
/** Returns whether or not a flag is disabled and should raise an exception if used. */
public static boolean isDisabled(Flag flag) {
return DISABLED_FLAGS.contains(flag);
@NonNull private Set<String> args;
/**
* Creates a set of Flutter shell arguments from a given {@code String[]} array. The given
* arguments are automatically de-duplicated.
*/
public FlutterShellArgs(@NonNull String[] args) {
this.args = new HashSet<>(Arrays.asList(args));
}
/** Returns the replacement flag of that given if it is deprecated. */
public static Flag getReplacementFlagIfDeprecated(Flag flag) {
return DEPRECATED_FLAGS_BY_REPLACEMENT.get(flag);
/**
* Creates a set of Flutter shell arguments from a given {@code List<String>}. The given arguments
* are automatically de-duplicated.
*/
public FlutterShellArgs(@NonNull List<String> args) {
this.args = new HashSet<>(args);
}
/** Creates a set of Flutter shell arguments from a given {@code Set<String>}. */
public FlutterShellArgs(@NonNull Set<String> args) {
this.args = new HashSet<>(args);
}
/**
* Adds the given {@code arg} to this set of arguments.
*
* @param arg argument to add
*/
public void add(@NonNull String arg) {
args.add(arg);
}
/**
* Removes the given {@code arg} from this set of arguments.
*
* @param arg argument to remove
*/
public void remove(@NonNull String arg) {
args.remove(arg);
}
/**
* Returns a new {@code String[]} array which contains each of the arguments within this {@code
* FlutterShellArgs}.
*
* @return array of arguments
*/
@NonNull
public String[] toArray() {
String[] argsArray = new String[args.size()];
return args.toArray(argsArray);
}
}

View File

@ -1,169 +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.
package io.flutter.embedding.engine;
import android.content.Intent;
import androidx.annotation.NonNull;
import java.util.*;
/**
* Arguments that can be delivered to the Flutter shell on Android as Intent extras.
*
* <p>The term "shell" refers to the native code that adapts Flutter to different platforms.
* Flutter's Android Java code initializes a native "shell" and passes these arguments to that
* native "shell" when it is initialized. See {@link
* io.flutter.embedding.engine.loader.FlutterLoader#ensureInitializationComplete(Context, String[])}
* for more information.
*
* <p>All of these flags map to a flag listed in shell/common/switches.cc, which contains the full
* list of flags that can be set across all platforms.
*
* <p>These flags are preferably set via the manifest metadata in a Flutter component's
* AndroidManifest.xml or via the command line for security purposes as Intent extras may expose
* sensitive information to malicious actors. See {@link FlutterShellArgs} for the specification of
* how to set each flag via the command line and manifest metadata.
*/
// TODO(camsim99): Delete this class when support for setting engine shell arguments via Intent
// is no longer supported. See https://github.com/flutter/flutter/issues/180686.
public final class FlutterShellArgsIntentUtils {
private FlutterShellArgsIntentUtils() {}
public static final String ARG_KEY_TRACE_STARTUP = "trace-startup";
public static final String ARG_TRACE_STARTUP = "--trace-startup";
public static final String ARG_KEY_START_PAUSED = "start-paused";
public static final String ARG_START_PAUSED = "--start-paused";
public static final String ARG_KEY_DISABLE_SERVICE_AUTH_CODES = "disable-service-auth-codes";
public static final String ARG_DISABLE_SERVICE_AUTH_CODES = "--disable-service-auth-codes";
public static final String ARG_KEY_ENDLESS_TRACE_BUFFER = "endless-trace-buffer";
public static final String ARG_ENDLESS_TRACE_BUFFER = "--endless-trace-buffer";
public static final String ARG_KEY_USE_TEST_FONTS = "use-test-fonts";
public static final String ARG_USE_TEST_FONTS = "--use-test-fonts";
public static final String ARG_KEY_ENABLE_DART_PROFILING = "enable-dart-profiling";
public static final String ARG_ENABLE_DART_PROFILING = "--enable-dart-profiling";
public static final String ARG_KEY_PROFILE_STARTUP = "profile-startup";
public static final String ARG_PROFILE_STARTUP = "--profile-startup";
public static final String ARG_KEY_ENABLE_SOFTWARE_RENDERING = "enable-software-rendering";
public static final String ARG_ENABLE_SOFTWARE_RENDERING = "--enable-software-rendering";
public static final String ARG_KEY_SKIA_DETERMINISTIC_RENDERING = "skia-deterministic-rendering";
public static final String ARG_SKIA_DETERMINISTIC_RENDERING = "--skia-deterministic-rendering";
public static final String ARG_KEY_TRACE_SKIA = "trace-skia";
public static final String ARG_TRACE_SKIA = "--trace-skia";
public static final String ARG_KEY_TRACE_SKIA_ALLOWLIST = "trace-skia-allowlist";
public static final String ARG_TRACE_SKIA_ALLOWLIST = "--trace-skia-allowlist=";
public static final String ARG_KEY_TRACE_SYSTRACE = "trace-systrace";
public static final String ARG_TRACE_SYSTRACE = "--trace-systrace";
public static final String ARG_KEY_TRACE_TO_FILE = "trace-to-file";
public static final String ARG_TRACE_TO_FILE = "--trace-to-file";
public static final String ARG_KEY_PROFILE_MICROTASKS = "profile-microtasks";
public static final String ARG_PROFILE_MICROTASKS = "--profile-microtasks";
public static final String ARG_KEY_TOGGLE_IMPELLER = "enable-impeller";
public static final String ARG_ENABLE_IMPELLER = "--enable-impeller=true";
public static final String ARG_DISABLE_IMPELLER = "--enable-impeller=false";
public static final String ARG_KEY_ENABLE_VULKAN_VALIDATION = "enable-vulkan-validation";
public static final String ARG_ENABLE_VULKAN_VALIDATION = "--enable-vulkan-validation";
public static final String ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION =
"dump-skp-on-shader-compilation";
public static final String ARG_DUMP_SHADER_SKP_ON_SHADER_COMPILATION =
"--dump-skp-on-shader-compilation";
public static final String ARG_KEY_CACHE_SKSL = "cache-sksl";
public static final String ARG_CACHE_SKSL = "--cache-sksl";
public static final String ARG_KEY_PURGE_PERSISTENT_CACHE = "purge-persistent-cache";
public static final String ARG_PURGE_PERSISTENT_CACHE = "--purge-persistent-cache";
public static final String ARG_KEY_VERBOSE_LOGGING = "verbose-logging";
public static final String ARG_VERBOSE_LOGGING = "--verbose-logging";
public static final String ARG_KEY_VM_SERVICE_PORT = "vm-service-port";
public static final String ARG_VM_SERVICE_PORT = "--vm-service-port=";
public static final String ARG_KEY_DART_FLAGS = "dart-flags";
public static final String ARG_DART_FLAGS = "--dart-flags";
@NonNull
public static String[] getFlutterShellCommandLineArgs(@NonNull Intent intent) {
// Before adding more entries to this list, consider that arbitrary
// Android applications can generate intents with extra data and that
// there are many security-sensitive args in the binary.
ArrayList<String> args = new ArrayList<>();
if (intent.getBooleanExtra(ARG_KEY_TRACE_STARTUP, false)) {
args.add(ARG_TRACE_STARTUP);
}
if (intent.getBooleanExtra(ARG_KEY_START_PAUSED, false)) {
args.add(ARG_START_PAUSED);
}
int vmServicePort = intent.getIntExtra(ARG_KEY_VM_SERVICE_PORT, 0);
if (vmServicePort > 0) {
args.add(ARG_VM_SERVICE_PORT + vmServicePort);
}
if (intent.getBooleanExtra(ARG_KEY_DISABLE_SERVICE_AUTH_CODES, false)) {
args.add(ARG_DISABLE_SERVICE_AUTH_CODES);
}
if (intent.getBooleanExtra(ARG_KEY_ENDLESS_TRACE_BUFFER, false)) {
args.add(ARG_ENDLESS_TRACE_BUFFER);
}
if (intent.getBooleanExtra(ARG_KEY_USE_TEST_FONTS, false)) {
args.add(ARG_USE_TEST_FONTS);
}
if (intent.getBooleanExtra(ARG_KEY_ENABLE_DART_PROFILING, false)) {
args.add(ARG_ENABLE_DART_PROFILING);
}
if (intent.getBooleanExtra(ARG_KEY_PROFILE_STARTUP, false)) {
args.add(ARG_PROFILE_STARTUP);
}
if (intent.getBooleanExtra(ARG_KEY_ENABLE_SOFTWARE_RENDERING, false)) {
args.add(ARG_ENABLE_SOFTWARE_RENDERING);
}
if (intent.getBooleanExtra(ARG_KEY_SKIA_DETERMINISTIC_RENDERING, false)) {
args.add(ARG_SKIA_DETERMINISTIC_RENDERING);
}
if (intent.getBooleanExtra(ARG_KEY_TRACE_SKIA, false)) {
args.add(ARG_TRACE_SKIA);
}
String traceSkiaAllowlist = intent.getStringExtra(ARG_KEY_TRACE_SKIA_ALLOWLIST);
if (traceSkiaAllowlist != null) {
args.add(ARG_TRACE_SKIA_ALLOWLIST + traceSkiaAllowlist);
}
if (intent.getBooleanExtra(ARG_KEY_TRACE_SYSTRACE, false)) {
args.add(ARG_TRACE_SYSTRACE);
}
if (intent.hasExtra(ARG_KEY_TRACE_TO_FILE)) {
args.add(ARG_TRACE_TO_FILE + "=" + intent.getStringExtra(ARG_KEY_TRACE_TO_FILE));
}
if (intent.hasExtra(ARG_KEY_PROFILE_MICROTASKS)) {
args.add(ARG_PROFILE_MICROTASKS);
}
if (intent.hasExtra(ARG_KEY_TOGGLE_IMPELLER)) {
if (intent.getBooleanExtra(ARG_KEY_TOGGLE_IMPELLER, false)) {
args.add(ARG_ENABLE_IMPELLER);
} else {
args.add(ARG_DISABLE_IMPELLER);
}
}
if (intent.getBooleanExtra(ARG_KEY_ENABLE_VULKAN_VALIDATION, false)) {
args.add(ARG_ENABLE_VULKAN_VALIDATION);
}
if (intent.getBooleanExtra(ARG_KEY_DUMP_SHADER_SKP_ON_SHADER_COMPILATION, false)) {
args.add(ARG_DUMP_SHADER_SKP_ON_SHADER_COMPILATION);
}
if (intent.getBooleanExtra(ARG_KEY_CACHE_SKSL, false)) {
args.add(ARG_CACHE_SKSL);
}
if (intent.getBooleanExtra(ARG_KEY_PURGE_PERSISTENT_CACHE, false)) {
args.add(ARG_PURGE_PERSISTENT_CACHE);
}
if (intent.getBooleanExtra(ARG_KEY_VERBOSE_LOGGING, false)) {
args.add(ARG_VERBOSE_LOGGING);
}
// All flags provided with this argument are subject to filtering
// based on a list of allowed flags in shell/common/switches.cc. If any
// flag provided is not allowed, the process will immediately terminate.
if (intent.hasExtra(ARG_KEY_DART_FLAGS)) {
args.add(ARG_DART_FLAGS + "=" + intent.getStringExtra(ARG_KEY_DART_FLAGS));
}
String[] argsArray = new String[args.size()];
return args.toArray(argsArray);
}
}

View File

@ -10,7 +10,7 @@ import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.FlutterEngineFlags;
import java.io.IOException;
import org.json.JSONArray;
import org.xmlpull.v1.XmlPullParserException;
@ -162,14 +162,14 @@ public final class ApplicationInfoLoader {
return new FlutterApplicationInfo(
getStringWithFallback(
appInfo.metaData,
FlutterShellArgs.DEPRECATED_AOT_SHARED_LIBRARY_NAME.metadataKey,
FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.metadataKey),
getString(appInfo.metaData, FlutterShellArgs.VM_SNAPSHOT_DATA.metadataKey),
getString(appInfo.metaData, FlutterShellArgs.ISOLATE_SNAPSHOT_DATA.metadataKey),
FlutterEngineFlags.DEPRECATED_AOT_SHARED_LIBRARY_NAME.metadataKey,
FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME.metadataKey),
getString(appInfo.metaData, FlutterEngineFlags.VM_SNAPSHOT_DATA.metadataKey),
getString(appInfo.metaData, FlutterEngineFlags.ISOLATE_SNAPSHOT_DATA.metadataKey),
getStringWithFallback(
appInfo.metaData,
FlutterShellArgs.DEPRECATED_FLUTTER_ASSETS_DIR.metadataKey,
FlutterShellArgs.FLUTTER_ASSETS_DIR.metadataKey),
FlutterEngineFlags.DEPRECATED_FLUTTER_ASSETS_DIR.metadataKey,
FlutterEngineFlags.FLUTTER_ASSETS_DIR.metadataKey),
getNetworkPolicy(appInfo, applicationContext),
appInfo.nativeLibraryDir,
getBoolean(appInfo.metaData, PUBLIC_AUTOMATICALLY_REGISTER_PLUGINS_METADATA_KEY, true));

View File

@ -22,8 +22,8 @@ import androidx.annotation.VisibleForTesting;
import io.flutter.BuildConfig;
import io.flutter.FlutterInjector;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngineFlags;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.util.HandlerCompat;
import io.flutter.util.PathUtils;
import io.flutter.util.TraceSection;
@ -305,12 +305,12 @@ public class FlutterLoader {
// so we must add it here before adding flags from the manifest.
if (args != null) {
for (String arg : args) {
if (arg.startsWith(FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.commandLineArgument)) {
if (arg.startsWith(FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME.commandLineArgument)) {
// Perform security check for path containing application's compiled Dart
// code and potentially user-provided compiled native code.
String aotSharedLibraryPath =
arg.substring(
FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.commandLineArgument.length());
FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME.commandLineArgument.length());
maybeAddAotSharedLibraryNameArg(applicationContext, aotSharedLibraryPath, shellArgs);
break;
}
@ -334,27 +334,28 @@ public class FlutterLoader {
.filter(metadataKey -> !metadataKey.equals(FLUTTER_EMBEDDING_KEY))
.forEach(
metadataKey -> {
FlutterShellArgs.Flag flag = FlutterShellArgs.getFlagByMetadataKey(metadataKey);
FlutterEngineFlags.Flag flag =
FlutterEngineFlags.getFlagByMetadataKey(metadataKey);
if (flag == null) {
// Manifest flag was not recognized.
Log.w(
TAG,
"Flag with metadata key "
+ metadataKey
+ " is not recognized. Please ensure that the flag is defined in the FlutterShellArgs.");
+ " is not recognized. Please ensure that the flag is defined in the FlutterEngineFlags.");
return;
} else if (FlutterShellArgs.isDisabled(flag)) {
} else if (FlutterEngineFlags.isDisabled(flag)) {
// Do not allow disabled flags.
throw new IllegalArgumentException(
metadataKey
+ " is disabled and no longer allowed. Please remove this flag from your application manifest.");
} else if (FlutterShellArgs.getReplacementFlagIfDeprecated(flag) != null) {
} else if (FlutterEngineFlags.getReplacementFlagIfDeprecated(flag) != null) {
Log.w(
TAG,
"If you are trying to specify "
+ flag.metadataKey
+ " in your application manifest, please make sure to use the new metadata key name: "
+ FlutterShellArgs.getReplacementFlagIfDeprecated(flag).metadataKey);
+ FlutterEngineFlags.getReplacementFlagIfDeprecated(flag).metadataKey);
} else if (!flag.allowedInRelease && isRelease) {
// Manifest flag is not allowed in release builds.
Log.w(
@ -366,21 +367,21 @@ public class FlutterLoader {
}
// Handle special cases for specific flags.
if (flag == FlutterShellArgs.OLD_GEN_HEAP_SIZE) {
if (flag == FlutterEngineFlags.OLD_GEN_HEAP_SIZE) {
// Mark if old gen heap size is set to track whether or not to set default
// internally.
oldGenHeapSizeSet.set(true);
} else if (flag == FlutterShellArgs.LEAK_VM) {
} else if (flag == FlutterEngineFlags.LEAK_VM) {
// Mark if leak VM is set to track whether or not to set default internally.
isLeakVMSet.set(true);
} else if (flag == FlutterShellArgs.ENABLE_SOFTWARE_RENDERING) {
} else if (flag == FlutterEngineFlags.ENABLE_SOFTWARE_RENDERING) {
// Enabling software rendering impacts platform views, so save this value
// so that the PlatformViewsController can be properly configured.
enableSoftwareRendering =
applicationMetaData.getBoolean(
FlutterShellArgs.ENABLE_SOFTWARE_RENDERING.metadataKey, false);
} else if (flag == FlutterShellArgs.AOT_SHARED_LIBRARY_NAME
|| flag == FlutterShellArgs.DEPRECATED_AOT_SHARED_LIBRARY_NAME) {
FlutterEngineFlags.ENABLE_SOFTWARE_RENDERING.metadataKey, false);
} else if (flag == FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME
|| flag == FlutterEngineFlags.DEPRECATED_AOT_SHARED_LIBRARY_NAME) {
// Perform security check for path containing application's compiled Dart
// code and potentially user-provided compiled native code.
String aotSharedLibraryPath = applicationMetaData.getString(metadataKey);
@ -414,16 +415,16 @@ public class FlutterLoader {
// metadata and any defaults set below.
if (args != null) {
for (String arg : args) {
FlutterShellArgs.Flag flag = FlutterShellArgs.getFlagByCommandLineArgument(arg);
FlutterEngineFlags.Flag flag = FlutterEngineFlags.getFlagByCommandLineArgument(arg);
if (flag == null) {
// Command line flag was not recognized.
Log.w(
TAG,
"Command line argument "
+ arg
+ "is not recognized. Please ensure that the flag is defined in the FlutterShellArgs.");
+ "is not recognized. Please ensure that the flag is defined in the FlutterEngineFlags.");
continue;
} else if (flag.equals(FlutterShellArgs.AOT_SHARED_LIBRARY_NAME)) {
} else if (flag.equals(FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME)) {
// This flag has already been handled.
continue;
} else if (!flag.allowedInRelease && isRelease) {
@ -450,24 +451,24 @@ public class FlutterLoader {
kernelPath = snapshotAssetPath + File.separator + DEFAULT_KERNEL_BLOB;
shellArgs.add("--" + SNAPSHOT_ASSET_PATH_KEY + "=" + snapshotAssetPath);
shellArgs.add(
FlutterShellArgs.VM_SNAPSHOT_DATA.commandLineArgument
FlutterEngineFlags.VM_SNAPSHOT_DATA.commandLineArgument
+ flutterApplicationInfo.vmSnapshotData);
shellArgs.add(
FlutterShellArgs.ISOLATE_SNAPSHOT_DATA.commandLineArgument
FlutterEngineFlags.ISOLATE_SNAPSHOT_DATA.commandLineArgument
+ flutterApplicationInfo.isolateSnapshotData);
} else {
// Add default AOT shared library name arg. Note that if a different library
// is set in the manifest, that value will take precendence and the default
// libraries will be used as fallbacks in the order that they are added.
shellArgs.add(
FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.commandLineArgument
FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME.commandLineArgument
+ flutterApplicationInfo.aotSharedLibraryName);
// Some devices cannot load the an AOT shared library based on the library name
// with no directory path. So, we provide a fully qualified path to the default library
// as a workaround for devices where that fails.
shellArgs.add(
FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.commandLineArgument
FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME.commandLineArgument
+ flutterApplicationInfo.nativeLibraryDir
+ File.separator
+ flutterApplicationInfo.aotSharedLibraryName);
@ -496,7 +497,7 @@ public class FlutterLoader {
activityManager.getMemoryInfo(memInfo);
int oldGenHeapSizeMegaBytes = (int) (memInfo.totalMem / 1e6 / 2);
shellArgs.add(
FlutterShellArgs.OLD_GEN_HEAP_SIZE.commandLineArgument
FlutterEngineFlags.OLD_GEN_HEAP_SIZE.commandLineArgument
+ String.valueOf(oldGenHeapSizeMegaBytes));
}
@ -511,7 +512,7 @@ public class FlutterLoader {
shellArgs.add("--prefetched-default-font-manager");
if (!isLeakVMSet.get()) {
shellArgs.add(FlutterShellArgs.LEAK_VM.commandLineArgument + "true");
shellArgs.add(FlutterEngineFlags.LEAK_VM.commandLineArgument + "true");
}
long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
@ -550,7 +551,8 @@ public class FlutterLoader {
if (safeAotSharedLibraryName != null) {
shellArgs.add(
FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.commandLineArgument + safeAotSharedLibraryName);
FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME.commandLineArgument
+ safeAotSharedLibraryName);
} else {
// If the library path is not safe, we will skip adding this argument.
Log.w(

View File

@ -250,7 +250,7 @@ public class FlutterActivityTest {
assertNull(flutterActivity.getDartEntrypointLibraryUri());
assertNull(flutterActivity.getDartEntrypointArgs());
assertEquals("/", flutterActivity.getInitialRoute());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertNull(flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
@ -303,7 +303,7 @@ public class FlutterActivityTest {
assertEquals("/custom/route", flutterActivity.getInitialRoute());
assertArrayEquals(
new String[] {"foo", "bar"}, flutterActivity.getDartEntrypointArgs().toArray());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertNull(flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
@ -328,7 +328,7 @@ public class FlutterActivityTest {
assertEquals("my_cached_engine_group", flutterActivity.getCachedEngineGroupId());
assertEquals("custom_entrypoint", flutterActivity.getDartEntrypointFunctionName());
assertEquals("/custom/route", flutterActivity.getInitialRoute());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());
assertNull(flutterActivity.getCachedEngineId());
@ -393,7 +393,7 @@ public class FlutterActivityTest {
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertEquals("my_cached_engine", flutterActivity.getCachedEngineId());
assertFalse(flutterActivity.shouldDestroyEngineWithHost());
@ -409,7 +409,7 @@ public class FlutterActivityTest {
Robolectric.buildActivity(FlutterActivity.class, intent);
FlutterActivity flutterActivity = activityController.get();
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertEquals("my_cached_engine", flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());

View File

@ -31,6 +31,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
@ -301,8 +302,9 @@ public class FlutterAndroidComponentTest {
@NonNull
@Override
public String[] getFlutterShellArgs() {
return new String[0];
@SuppressWarnings("deprecation")
public FlutterShellArgs getFlutterShellArgs() {
return new FlutterShellArgs(new String[] {});
}
@Nullable

View File

@ -69,7 +69,7 @@ public class FlutterFragmentTest {
assertNull(fragment.getDartEntrypointLibraryUri());
assertNull(fragment.getDartEntrypointArgs());
assertEquals("/", fragment.getInitialRoute());
assertArrayEquals(new String[] {}, fragment.getFlutterShellArgs());
assertArrayEquals(new String[] {}, fragment.getFlutterShellArgs().toArray());
assertTrue(fragment.shouldAttachEngineToActivity());
assertFalse(fragment.shouldHandleDeeplinking());
assertNull(fragment.getCachedEngineId());
@ -100,7 +100,7 @@ public class FlutterFragmentTest {
assertEquals("package:foo/bar.dart", fragment.getDartEntrypointLibraryUri());
assertEquals("/custom/route", fragment.getInitialRoute());
assertArrayEquals(new String[] {"foo", "bar"}, fragment.getDartEntrypointArgs().toArray());
assertArrayEquals(new String[] {}, fragment.getFlutterShellArgs());
assertArrayEquals(new String[] {}, fragment.getFlutterShellArgs().toArray());
assertFalse(fragment.shouldAttachEngineToActivity());
assertTrue(fragment.shouldHandleDeeplinking());
assertNull(fragment.getCachedEngineId());
@ -129,7 +129,7 @@ public class FlutterFragmentTest {
assertEquals("my_cached_engine_group", fragment.getCachedEngineGroupId());
assertEquals("custom_entrypoint", fragment.getDartEntrypointFunctionName());
assertEquals("/custom/route", fragment.getInitialRoute());
assertArrayEquals(new String[] {}, fragment.getFlutterShellArgs());
assertArrayEquals(new String[] {}, fragment.getFlutterShellArgs().toArray());
assertFalse(fragment.shouldAttachEngineToActivity());
assertTrue(fragment.shouldHandleDeeplinking());
assertNull(fragment.getCachedEngineId());

View File

@ -0,0 +1,124 @@
// 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.
package io.flutter.embedding.engine;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.junit.Test;
public class FlutterEngineFlagsTest {
@Test
public void allFlags_containsAllFlags() {
// Count the number of declared flags in FlutterEngineFlags.
int declaredFlagsCount = 0;
for (Field field : FlutterEngineFlags.class.getDeclaredFields()) {
if (FlutterEngineFlags.Flag.class.isAssignableFrom(field.getType())
&& Modifier.isStatic(field.getModifiers())
&& Modifier.isFinal(field.getModifiers())) {
declaredFlagsCount++;
}
}
// Check that the number of declared flags matches the size of ALL_FLAGS.
assertEquals(
"If you are adding a new Flag to FlutterEngineFlags, please make sure it is added to ALL_FLAGS as well. Otherwise, the flag will be silently ignored when specified.",
declaredFlagsCount,
FlutterEngineFlags.ALL_FLAGS.size());
}
@SuppressWarnings("deprecation")
@Test
public void allFlags_haveExpectedMetaDataNamePrefix() {
String defaultPrefix = "io.flutter.embedding.android.";
for (FlutterEngineFlags.Flag flag : FlutterEngineFlags.ALL_FLAGS) {
// Test all non-deprecated flags that should have the default prefix.
if (!flag.equals(FlutterEngineFlags.DEPRECATED_AOT_SHARED_LIBRARY_NAME)
&& !flag.equals(FlutterEngineFlags.DEPRECATED_FLUTTER_ASSETS_DIR)) {
assertTrue(
"Flag " + flag.commandLineArgument + " does not have the correct metadata key prefix.",
flag.metadataKey.startsWith(defaultPrefix));
}
}
}
@Test
public void getFlagByMetadataKey_returnsExpectedFlagWhenValidKeySpecified() {
FlutterEngineFlags.Flag flag =
FlutterEngineFlags.getFlagByMetadataKey(
"io.flutter.embedding.android.AOTSharedLibraryName");
assertEquals(FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME, flag);
}
@Test
public void getFlagByMetadataKey_returnsNullWhenInvalidKeySpecified() {
FlutterEngineFlags.Flag flag =
FlutterEngineFlags.getFlagByMetadataKey("io.flutter.embedding.android.InvalidMetaDataKey");
assertNull("Should return null for an invalid meta-data key", flag);
}
@Test
public void getFlagByCommandLineArgument_returnsExpectedFlagWhenValidArgumentSpecified() {
FlutterEngineFlags.Flag flag =
FlutterEngineFlags.getFlagByCommandLineArgument("--flutter-assets-dir=");
assertEquals(FlutterEngineFlags.FLUTTER_ASSETS_DIR, flag);
}
@Test
public void getFlagByCommandLineArgument_returnsNullWhenInvalidArgumentSpecified() {
assertNull(FlutterEngineFlags.getFlagFromIntentKey("--non-existent-flag"));
}
@Test
public void getFlagFromIntentKey_returnsExpectedFlagWhenValidKeySpecified() {
// Test flag without value.
FlutterEngineFlags.Flag flag = FlutterEngineFlags.getFlagFromIntentKey("old-gen-heap-size");
assertEquals(FlutterEngineFlags.OLD_GEN_HEAP_SIZE, flag);
// Test with flag.
flag = FlutterEngineFlags.getFlagFromIntentKey("vm-snapshot-data");
assertEquals(FlutterEngineFlags.VM_SNAPSHOT_DATA, flag);
}
@Test
public void getFlagFromIntentKey_returnsNullWhenInvalidKeySpecified() {
assertNull(FlutterEngineFlags.getFlagFromIntentKey("non-existent-flag"));
}
@Test
public void isDisabled_returnsTrueWhenFlagIsDisabled() {
assertTrue(FlutterEngineFlags.isDisabled(FlutterEngineFlags.DISABLE_MERGED_PLATFORM_UI_THREAD));
}
@Test
public void isDisabled_returnsFalseWhenFlagIsNotDisabled() {
assertFalse(FlutterEngineFlags.isDisabled(FlutterEngineFlags.VM_SNAPSHOT_DATA));
}
// Deprecated flags are tested in this test.
@SuppressWarnings("deprecation")
@Test
public void getReplacementFlagIfDeprecated_returnsExpectedFlag() {
assertEquals(
FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME,
FlutterEngineFlags.getReplacementFlagIfDeprecated(
FlutterEngineFlags.DEPRECATED_AOT_SHARED_LIBRARY_NAME));
assertEquals(
FlutterEngineFlags.FLUTTER_ASSETS_DIR,
FlutterEngineFlags.getReplacementFlagIfDeprecated(
FlutterEngineFlags.DEPRECATED_FLUTTER_ASSETS_DIR));
}
@Test
public void getReplacementFlagIfDeprecated_returnsNullWhenFlagIsNotDeprecated() {
assertNull(
FlutterEngineFlags.getReplacementFlagIfDeprecated(FlutterEngineFlags.VM_SNAPSHOT_DATA));
}
}

View File

@ -1,36 +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.
package test.io.flutter.embedding.engine;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Intent;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.flutter.embedding.engine.FlutterShellArgsIntentUtils;
import java.util.Arrays;
import java.util.HashSet;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class FlutterShellArgsIntentUtilsTest {
@Test
public void itProcessesShellFlags() {
// Setup the test.
Intent intent = new Intent();
intent.putExtra("dart-flags", "--observe --no-hot --no-pub");
intent.putExtra("trace-skia-allowlist", "skia.a,skia.b");
// Execute the behavior under test.
String[] args = FlutterShellArgsIntentUtils.getFlutterShellCommandLineArgs(intent);
HashSet<String> argValues = new HashSet<String>(Arrays.asList(args));
// Verify results.
assertEquals(2, argValues.size());
assertTrue(argValues.contains("--dart-flags=--observe --no-hot --no-pub"));
assertTrue(argValues.contains("--trace-skia-allowlist=skia.a,skia.b"));
}
}

View File

@ -2,121 +2,36 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.embedding.engine;
package test.io.flutter.embedding.engine;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import android.content.Intent;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.flutter.embedding.engine.FlutterShellArgs;
import java.util.Arrays;
import java.util.HashSet;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class FlutterShellArgsTest {
@Test
public void allFlags_containsAllFlags() {
// Count the number of declared flags in FlutterShellArgs.
int declaredFlagsCount = 0;
for (Field field : FlutterShellArgs.class.getDeclaredFields()) {
if (FlutterShellArgs.Flag.class.isAssignableFrom(field.getType())
&& Modifier.isStatic(field.getModifiers())
&& Modifier.isFinal(field.getModifiers())) {
declaredFlagsCount++;
}
}
// Check that the number of declared flags matches the size of ALL_FLAGS.
assertEquals(
"If you are adding a new Flag to FlutterShellArgs, please make sure it is added to ALL_FLAGS as well. Otherwise, the flag will be silently ignored when specified.",
declaredFlagsCount,
FlutterShellArgs.ALL_FLAGS.size());
}
@SuppressWarnings("deprecation")
@Test
public void allFlags_haveExpectedMetaDataNamePrefix() {
String defaultPrefix = "io.flutter.embedding.android.";
for (FlutterShellArgs.Flag flag : FlutterShellArgs.ALL_FLAGS) {
// Test all non-deprecated flags that should have the default prefix.
if (!flag.equals(FlutterShellArgs.DEPRECATED_AOT_SHARED_LIBRARY_NAME)
&& !flag.equals(FlutterShellArgs.DEPRECATED_FLUTTER_ASSETS_DIR)) {
assertTrue(
"Flag " + flag.commandLineArgument + " does not have the correct metadata key prefix.",
flag.metadataKey.startsWith(defaultPrefix));
}
}
}
public void itProcessesShellFlags() {
// Setup the test.
Intent intent = new Intent();
intent.putExtra("dart-flags", "--observe --no-hot --no-pub");
intent.putExtra("trace-skia-allowlist", "skia.a,skia.b");
@Test
public void getFlagByMetadataKey_returnsExpectedFlagWhenValidKeySpecified() {
FlutterShellArgs.Flag flag =
FlutterShellArgs.getFlagByMetadataKey("io.flutter.embedding.android.AOTSharedLibraryName");
assertEquals(FlutterShellArgs.AOT_SHARED_LIBRARY_NAME, flag);
}
// Execute the behavior under test.
FlutterShellArgs args = FlutterShellArgs.fromIntent(intent);
HashSet<String> argValues = new HashSet<String>(Arrays.asList(args.toArray()));
@Test
public void getFlagByMetadataKey_returnsNullWhenInvalidKeySpecified() {
FlutterShellArgs.Flag flag =
FlutterShellArgs.getFlagByMetadataKey("io.flutter.embedding.android.InvalidMetaDataKey");
assertNull("Should return null for an invalid meta-data key", flag);
}
@Test
public void getFlagByCommandLineArgument_returnsExpectedFlagWhenValidArgumentSpecified() {
FlutterShellArgs.Flag flag =
FlutterShellArgs.getFlagByCommandLineArgument("--flutter-assets-dir=");
assertEquals(FlutterShellArgs.FLUTTER_ASSETS_DIR, flag);
}
@Test
public void getFlagByCommandLineArgument_returnsNullWhenInvalidArgumentSpecified() {
assertNull(FlutterShellArgs.getFlagFromIntentKey("--non-existent-flag"));
}
@Test
public void getFlagFromIntentKey_returnsExpectedFlagWhenValidKeySpecified() {
// Test flag without value.
FlutterShellArgs.Flag flag = FlutterShellArgs.getFlagFromIntentKey("old-gen-heap-size");
assertEquals(FlutterShellArgs.OLD_GEN_HEAP_SIZE, flag);
// Test with flag.
flag = FlutterShellArgs.getFlagFromIntentKey("vm-snapshot-data");
assertEquals(FlutterShellArgs.VM_SNAPSHOT_DATA, flag);
}
@Test
public void getFlagFromIntentKey_returnsNullWhenInvalidKeySpecified() {
assertNull(FlutterShellArgs.getFlagFromIntentKey("non-existent-flag"));
}
@Test
public void isDisabled_returnsTrueWhenFlagIsDisabled() {
assertTrue(FlutterShellArgs.isDisabled(FlutterShellArgs.DISABLE_MERGED_PLATFORM_UI_THREAD));
}
@Test
public void isDisabled_returnsFalseWhenFlagIsNotDisabled() {
assertFalse(FlutterShellArgs.isDisabled(FlutterShellArgs.VM_SNAPSHOT_DATA));
}
// Deprecated flags are tested in this test.
@SuppressWarnings("deprecation")
@Test
public void getReplacementFlagIfDeprecated_returnsExpectedFlag() {
assertEquals(
FlutterShellArgs.AOT_SHARED_LIBRARY_NAME,
FlutterShellArgs.getReplacementFlagIfDeprecated(
FlutterShellArgs.DEPRECATED_AOT_SHARED_LIBRARY_NAME));
assertEquals(
FlutterShellArgs.FLUTTER_ASSETS_DIR,
FlutterShellArgs.getReplacementFlagIfDeprecated(
FlutterShellArgs.DEPRECATED_FLUTTER_ASSETS_DIR));
}
@Test
public void getReplacementFlagIfDeprecated_returnsNullWhenFlagIsNotDeprecated() {
assertNull(FlutterShellArgs.getReplacementFlagIfDeprecated(FlutterShellArgs.VM_SNAPSHOT_DATA));
// Verify results.
assertEquals(2, argValues.size());
assertTrue(argValues.contains("--dart-flags=--observe --no-hot --no-pub"));
assertTrue(argValues.contains("--trace-skia-allowlist=skia.a,skia.b"));
}
}

View File

@ -23,8 +23,8 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.flutter.embedding.engine.FlutterEngineFlags;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.FlutterShellArgs;
import java.io.File;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -129,8 +129,8 @@ public class PlayStoreDeferredComponentManagerTest {
TestFlutterJNI jni = new TestFlutterJNI();
Bundle bundle = new Bundle();
bundle.putString(FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.metadataKey, "custom_name.so");
bundle.putString(FlutterShellArgs.FLUTTER_ASSETS_DIR.metadataKey, "custom_assets");
bundle.putString(FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME.metadataKey, "custom_name.so");
bundle.putString(FlutterEngineFlags.FLUTTER_ASSETS_DIR.metadataKey, "custom_assets");
Context spyContext = createSpyContext(bundle);
doReturn(null).when(spyContext).getAssets();
@ -162,7 +162,7 @@ public class PlayStoreDeferredComponentManagerTest {
Bundle bundle = new Bundle();
bundle.putString(PlayStoreDeferredComponentManager.MAPPING_KEY, "123:module:custom_name.so");
bundle.putString(FlutterShellArgs.FLUTTER_ASSETS_DIR.metadataKey, "custom_assets");
bundle.putString(FlutterEngineFlags.FLUTTER_ASSETS_DIR.metadataKey, "custom_assets");
Context spyContext = createSpyContext(bundle);
doReturn(null).when(spyContext).getAssets();
@ -194,7 +194,7 @@ public class PlayStoreDeferredComponentManagerTest {
Bundle bundle = new Bundle();
bundle.putString(
PlayStoreDeferredComponentManager.MAPPING_KEY, "123:module:custom_name.so,3:,4:");
bundle.putString(FlutterShellArgs.FLUTTER_ASSETS_DIR.metadataKey, "custom_assets");
bundle.putString(FlutterEngineFlags.FLUTTER_ASSETS_DIR.metadataKey, "custom_assets");
Context spyContext = createSpyContext(bundle);
doReturn(null).when(spyContext).getAssets();

View File

@ -23,7 +23,7 @@ import android.content.res.XmlResourceParser;
import android.os.Bundle;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.FlutterEngineFlags;
import java.io.StringReader;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -71,10 +71,10 @@ public class ApplicationInfoLoaderTest {
@Test
public void itGeneratesCorrectApplicationInfoWithCustomValues() throws Exception {
Bundle bundle = new Bundle();
bundle.putString(FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.metadataKey, "testaot");
bundle.putString(FlutterShellArgs.VM_SNAPSHOT_DATA.metadataKey, "testvmsnapshot");
bundle.putString(FlutterShellArgs.ISOLATE_SNAPSHOT_DATA.metadataKey, "testisolatesnapshot");
bundle.putString(FlutterShellArgs.FLUTTER_ASSETS_DIR.metadataKey, "testassets");
bundle.putString(FlutterEngineFlags.AOT_SHARED_LIBRARY_NAME.metadataKey, "testaot");
bundle.putString(FlutterEngineFlags.VM_SNAPSHOT_DATA.metadataKey, "testvmsnapshot");
bundle.putString(FlutterEngineFlags.ISOLATE_SNAPSHOT_DATA.metadataKey, "testisolatesnapshot");
bundle.putString(FlutterEngineFlags.FLUTTER_ASSETS_DIR.metadataKey, "testassets");
Context context = generateMockContext(bundle, null);
FlutterApplicationInfo info = ApplicationInfoLoader.load(context);
assertNotNull(info);

View File

@ -971,8 +971,13 @@ public class FlutterLoaderTest {
@Test
public void itSetsEnableDartProfilingFromMetadata() {
// Test debug mode.
testFlagFromMetadataPresent(
"io.flutter.embedding.android.EnableDartProfiling", true, "--enable-dart-profiling");
// Test release mode.
testFlagFromMetadataPresentInReleaseMode(
"io.flutter.embedding.android.EnableDartProfiling", true, "--enable-dart-profiling");
}
@Test

View File

@ -26,7 +26,7 @@ public class FlutterLaunchTests {
assertEquals("main", flutterActivity.getDartEntrypointFunctionName());
assertEquals("/", flutterActivity.getInitialRoute());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs());
assertArrayEquals(new String[] {}, flutterActivity.getFlutterShellArgs().toArray());
assertTrue(flutterActivity.shouldAttachEngineToActivity());
assertNull(flutterActivity.getCachedEngineId());
assertTrue(flutterActivity.shouldDestroyEngineWithHost());

View File

@ -42,7 +42,7 @@ public class MainActivity extends AppCompatActivity {
"trace-startup", "start-paused", "enable-dart-profiling");
for (String flag : previouslySupportedFlagsViaIntent) {
if (intent.hasExtra(flag)) {
Log.w("MainActivity", "Engine flags can no longer be set via Intent on Android. If you wish to set " + flag + ", see https://github.com/flutter/flutter/blob/main/docs/engine/Android-Flutter-Shell-Arguments.md for alternative methods.");
Log.w("MainActivity", "Engine flags can no longer be set via Intent on Android. If you wish to set " + flag + ", see https://github.com/flutter/flutter/blob/main/docs/engine/Android-Flutter-Engine-Flags.md for alternative methods.");
break;
}
}