Skip to content

Commit e120494

Browse files
authored
Fix deferred components startup threading and improve .so search algorithm. (flutter#26429)
1 parent a832502 commit e120494

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

shell/common/shell.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,8 +1313,15 @@ void Shell::LoadDartDeferredLibrary(
13131313
intptr_t loading_unit_id,
13141314
std::unique_ptr<const fml::Mapping> snapshot_data,
13151315
std::unique_ptr<const fml::Mapping> snapshot_instructions) {
1316-
engine_->LoadDartDeferredLibrary(loading_unit_id, std::move(snapshot_data),
1317-
std::move(snapshot_instructions));
1316+
task_runners_.GetUITaskRunner()->PostTask(fml::MakeCopyable(
1317+
[engine = engine_->GetWeakPtr(), loading_unit_id,
1318+
data = std::move(snapshot_data),
1319+
instructions = std::move(snapshot_instructions)]() mutable {
1320+
if (engine) {
1321+
engine->LoadDartDeferredLibrary(loading_unit_id, std::move(data),
1322+
std::move(instructions));
1323+
}
1324+
}));
13181325
}
13191326

13201327
void Shell::LoadDartDeferredLibraryError(intptr_t loading_unit_id,

shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,18 +425,34 @@ public void loadDartLibrary(int loadingUnitId, String componentName) {
425425
List<String> apkPaths = new ArrayList<>();
426426
// If not found in APKs, we check in extracted native libs for the lib directly.
427427
List<String> soPaths = new ArrayList<>();
428+
428429
Queue<File> searchFiles = new LinkedList<>();
430+
// Downloaded modules are stored here
429431
searchFiles.add(context.getFilesDir());
432+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
433+
// The initial installed apks are provided by `sourceDirs` in ApplicationInfo.
434+
// The jniLibs we want are in the splits not the baseDir. These
435+
// APKs are only searched as a fallback, as base libs generally do not need
436+
// to be fully path referenced.
437+
for (String path : context.getApplicationInfo().splitSourceDirs) {
438+
searchFiles.add(new File(path));
439+
}
440+
}
441+
430442
while (!searchFiles.isEmpty()) {
431443
File file = searchFiles.remove();
432-
if (file != null && file.isDirectory()) {
444+
if (file != null && file.isDirectory() && file.listFiles() != null) {
433445
for (File f : file.listFiles()) {
434446
searchFiles.add(f);
435447
}
436448
continue;
437449
}
438450
String name = file.getName();
439-
if (name.endsWith(".apk") && name.startsWith(componentName) && name.contains(pathAbi)) {
451+
// Special case for "split_config" since android base module non-master apks are
452+
// initially installed with the "split_config" prefix/name.
453+
if (name.endsWith(".apk")
454+
&& (name.startsWith(componentName) || name.startsWith("split_config"))
455+
&& name.contains(pathAbi)) {
440456
apkPaths.add(file.getAbsolutePath());
441457
continue;
442458
}
@@ -459,7 +475,7 @@ public void loadDartLibrary(int loadingUnitId, String componentName) {
459475
}
460476

461477
flutterJNI.loadDartDeferredLibrary(
462-
loadingUnitId, searchPaths.toArray(new String[apkPaths.size()]));
478+
loadingUnitId, searchPaths.toArray(new String[searchPaths.size()]));
463479
}
464480

465481
public boolean uninstallDeferredComponent(int loadingUnitId, String componentName) {

shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import static org.mockito.Mockito.spy;
1515
import static org.mockito.Mockito.when;
1616

17+
import android.annotation.TargetApi;
1718
import android.content.Context;
1819
import android.content.pm.ApplicationInfo;
1920
import android.content.pm.PackageManager;
@@ -32,6 +33,7 @@
3233

3334
@Config(manifest = Config.NONE)
3435
@RunWith(RobolectricTestRunner.class)
36+
@TargetApi(21)
3537
public class PlayStoreDeferredComponentManagerTest {
3638
private class TestFlutterJNI extends FlutterJNI {
3739
public int loadDartDeferredLibraryCalled = 0;
@@ -90,9 +92,12 @@ private Context createSpyContext(Bundle metadata) throws NameNotFoundException {
9092
PackageManager packageManager = mock(PackageManager.class);
9193
ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
9294
applicationInfo.metaData = metadata;
95+
applicationInfo.splitSourceDirs = new String[1];
96+
applicationInfo.splitSourceDirs[0] = "some.invalid.apk";
9397
when(packageManager.getApplicationInfo(any(String.class), any(int.class)))
9498
.thenReturn(applicationInfo);
9599
doReturn(packageManager).when(spyContext).getPackageManager();
100+
doReturn(applicationInfo).when(spyContext).getApplicationInfo();
96101
return spyContext;
97102
}
98103

@@ -239,6 +244,30 @@ public void searchPathsAddsApks() throws NameNotFoundException {
239244
assertEquals(jni.loadingUnitId, 123);
240245
}
241246

247+
@Test
248+
public void searchPathsSearchesSplitConfig() throws NameNotFoundException {
249+
TestFlutterJNI jni = new TestFlutterJNI();
250+
Context spyContext = createSpyContext(null);
251+
doReturn(null).when(spyContext).getAssets();
252+
String apkTestPath = "test/path/split_config.armeabi_v7a.apk";
253+
doReturn(new File(apkTestPath)).when(spyContext).getFilesDir();
254+
TestPlayStoreDeferredComponentManager playStoreManager =
255+
new TestPlayStoreDeferredComponentManager(spyContext, jni);
256+
jni.setDeferredComponentManager(playStoreManager);
257+
258+
assertEquals(jni.loadingUnitId, 0);
259+
260+
playStoreManager.installDeferredComponent(123, "TestModuleName");
261+
assertEquals(jni.loadDartDeferredLibraryCalled, 1);
262+
assertEquals(jni.updateAssetManagerCalled, 1);
263+
assertEquals(jni.deferredComponentInstallFailureCalled, 0);
264+
265+
assertEquals(jni.searchPaths[0], "libapp.so-123.part.so");
266+
assertTrue(jni.searchPaths[1].endsWith(apkTestPath + "!lib/armeabi-v7a/libapp.so-123.part.so"));
267+
assertEquals(jni.searchPaths.length, 2);
268+
assertEquals(jni.loadingUnitId, 123);
269+
}
270+
242271
@Test
243272
public void invalidSearchPathsAreIgnored() throws NameNotFoundException {
244273
TestFlutterJNI jni = new TestFlutterJNI();

0 commit comments

Comments
 (0)