5package io.flutter.embedding.engine.deferredcomponents;
7import static junit.framework.TestCase.assertEquals;
8import static junit.framework.TestCase.assertFalse;
9import static junit.framework.TestCase.assertTrue;
10import static org.mockito.Mockito.any;
11import static org.mockito.Mockito.anyInt;
12import static org.mockito.Mockito.doReturn;
13import static org.mockito.Mockito.mock;
14import static org.mockito.Mockito.spy;
15import static org.mockito.Mockito.when;
18import android.content.pm.ApplicationInfo;
19import android.content.pm.PackageManager;
20import android.content.pm.PackageManager.NameNotFoundException;
21import android.content.res.AssetManager;
23import androidx.annotation.NonNull;
24import androidx.test.core.app.ApplicationProvider;
25import androidx.test.ext.junit.runners.AndroidJUnit4;
26import io.flutter.embedding.engine.FlutterJNI;
27import io.flutter.embedding.engine.loader.ApplicationInfoLoader;
30import org.junit.runner.RunWith;
31import org.robolectric.annotation.Config;
34@RunWith(AndroidJUnit4.class)
36 private class TestFlutterJNI
extends FlutterJNI {
37 public int loadDartDeferredLibraryCalled = 0;
38 public int updateAssetManagerCalled = 0;
39 public int deferredComponentInstallFailureCalled = 0;
40 public String[] searchPaths;
41 public int loadingUnitId;
42 public AssetManager assetManager;
43 public String assetBundlePath;
45 public TestFlutterJNI() {}
48 public void loadDartDeferredLibrary(
int loadingUnitId, @NonNull String[] searchPaths) {
49 loadDartDeferredLibraryCalled++;
50 this.searchPaths = searchPaths;
51 this.loadingUnitId = loadingUnitId;
55 public void updateJavaAssetManager(
56 @NonNull AssetManager assetManager, @NonNull String assetBundlePath) {
57 updateAssetManagerCalled++;
58 this.loadingUnitId = loadingUnitId;
59 this.assetManager = assetManager;
60 this.assetBundlePath = assetBundlePath;
64 public void deferredComponentInstallFailure(
65 int loadingUnitId, @NonNull String
error,
boolean isTransient) {
66 deferredComponentInstallFailureCalled++;
72 public TestPlayStoreDeferredComponentManager(Context context,
FlutterJNI jni) {
77 public void installDeferredComponent(
int loadingUnitId, String componentName) {
79 loadAssets(loadingUnitId, componentName);
80 loadDartLibrary(loadingUnitId, componentName);
84 @SuppressWarnings(
"deprecation")
86 private Context createSpyContext(Bundle metadata)
throws NameNotFoundException {
87 Context spyContext = spy(ApplicationProvider.getApplicationContext());
88 doReturn(spyContext).when(spyContext).createPackageContext(
any(), anyInt());
89 if (metadata ==
null) {
90 metadata =
new Bundle();
92 PackageManager packageManager = mock(PackageManager.class);
93 ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
94 applicationInfo.metaData = metadata;
95 applicationInfo.splitSourceDirs =
new String[1];
96 applicationInfo.splitSourceDirs[0] =
"some.invalid.apk";
97 when(packageManager.getApplicationInfo(
any(String.class),
any(
int.
class)))
98 .thenReturn(applicationInfo);
99 doReturn(packageManager).when(spyContext).getPackageManager();
100 doReturn(applicationInfo).when(spyContext).getApplicationInfo();
106 TestFlutterJNI jni =
new TestFlutterJNI();
107 Context spyContext = createSpyContext(
null);
108 doReturn(
null).when(spyContext).getAssets();
109 String soTestFilename =
"libapp.so-123.part.so";
110 String soTestPath =
"test/path/" + soTestFilename;
111 doReturn(
new File(soTestPath)).when(spyContext).getFilesDir();
112 TestPlayStoreDeferredComponentManager playStoreManager =
113 new TestPlayStoreDeferredComponentManager(spyContext, jni);
114 jni.setDeferredComponentManager(playStoreManager);
115 assertEquals(jni.loadingUnitId, 0);
117 playStoreManager.installDeferredComponent(123,
"TestModuleName");
118 assertEquals(jni.loadDartDeferredLibraryCalled, 1);
119 assertEquals(jni.updateAssetManagerCalled, 1);
120 assertEquals(jni.deferredComponentInstallFailureCalled, 0);
122 assertEquals(jni.searchPaths[0], soTestFilename);
123 assertTrue(jni.searchPaths[1].endsWith(soTestPath));
124 assertEquals(jni.searchPaths.length, 2);
125 assertEquals(jni.loadingUnitId, 123);
126 assertEquals(jni.assetBundlePath,
"flutter_assets");
131 TestFlutterJNI jni =
new TestFlutterJNI();
133 Bundle bundle =
new Bundle();
137 Context spyContext = createSpyContext(bundle);
138 doReturn(
null).when(spyContext).getAssets();
140 String soTestFilename =
"custom_name.so-123.part.so";
141 String soTestPath =
"test/path/" + soTestFilename;
142 doReturn(
new File(soTestPath)).when(spyContext).getFilesDir();
143 TestPlayStoreDeferredComponentManager playStoreManager =
144 new TestPlayStoreDeferredComponentManager(spyContext, jni);
145 jni.setDeferredComponentManager(playStoreManager);
146 assertEquals(jni.loadingUnitId, 0);
148 playStoreManager.installDeferredComponent(123,
"TestModuleName");
149 assertEquals(jni.loadDartDeferredLibraryCalled, 1);
150 assertEquals(jni.updateAssetManagerCalled, 1);
151 assertEquals(jni.deferredComponentInstallFailureCalled, 0);
153 assertEquals(jni.searchPaths[0], soTestFilename);
154 assertTrue(jni.searchPaths[1].endsWith(soTestPath));
155 assertEquals(jni.searchPaths.length, 2);
156 assertEquals(jni.loadingUnitId, 123);
157 assertEquals(jni.assetBundlePath,
"custom_assets");
162 throws NameNotFoundException {
163 TestFlutterJNI jni =
new TestFlutterJNI();
165 Bundle bundle =
new Bundle();
169 Context spyContext = createSpyContext(bundle);
170 doReturn(
null).when(spyContext).getAssets();
172 String soTestFilename =
"custom_name.so";
173 String soTestPath =
"test/path/" + soTestFilename;
174 doReturn(
new File(soTestPath)).when(spyContext).getFilesDir();
175 TestPlayStoreDeferredComponentManager playStoreManager =
176 new TestPlayStoreDeferredComponentManager(spyContext, jni);
177 jni.setDeferredComponentManager(playStoreManager);
178 assertEquals(jni.loadingUnitId, 0);
180 playStoreManager.installDeferredComponent(123,
"TestModuleName");
181 assertEquals(jni.loadDartDeferredLibraryCalled, 1);
182 assertEquals(jni.updateAssetManagerCalled, 1);
183 assertEquals(jni.deferredComponentInstallFailureCalled, 0);
185 assertEquals(jni.searchPaths[0], soTestFilename);
186 assertTrue(jni.searchPaths[1].endsWith(soTestPath));
187 assertEquals(jni.searchPaths.length, 2);
188 assertEquals(jni.loadingUnitId, 123);
189 assertEquals(jni.assetBundlePath,
"custom_assets");
194 TestFlutterJNI jni =
new TestFlutterJNI();
196 Bundle bundle =
new Bundle();
201 Context spyContext = createSpyContext(bundle);
202 doReturn(
null).when(spyContext).getAssets();
204 String soTestFilename =
"libapp.so-3.part.so";
205 String soTestPath =
"test/path/" + soTestFilename;
206 doReturn(
new File(soTestPath)).when(spyContext).getFilesDir();
209 jni.setDeferredComponentManager(playStoreManager);
210 assertEquals(jni.loadingUnitId, 0);
213 assertEquals(jni.loadDartDeferredLibraryCalled, 1);
214 assertEquals(jni.updateAssetManagerCalled, 0);
215 assertEquals(jni.deferredComponentInstallFailureCalled, 0);
217 assertEquals(jni.searchPaths[0], soTestFilename);
218 assertTrue(jni.searchPaths[1].endsWith(soTestPath));
219 assertEquals(jni.searchPaths.length, 2);
220 assertEquals(jni.loadingUnitId, 3);
225 TestFlutterJNI jni =
new TestFlutterJNI();
226 Context spyContext = createSpyContext(
null);
227 doReturn(
null).when(spyContext).getAssets();
228 String apkTestPath =
"test/path/TestModuleName_armeabi_v7a.apk";
229 doReturn(
new File(apkTestPath)).when(spyContext).getFilesDir();
230 TestPlayStoreDeferredComponentManager playStoreManager =
231 new TestPlayStoreDeferredComponentManager(spyContext, jni);
232 jni.setDeferredComponentManager(playStoreManager);
234 assertEquals(jni.loadingUnitId, 0);
236 playStoreManager.installDeferredComponent(123,
"TestModuleName");
237 assertEquals(jni.loadDartDeferredLibraryCalled, 1);
238 assertEquals(jni.updateAssetManagerCalled, 1);
239 assertEquals(jni.deferredComponentInstallFailureCalled, 0);
241 assertEquals(jni.searchPaths[0],
"libapp.so-123.part.so");
242 assertTrue(jni.searchPaths[1].endsWith(apkTestPath +
"!lib/armeabi-v7a/libapp.so-123.part.so"));
243 assertEquals(jni.searchPaths.length, 2);
244 assertEquals(jni.loadingUnitId, 123);
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);
258 assertEquals(jni.loadingUnitId, 0);
260 playStoreManager.installDeferredComponent(123,
"TestModuleName");
261 assertEquals(jni.loadDartDeferredLibraryCalled, 1);
262 assertEquals(jni.updateAssetManagerCalled, 1);
263 assertEquals(jni.deferredComponentInstallFailureCalled, 0);
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);
273 TestFlutterJNI jni =
new TestFlutterJNI();
274 Context spyContext = createSpyContext(
null);
275 doReturn(
null).when(spyContext).getAssets();
276 String apkTestPath =
"test/path/invalidpath.apk";
277 doReturn(
new File(apkTestPath)).when(spyContext).getFilesDir();
278 TestPlayStoreDeferredComponentManager playStoreManager =
279 new TestPlayStoreDeferredComponentManager(spyContext, jni);
280 jni.setDeferredComponentManager(playStoreManager);
282 assertEquals(jni.loadingUnitId, 0);
284 playStoreManager.installDeferredComponent(123,
"TestModuleName");
285 assertEquals(jni.loadDartDeferredLibraryCalled, 1);
286 assertEquals(jni.updateAssetManagerCalled, 1);
287 assertEquals(jni.deferredComponentInstallFailureCalled, 0);
289 assertEquals(jni.searchPaths[0],
"libapp.so-123.part.so");
290 assertEquals(jni.searchPaths.length, 1);
291 assertEquals(jni.loadingUnitId, 123);
296 TestFlutterJNI jni =
new TestFlutterJNI();
297 Context spyContext = createSpyContext(
null);
298 doReturn(
null).when(spyContext).getAssets();
299 AssetManager assetManager = spyContext.getAssets();
300 String apkTestPath =
"blah doesn't matter here";
301 doReturn(
new File(apkTestPath)).when(spyContext).getFilesDir();
302 TestPlayStoreDeferredComponentManager playStoreManager =
303 new TestPlayStoreDeferredComponentManager(spyContext, jni);
304 jni.setDeferredComponentManager(playStoreManager);
306 assertEquals(jni.loadingUnitId, 0);
308 playStoreManager.installDeferredComponent(123,
"TestModuleName");
309 assertEquals(jni.loadDartDeferredLibraryCalled, 1);
310 assertEquals(jni.updateAssetManagerCalled, 1);
311 assertEquals(jni.deferredComponentInstallFailureCalled, 0);
313 assertEquals(jni.assetManager, assetManager);
318 TestFlutterJNI jni =
new TestFlutterJNI();
319 Context spyContext = createSpyContext(
null);
320 doReturn(
null).when(spyContext).getAssets();
321 TestPlayStoreDeferredComponentManager playStoreManager =
322 new TestPlayStoreDeferredComponentManager(spyContext, jni);
323 assertEquals(playStoreManager.getDeferredComponentInstallState(-1,
"invalidName"),
"unknown");
328 TestFlutterJNI jni =
new TestFlutterJNI();
329 Bundle bundle =
new Bundle();
331 Context spyContext = createSpyContext(bundle);
332 TestPlayStoreDeferredComponentManager playStoreManager =
333 new TestPlayStoreDeferredComponentManager(spyContext, jni);
335 assertTrue(playStoreManager.uninstallDeferredComponent(5,
null));
336 assertTrue(playStoreManager.uninstallDeferredComponent(2,
null));
337 assertFalse(playStoreManager.uninstallDeferredComponent(3,
null));
342 TestFlutterJNI jni =
new TestFlutterJNI();
343 Bundle bundle =
new Bundle();
345 Context spyContext = createSpyContext(bundle);
346 TestPlayStoreDeferredComponentManager playStoreManager =
347 new TestPlayStoreDeferredComponentManager(spyContext, jni);
void manifestMappingHandlesBaseModuleEmptyString()
void invalidSearchPathsAreIgnored()
void searchPathsAddsApks()
void loadingUnitMappingFindsMatch()
void downloadCallsJNIFunctions()
void downloadCallsJNIFunctionsWithFilenameFromManifest()
void searchPathsSearchesSplitConfig()
void assetOnlyMappingParses()
void assetManagerUpdateInvoked()
void downloadCallsJNIFunctionsWithSharedLibraryNameFromManifest()
void stateGetterReturnsUnknowByDefault()
static final String MAPPING_KEY
void installDeferredComponent(int loadingUnitId, @Nullable String componentName)
static final String PUBLIC_AOT_SHARED_LIBRARY_NAME
static final String PUBLIC_FLUTTER_ASSETS_DIR_KEY
const uint8_t uint32_t uint32_t GError ** error
SIT bool any(const Vec< 1, T > &x)