Skip to content

Commit daf6d37

Browse files
committed
Maintain compatibility with deprecated flags
1 parent d81ca98 commit daf6d37

4 files changed

Lines changed: 189 additions & 60 deletions

File tree

engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,26 @@ public static class Flag {
3838
/**
3939
* The metadata key name used to specify the flag in AndroidManifest.xml.
4040
*
41-
* <p>To specify a flag in a manifest, it must be prefixed with {@code
41+
* <p>To specify a flag in a manifest, it should be prefixed with {@code
4242
* io.flutter.embedding.android.}. This is enforced to avoid potential naming collisions with
43-
* other metadata keys.
43+
* other metadata keys. The only exception are flags that have already been deprecated.
4444
*/
4545
public final String metadataKey;
4646

4747
/** Whether this flag is allowed to be set in release mode. */
4848
public final boolean allowedInRelease;
4949

50-
private String flagPrefix = "io.flutter.embedding.android.";
51-
52-
/** Creates a new Flutter shell flag that is not allowed in release mode. */
50+
/**
51+
* Creates a new Flutter shell flag that is not allowed in release mode with the default flag
52+
* prefix.
53+
*/
5354
private Flag(String commandLineArgument, String metaDataName) {
54-
this(commandLineArgument, metaDataName, false);
55+
this(commandLineArgument, metaDataName, "io.flutter.embedding.android.", false);
56+
}
57+
58+
/** Creates a new Flutter shell flag with the default flag prefix. */
59+
private Flag(String commandLineArgument, String metaDataName, boolean allowedInRelease) {
60+
this(commandLineArgument, metaDataName, "io.flutter.embedding.android.", allowedInRelease);
5561
}
5662

5763
/**
@@ -65,7 +71,11 @@ private Flag(String commandLineArgument, String metaDataName) {
6571
* <p>If creating a flag that will be allowed in release, please leave a comment in the Javadoc
6672
* explaining why it should be allowed in release.
6773
*/
68-
private Flag(String commandLineArgument, String metaDataName, boolean allowedInRelease) {
74+
private Flag(
75+
String commandLineArgument,
76+
String metaDataName,
77+
String flagPrefix,
78+
boolean allowedInRelease) {
6979
this.commandLineArgument = commandLineArgument;
7080
this.metadataKey = flagPrefix + metaDataName;
7181
this.allowedInRelease = allowedInRelease;
@@ -91,6 +101,20 @@ public boolean hasValue() {
91101
public static final Flag AOT_SHARED_LIBRARY_NAME =
92102
new Flag("--aot-shared-library-name=", "AOTSharedLibraryName", true);
93103

104+
/**
105+
* Deprecated flag that specifies the path to the AOT shared library containing compiled Dart
106+
* code.
107+
*
108+
* <p>Please use {@link AOT_SHARED_LIBRARY_NAME} instead.
109+
*/
110+
@Deprecated
111+
public static final Flag DEPRECATED_AOT_SHARED_LIBRARY_NAME =
112+
new Flag(
113+
"--aot-shared-library-name=",
114+
"aot-shared-library-name",
115+
"io.flutter.embedding.engine.loader.FlutterLoader.",
116+
true);
117+
94118
/**
95119
* Sets the directory containing Flutter assets.
96120
*
@@ -99,6 +123,19 @@ public boolean hasValue() {
99123
public static final Flag FLUTTER_ASSETS_DIR =
100124
new Flag("--flutter-assets-dir=", "FlutterAssetsDir", true);
101125

126+
/**
127+
* The deprecated flag that sets the directory containing Flutter assets.
128+
*
129+
* <p>Please use {@link DEPRECATED_FLUTTER_ASSETS_DIR} instead.
130+
*/
131+
@Deprecated
132+
public static final Flag DEPRECATED_FLUTTER_ASSETS_DIR =
133+
new Flag(
134+
"--flutter-assets-dir=",
135+
"flutter-assets-dir",
136+
"io.flutter.embedding.engine.loader.FlutterLoader.",
137+
true);
138+
102139
/**
103140
* Sets the old generation heap size for the Dart VM in megabytes.
104141
*
@@ -317,10 +354,26 @@ public boolean hasValue() {
317354
PURGE_PERSISTENT_CACHE,
318355
VERBOSE_LOGGING,
319356
DART_FLAGS,
320-
DISABLE_MERGED_PLATFORM_UI_THREAD));
357+
DISABLE_MERGED_PLATFORM_UI_THREAD,
358+
DEPRECATED_AOT_SHARED_LIBRARY_NAME,
359+
DEPRECATED_FLUTTER_ASSETS_DIR));
321360

322-
private static final List<Flag> DEPRECATED_FLAGS =
323-
Collections.unmodifiableList(Arrays.asList(DISABLE_MERGED_PLATFORM_UI_THREAD));
361+
// Flags that have been turned off.
362+
private static final List<Flag> DISABLED_FLAGS =
363+
Collections.unmodifiableList(
364+
Arrays.asList(
365+
DISABLE_MERGED_PLATFORM_UI_THREAD,
366+
DEPRECATED_AOT_SHARED_LIBRARY_NAME,
367+
DEPRECATED_FLUTTER_ASSETS_DIR));
368+
369+
// Lookup map for current flags that replace deprecated ones.
370+
private static final Map<Flag, Flag> DEPRECATED_FLAGS_BY_REPLACEMENT =
371+
new HashMap<Flag, Flag>() {
372+
{
373+
put(DEPRECATED_AOT_SHARED_LIBRARY_NAME, AOT_SHARED_LIBRARY_NAME);
374+
put(DEPRECATED_FLUTTER_ASSETS_DIR, FLUTTER_ASSETS_DIR);
375+
}
376+
};
324377

325378
// Lookup map for retrieving the Flag corresponding to a specific command line argument.
326379
private static final Map<String, Flag> FLAG_BY_COMMAND_LINE_ARG;
@@ -341,17 +394,18 @@ public boolean hasValue() {
341394

342395
/** Looks up a {@link Flag} by its metadataKey. */
343396
public static Flag getFlagByMetadataKey(String key) {
344-
return FLAG_BY_META_DATA_KEY.get(key);
397+
Flag flag = FLAG_BY_META_DATA_KEY.get(key);
398+
Flag replacementFlag = getReplacementFlagIfDeprecated(flag);
399+
return replacementFlag != null ? replacementFlag : flag;
345400
}
346401

347402
/** Looks up a {@link Flag} by its commandLineArgument. */
348403
public static Flag getFlagByCommandLineArgument(String arg) {
349404
int equalsIndex = arg.indexOf('=');
350-
if (equalsIndex == -1) {
351-
return FLAG_BY_COMMAND_LINE_ARG.get(arg);
352-
}
353-
// Return the part of the string including the '='
354-
return FLAG_BY_COMMAND_LINE_ARG.get(arg.substring(0, equalsIndex + 1));
405+
Flag flag =
406+
FLAG_BY_COMMAND_LINE_ARG.get(equalsIndex == -1 ? arg : arg.substring(0, equalsIndex + 1));
407+
Flag replacementFlag = getReplacementFlagIfDeprecated(flag);
408+
return replacementFlag != null ? replacementFlag : flag;
355409
}
356410

357411
/**
@@ -375,8 +429,13 @@ public static Flag getFlagFromIntentKey(String intentKey) {
375429
return null;
376430
}
377431

378-
/** Returns whether or not a flag is deprecated and should raise an exception if used. */
379-
public static boolean isDeprecated(Flag flag) {
380-
return DEPRECATED_FLAGS.contains(flag);
432+
/** Returns whether or not a flag is disabled and should raise an exception if used. */
433+
public static boolean isDisabled(Flag flag) {
434+
return DISABLED_FLAGS.contains(flag);
435+
}
436+
437+
/** Returns the replacement flag of that given if it is deprecated. */
438+
public static Flag getReplacementFlagIfDeprecated(Flag flag) {
439+
return DEPRECATED_FLAGS_BY_REPLACEMENT.get(flag);
381440
}
382441
}

engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,6 @@ public void ensureInitializationComplete(
316316
final AtomicBoolean oldGenHeapSizeSet = new AtomicBoolean(false);
317317
final AtomicBoolean isLeakVMSet = new AtomicBoolean(false);
318318

319-
warnIfDeprecatedManifestMetadataKeyUsed(applicationMetaData);
320-
321319
if (applicationMetaData != null) {
322320
applicationMetaData.keySet().stream()
323321
.filter(metadataKey -> !metadataKey.equals(FLUTTER_EMBEDDING_KEY))
@@ -332,11 +330,18 @@ public void ensureInitializationComplete(
332330
+ metadataKey
333331
+ " is not recognized. Please ensure that the flag is defined in the FlutterShellArgs.");
334332
return;
335-
} else if (FlutterShellArgs.isDeprecated(flag)) {
336-
// Do not allow deprecated flags.
333+
} else if (FlutterShellArgs.isDisabled(flag)) {
334+
// Do not allow disabled flags.
337335
throw new IllegalArgumentException(
338336
metadataKey
339337
+ " is deprecated and no longer allowed. Please remove this flag from your application manifest.");
338+
} else if (FlutterShellArgs.getReplacementFlagIfDeprecated(flag) != null) {
339+
Log.w(
340+
TAG,
341+
"If you are trying to specify "
342+
+ flag.metadataKey
343+
+ " in your application manifest, please make sure to use the new metadata key name: "
344+
+ FlutterShellArgs.getReplacementFlagIfDeprecated(flag).metadataKey);
340345
} else if (!flag.allowedInRelease && BuildConfig.RELEASE) {
341346
// Manifest flag is not allowed in release builds.
342347
Log.w(
@@ -361,7 +366,8 @@ public void ensureInitializationComplete(
361366
enableSoftwareRendering =
362367
applicationMetaData.getBoolean(
363368
FlutterShellArgs.ENABLE_SOFTWARE_RENDERING.metadataKey, false);
364-
} else if (flag == FlutterShellArgs.AOT_SHARED_LIBRARY_NAME) {
369+
} else if (flag == FlutterShellArgs.AOT_SHARED_LIBRARY_NAME
370+
|| flag == FlutterShellArgs.DEPRECATED_AOT_SHARED_LIBRARY_NAME) {
365371
// Perform security check for path containing application's compiled Dart
366372
// code and potentially user-provided compiled native code.
367373
String aotSharedLibraryPath = applicationMetaData.getString(metadataKey);
@@ -513,38 +519,6 @@ public void ensureInitializationComplete(
513519
}
514520
}
515521

516-
/**
517-
* Warns the developer to migrate old metadata keys to the new names if specified in their project
518-
* manifest.
519-
*/
520-
private void warnIfDeprecatedManifestMetadataKeyUsed(Bundle applicationMetaData) {
521-
if (applicationMetaData == null) {
522-
return;
523-
}
524-
525-
Map<String, String> deprecatedKeys = new HashMap<>();
526-
deprecatedKeys.put(
527-
"io.flutter.embedding.engine.loader.FlutterLoader.flutter-assets-dir",
528-
FlutterShellArgs.FLUTTER_ASSETS_DIR.metadataKey);
529-
deprecatedKeys.put(
530-
"io.flutter.embedding.engine.loader.FlutterLoader.aot-shared-library-name",
531-
FlutterShellArgs.AOT_SHARED_LIBRARY_NAME.metadataKey);
532-
533-
if (applicationMetaData != null) {
534-
for (Map.Entry<String, String> entry : deprecatedKeys.entrySet()) {
535-
String key = entry.getKey();
536-
if (applicationMetaData.getString(key) != null) {
537-
Log.w(
538-
TAG,
539-
"If you are trying to specify "
540-
+ key
541-
+ " in your application manifest, please make sure to use the new metadata key name: "
542-
+ entry.getValue());
543-
}
544-
}
545-
}
546-
}
547-
548522
/** Adds the AOT shared library name argument to the shell args if the provided path is safe. */
549523
private void maybeAddAotSharedLibraryNameArg(
550524
@NonNull Context applicationContext,

engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/FlutterShellArgsTest.java

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ public void allFlags_containsAllFlags() {
3434
FlutterShellArgs.ALL_FLAGS.size());
3535
}
3636

37+
@SuppressWarnings("deprecation")
38+
@Test
39+
public void allFlags_haveExpectedMetaDataNamePrefix() {
40+
String defaultPrefix = "io.flutter.embedding.android.";
41+
for (FlutterShellArgs.Flag flag : FlutterShellArgs.ALL_FLAGS) {
42+
// Test all non-deprecated flags that should have the default prefix.
43+
if (!flag.equals(FlutterShellArgs.DEPRECATED_AOT_SHARED_LIBRARY_NAME)
44+
&& !flag.equals(FlutterShellArgs.DEPRECATED_FLUTTER_ASSETS_DIR)) {
45+
assertTrue(
46+
"Flag " + flag.commandLineArgument + " does not have the correct metadata key prefix.",
47+
flag.metadataKey.startsWith(defaultPrefix));
48+
}
49+
}
50+
}
51+
3752
@Test
3853
public void getFlagByMetadataKey_returnsExpectedFlagWhenValidKeySpecified() {
3954
FlutterShellArgs.Flag flag =
@@ -77,12 +92,31 @@ public void getFlagFromIntentKey_returnsNullWhenInvalidKeySpecified() {
7792
}
7893

7994
@Test
80-
public void isDeprecated_returnsTrueWhenFlagIsDeprecated() {
81-
assertTrue(FlutterShellArgs.isDeprecated(FlutterShellArgs.DISABLE_MERGED_PLATFORM_UI_THREAD));
95+
public void isDisabled_returnsTrueWhenFlagIsDisabled() {
96+
assertTrue(FlutterShellArgs.isDisabled(FlutterShellArgs.DISABLE_MERGED_PLATFORM_UI_THREAD));
97+
}
98+
99+
@Test
100+
public void isDisabled_returnsFalseWhenFlagIsNotDisabled() {
101+
assertFalse(FlutterShellArgs.isDisabled(FlutterShellArgs.VM_SNAPSHOT_DATA));
102+
}
103+
104+
// Deprecated flags are tested in this test.
105+
@SuppressWarnings("deprecation")
106+
@Test
107+
public void getReplacementFlagIfDeprecated_returnsExpectedFlag() {
108+
assertEquals(
109+
FlutterShellArgs.AOT_SHARED_LIBRARY_NAME,
110+
FlutterShellArgs.getReplacementFlagIfDeprecated(
111+
FlutterShellArgs.DEPRECATED_AOT_SHARED_LIBRARY_NAME));
112+
assertEquals(
113+
FlutterShellArgs.FLUTTER_ASSETS_DIR,
114+
FlutterShellArgs.getReplacementFlagIfDeprecated(
115+
FlutterShellArgs.DEPRECATED_FLUTTER_ASSETS_DIR));
82116
}
83117

84118
@Test
85-
public void isDeprecated_returnsFalseWhenFlagIsNotDeprecated() {
86-
assertFalse(FlutterShellArgs.isDeprecated(FlutterShellArgs.VM_SNAPSHOT_DATA));
119+
public void getReplacementFlagIfDeprecated_returnsNullWhenFlagIsNotDeprecated() {
120+
assertNull(FlutterShellArgs.getReplacementFlagIfDeprecated(FlutterShellArgs.VM_SNAPSHOT_DATA));
87121
}
88122
}

engine/src/flutter/shell/platform/android/test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,59 @@ public void itDoesNotSetEnableVulkanValidationByDefault() {
265265
assertFalse(arguments.contains(enableVulkanValidationArg));
266266
}
267267

268+
@Test
269+
public void itSetsDeprecatedAotSharedLibraryNameIfPathIsInInternalStorage() throws IOException {
270+
FlutterJNI mockFlutterJNI = mock(FlutterJNI.class);
271+
FlutterLoader flutterLoader = spy(new FlutterLoader(mockFlutterJNI));
272+
Context mockApplicationContext = mock(Context.class);
273+
File internalStorageDir = ctx.getFilesDir();
274+
Path internalStorageDirAsPathObj = internalStorageDir.toPath();
275+
276+
ctx.getApplicationInfo().nativeLibraryDir =
277+
Paths.get("some", "path", "doesnt", "matter").toString();
278+
assertFalse(flutterLoader.initialized());
279+
flutterLoader.startInitialization(ctx);
280+
281+
// Test paths for library living within internal storage.
282+
String librarySoFileName = "library.so";
283+
Path testPath = internalStorageDirAsPathObj.resolve(librarySoFileName);
284+
285+
String path = testPath.toString();
286+
Bundle metadata = new Bundle();
287+
metadata.putString(
288+
"io.flutter.embedding.engine.loader.FlutterLoader.aot-shared-library-name", path);
289+
ctx.getApplicationInfo().metaData = metadata;
290+
291+
flutterLoader.ensureInitializationComplete(ctx, null);
292+
293+
ArgumentCaptor<String[]> shellArgsCaptor = ArgumentCaptor.forClass(String[].class);
294+
verify(mockFlutterJNI)
295+
.init(
296+
eq(ctx),
297+
shellArgsCaptor.capture(),
298+
anyString(),
299+
anyString(),
300+
anyString(),
301+
anyLong(),
302+
anyInt());
303+
304+
List<String> actualArgs = Arrays.asList(shellArgsCaptor.getValue());
305+
306+
// This check works because the tests run in debug mode. If run in release (or JIT release)
307+
// mode, actualArgs would contain the default arguments for AOT shared library name on top
308+
// of aotSharedLibraryNameArg.
309+
String canonicalTestPath = testPath.toFile().getCanonicalPath();
310+
String canonicalAotSharedLibraryNameArg = "--aot-shared-library-name=" + canonicalTestPath;
311+
assertTrue(
312+
"Args sent to FlutterJni.init incorrectly did not include path " + path,
313+
actualArgs.contains(canonicalAotSharedLibraryNameArg));
314+
315+
// Reset FlutterLoader and mockFlutterJNI to make more calls to
316+
// FlutterLoader.ensureInitialized and mockFlutterJNI.init for testing.
317+
flutterLoader.initialized = false;
318+
clearInvocations(mockFlutterJNI);
319+
}
320+
268321
@Test
269322
public void itSetsAotSharedLibraryNameIfPathIsInInternalStorage() throws IOException {
270323
FlutterJNI mockFlutterJNI = mock(FlutterJNI.class);
@@ -634,6 +687,15 @@ public void itSetsFlutterAssetsDirFromMetadata() {
634687
"--flutter-assets-dir=" + expectedAssetsDir);
635688
}
636689

690+
@Test
691+
public void itSetsDeprecatedFlutterAssetsDirFromMetadata() {
692+
String expectedAssetsDir = "flutter_assets_dir";
693+
testFlagFromMetaData(
694+
"io.flutter.embedding.engine.loader.FlutterLoader.flutter-assets-dir",
695+
expectedAssetsDir,
696+
"--flutter-assets-dir=" + expectedAssetsDir);
697+
}
698+
637699
@Test
638700
public void itSetsOldGenHeapSizeFromMetaData() {
639701
// Test old gen heap size can be set from metadata.

0 commit comments

Comments
 (0)