Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 40136ed

Browse files
Clone the parent Android engine's asset provider into a spawned engine (#41642)
Typically the AndroidShellHolder's apk_asset_provider_ is set by AndroidShellHolder::Launch when the DartExecutor runs the engine's entrypoint. But if the engine was started by Spawn, then the apk_asset_provider_ was not being set. This would cause a crash if the resulting engine was later used to spawn another engine. Fixes flutter/flutter#122364
1 parent 53c192f commit 40136ed

File tree

6 files changed

+88
-4
lines changed

6 files changed

+88
-4
lines changed

shell/platform/android/android_shell_holder.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,14 @@ AndroidShellHolder::AndroidShellHolder(
180180
const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade,
181181
const std::shared_ptr<ThreadHost>& thread_host,
182182
std::unique_ptr<Shell> shell,
183+
std::unique_ptr<APKAssetProvider> apk_asset_provider,
183184
const fml::WeakPtr<PlatformViewAndroid>& platform_view)
184185
: settings_(settings),
185186
jni_facade_(jni_facade),
186187
platform_view_(platform_view),
187188
thread_host_(thread_host),
188-
shell_(std::move(shell)) {
189+
shell_(std::move(shell)),
190+
apk_asset_provider_(std::move(apk_asset_provider)) {
189191
FML_DCHECK(jni_facade);
190192
FML_DCHECK(shell_);
191193
FML_DCHECK(shell_->IsSetup());
@@ -270,9 +272,9 @@ std::unique_ptr<AndroidShellHolder> AndroidShellHolder::Spawn(
270272
shell_->Spawn(std::move(config.value()), initial_route,
271273
on_create_platform_view, on_create_rasterizer);
272274

273-
return std::unique_ptr<AndroidShellHolder>(
274-
new AndroidShellHolder(GetSettings(), jni_facade, thread_host_,
275-
std::move(shell), weak_platform_view));
275+
return std::unique_ptr<AndroidShellHolder>(new AndroidShellHolder(
276+
GetSettings(), jni_facade, thread_host_, std::move(shell),
277+
apk_asset_provider_->Clone(), weak_platform_view));
276278
}
277279

278280
void AndroidShellHolder::Launch(

shell/platform/android/android_shell_holder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class AndroidShellHolder {
128128
const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade,
129129
const std::shared_ptr<ThreadHost>& thread_host,
130130
std::unique_ptr<Shell> shell,
131+
std::unique_ptr<APKAssetProvider> apk_asset_provider,
131132
const fml::WeakPtr<PlatformViewAndroid>& platform_view);
132133
static void ThreadDestructCallback(void* value);
133134
std::optional<RunConfiguration> BuildRunConfiguration(

testing/scenario_app/android/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ _android_sources = [
2121
"app/src/androidTest/java/dev/flutter/scenariosui/PlatformViewWithTextureViewUiTest.java",
2222
"app/src/androidTest/java/dev/flutter/scenariosui/ScreenshotUtil.java",
2323
"app/src/androidTest/java/dev/flutter/scenariosui/SpawnEngineTests.java",
24+
"app/src/androidTest/java/dev/flutter/scenariosui/SpawnMultiEngineTest.java",
2425
"app/src/main/AndroidManifest.xml",
2526
"app/src/main/java/dev/flutter/scenarios/GetBitmapActivity.java",
2627
"app/src/main/java/dev/flutter/scenarios/PlatformViewsActivity.java",
28+
"app/src/main/java/dev/flutter/scenarios/SpawnMultiEngineActivity.java",
2729
"app/src/main/java/dev/flutter/scenarios/SpawnedEngineActivity.java",
2830
"app/src/main/java/dev/flutter/scenarios/StrictModeFlutterActivity.java",
2931
"app/src/main/java/dev/flutter/scenarios/SurfacePlatformViewFactory.java",
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package dev.flutter.scenariosui;
6+
7+
import android.content.Intent;
8+
import androidx.annotation.NonNull;
9+
import androidx.test.filters.LargeTest;
10+
import androidx.test.rule.ActivityTestRule;
11+
import androidx.test.runner.AndroidJUnit4;
12+
import dev.flutter.scenarios.SpawnMultiEngineActivity;
13+
import org.junit.Before;
14+
import org.junit.Rule;
15+
import org.junit.Test;
16+
import org.junit.runner.RunWith;
17+
18+
@RunWith(AndroidJUnit4.class)
19+
@LargeTest
20+
public class SpawnMultiEngineTest {
21+
Intent intent;
22+
23+
@Rule @NonNull
24+
public ActivityTestRule<SpawnMultiEngineActivity> activityRule =
25+
new ActivityTestRule<>(
26+
SpawnMultiEngineActivity.class, /*initialTouchMode=*/ false, /*launchActivity=*/ false);
27+
28+
@Before
29+
public void setUp() {
30+
intent = new Intent(Intent.ACTION_MAIN);
31+
}
32+
33+
@Test
34+
public void testSpawnedEngine() throws Exception {
35+
activityRule.launchActivity(intent);
36+
}
37+
}

testing/scenario_app/android/app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@
3737
<category android:name="android.intent.category.LAUNCHER" />
3838
</intent-filter>
3939
</activity>
40+
<activity
41+
android:name=".SpawnMultiEngineActivity"
42+
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
43+
android:hardwareAccelerated="true"
44+
android:launchMode="singleTop"
45+
android:windowSoftInputMode="adjustResize"
46+
android:exported="true">
47+
<intent-filter>
48+
<action android:name="android.intent.action.MAIN" />
49+
<category android:name="android.intent.category.LAUNCHER" />
50+
</intent-filter>
51+
</activity>
4052
<activity
4153
android:name=".ExternalTextureFlutterActivity"
4254
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package dev.flutter.scenarios;
6+
7+
import android.content.Context;
8+
import androidx.annotation.NonNull;
9+
import io.flutter.embedding.engine.FlutterEngine;
10+
import io.flutter.embedding.engine.FlutterEngineGroup;
11+
12+
public class SpawnMultiEngineActivity extends TestActivity {
13+
static final String TAG = "Scenarios";
14+
15+
@Override
16+
@NonNull
17+
public FlutterEngine provideFlutterEngine(@NonNull Context context) {
18+
FlutterEngineGroup engineGroup = new FlutterEngineGroup(context);
19+
FlutterEngine firstEngine = engineGroup.createAndRunDefaultEngine(context);
20+
21+
FlutterEngine secondEngine = engineGroup.createAndRunDefaultEngine(context);
22+
23+
// Check that a new engine can be spawned from the group even if the group's
24+
// original engine has been destroyed.
25+
firstEngine.destroy();
26+
FlutterEngine thirdEngine = engineGroup.createAndRunDefaultEngine(context);
27+
28+
return thirdEngine;
29+
}
30+
}

0 commit comments

Comments
 (0)