Skip to content

Commit

Permalink
Fix deferred components startup threading and improve .so search algo…
Browse files Browse the repository at this point in the history
…rithm. (flutter#26429)
  • Loading branch information
GaryQian authored May 27, 2021
1 parent a832502 commit e120494
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 5 deletions.
11 changes: 9 additions & 2 deletions shell/common/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1313,8 +1313,15 @@ void Shell::LoadDartDeferredLibrary(
intptr_t loading_unit_id,
std::unique_ptr<const fml::Mapping> snapshot_data,
std::unique_ptr<const fml::Mapping> snapshot_instructions) {
engine_->LoadDartDeferredLibrary(loading_unit_id, std::move(snapshot_data),
std::move(snapshot_instructions));
task_runners_.GetUITaskRunner()->PostTask(fml::MakeCopyable(
[engine = engine_->GetWeakPtr(), loading_unit_id,
data = std::move(snapshot_data),
instructions = std::move(snapshot_instructions)]() mutable {
if (engine) {
engine->LoadDartDeferredLibrary(loading_unit_id, std::move(data),
std::move(instructions));
}
}));
}

void Shell::LoadDartDeferredLibraryError(intptr_t loading_unit_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,18 +425,34 @@ public void loadDartLibrary(int loadingUnitId, String componentName) {
List<String> apkPaths = new ArrayList<>();
// If not found in APKs, we check in extracted native libs for the lib directly.
List<String> soPaths = new ArrayList<>();

Queue<File> searchFiles = new LinkedList<>();
// Downloaded modules are stored here
searchFiles.add(context.getFilesDir());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// The initial installed apks are provided by `sourceDirs` in ApplicationInfo.
// The jniLibs we want are in the splits not the baseDir. These
// APKs are only searched as a fallback, as base libs generally do not need
// to be fully path referenced.
for (String path : context.getApplicationInfo().splitSourceDirs) {
searchFiles.add(new File(path));
}
}

while (!searchFiles.isEmpty()) {
File file = searchFiles.remove();
if (file != null && file.isDirectory()) {
if (file != null && file.isDirectory() && file.listFiles() != null) {
for (File f : file.listFiles()) {
searchFiles.add(f);
}
continue;
}
String name = file.getName();
if (name.endsWith(".apk") && name.startsWith(componentName) && name.contains(pathAbi)) {
// Special case for "split_config" since android base module non-master apks are
// initially installed with the "split_config" prefix/name.
if (name.endsWith(".apk")
&& (name.startsWith(componentName) || name.startsWith("split_config"))
&& name.contains(pathAbi)) {
apkPaths.add(file.getAbsolutePath());
continue;
}
Expand All @@ -459,7 +475,7 @@ public void loadDartLibrary(int loadingUnitId, String componentName) {
}

flutterJNI.loadDartDeferredLibrary(
loadingUnitId, searchPaths.toArray(new String[apkPaths.size()]));
loadingUnitId, searchPaths.toArray(new String[searchPaths.size()]));
}

public boolean uninstallDeferredComponent(int loadingUnitId, String componentName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
Expand All @@ -32,6 +33,7 @@

@Config(manifest = Config.NONE)
@RunWith(RobolectricTestRunner.class)
@TargetApi(21)
public class PlayStoreDeferredComponentManagerTest {
private class TestFlutterJNI extends FlutterJNI {
public int loadDartDeferredLibraryCalled = 0;
Expand Down Expand Up @@ -90,9 +92,12 @@ private Context createSpyContext(Bundle metadata) throws NameNotFoundException {
PackageManager packageManager = mock(PackageManager.class);
ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
applicationInfo.metaData = metadata;
applicationInfo.splitSourceDirs = new String[1];
applicationInfo.splitSourceDirs[0] = "some.invalid.apk";
when(packageManager.getApplicationInfo(any(String.class), any(int.class)))
.thenReturn(applicationInfo);
doReturn(packageManager).when(spyContext).getPackageManager();
doReturn(applicationInfo).when(spyContext).getApplicationInfo();
return spyContext;
}

Expand Down Expand Up @@ -239,6 +244,30 @@ public void searchPathsAddsApks() throws NameNotFoundException {
assertEquals(jni.loadingUnitId, 123);
}

@Test
public void searchPathsSearchesSplitConfig() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = createSpyContext(null);
doReturn(null).when(spyContext).getAssets();
String apkTestPath = "test/path/split_config.armeabi_v7a.apk";
doReturn(new File(apkTestPath)).when(spyContext).getFilesDir();
TestPlayStoreDeferredComponentManager playStoreManager =
new TestPlayStoreDeferredComponentManager(spyContext, jni);
jni.setDeferredComponentManager(playStoreManager);

assertEquals(jni.loadingUnitId, 0);

playStoreManager.installDeferredComponent(123, "TestModuleName");
assertEquals(jni.loadDartDeferredLibraryCalled, 1);
assertEquals(jni.updateAssetManagerCalled, 1);
assertEquals(jni.deferredComponentInstallFailureCalled, 0);

assertEquals(jni.searchPaths[0], "libapp.so-123.part.so");
assertTrue(jni.searchPaths[1].endsWith(apkTestPath + "!lib/armeabi-v7a/libapp.so-123.part.so"));
assertEquals(jni.searchPaths.length, 2);
assertEquals(jni.loadingUnitId, 123);
}

@Test
public void invalidSearchPathsAreIgnored() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Expand Down

0 comments on commit e120494

Please sign in to comment.