From 0f9aea2979fbb5ea2cf763182fe13c9785a227d7 Mon Sep 17 00:00:00 2001 From: Sam Judd Date: Fri, 23 Dec 2022 23:32:43 -0800 Subject: [PATCH] Check for null results from PackageManager.getApplicationInfo This should never happen based on the API documention. However, Compose's preview API seems to return null anyway. Catch for the exception for now while we wait for a fix in the tooling. --- .../bumptech/glide/module/ManifestParser.java | 18 +++++-- .../glide/module/ManifestParserTest.java | 52 ++++++++++++++++--- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/module/ManifestParser.java b/library/src/main/java/com/bumptech/glide/module/ManifestParser.java index af42f709ea..b3834f3e8c 100644 --- a/library/src/main/java/com/bumptech/glide/module/ManifestParser.java +++ b/library/src/main/java/com/bumptech/glide/module/ManifestParser.java @@ -3,7 +3,9 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.util.Log; +import androidx.annotation.Nullable; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; @@ -24,6 +26,15 @@ public ManifestParser(Context context) { this.context = context; } + // getApplicationInfo returns null in Compose previews, see #4977 and b/263613353. + @SuppressWarnings("ConstantConditions") + @Nullable + private ApplicationInfo getOurApplicationInfo() throws NameNotFoundException { + return context + .getPackageManager() + .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); + } + @SuppressWarnings("deprecation") public List parse() { if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -31,11 +42,8 @@ public List parse() { } List modules = new ArrayList<>(); try { - ApplicationInfo appInfo = - context - .getPackageManager() - .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); - if (appInfo.metaData == null) { + ApplicationInfo appInfo = getOurApplicationInfo(); + if (appInfo == null || appInfo.metaData == null) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Got null app info metadata"); } diff --git a/library/test/src/test/java/com/bumptech/glide/module/ManifestParserTest.java b/library/test/src/test/java/com/bumptech/glide/module/ManifestParserTest.java index 1ea69fb662..7dcdb06374 100644 --- a/library/test/src/test/java/com/bumptech/glide/module/ManifestParserTest.java +++ b/library/test/src/test/java/com/bumptech/glide/module/ManifestParserTest.java @@ -1,13 +1,18 @@ package com.bumptech.glide.module; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import androidx.annotation.NonNull; import com.bumptech.glide.Glide; @@ -16,6 +21,7 @@ import java.util.List; import org.junit.Before; import org.junit.Test; +import org.junit.function.ThrowingRunnable; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -27,6 +33,7 @@ @SuppressWarnings("deprecation") public class ManifestParserTest { private static final String MODULE_VALUE = "GlideModule"; + private static final String PACKAGE_NAME = "com.bumptech.test"; @Mock private Context context; private ManifestParser parser; @@ -38,17 +45,27 @@ public void setUp() throws PackageManager.NameNotFoundException { applicationInfo = new ApplicationInfo(); applicationInfo.metaData = new Bundle(); - String packageName = "com.bumptech.test"; - when(context.getPackageName()).thenReturn(packageName); + when(context.getPackageName()).thenReturn(PACKAGE_NAME); PackageManager pm = mock(PackageManager.class); - when(pm.getApplicationInfo(eq(packageName), eq(PackageManager.GET_META_DATA))) + when(pm.getApplicationInfo(eq(PACKAGE_NAME), eq(PackageManager.GET_META_DATA))) .thenReturn(applicationInfo); when(context.getPackageManager()).thenReturn(pm); parser = new ManifestParser(context); } + // TODO(#4977): Remove this after the bug in Compose's previews is fixed. + @Test + public void parse_withNullApplicationInfo_doesNotThrow() throws NameNotFoundException { + PackageManager pm = mock(PackageManager.class); + when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(null); + when(context.getPackageManager()).thenReturn(pm); + + parser = new ManifestParser(context); + parser.parse(); + } + @Test public void testParse_returnsEmptyListIfNoModulesListed() { assertThat(parser.parse()).isEmpty(); @@ -78,7 +95,6 @@ public void testParse_withMultipleValidModuleNames_returnsListContainingModules( @Test public void testParse_withValidModuleName_ignoresMetadataWithoutGlideModuleValue() { applicationInfo.metaData.putString(TestModule1.class.getName(), MODULE_VALUE + "test"); - assertThat(parser.parse()).isEmpty(); } @@ -96,13 +112,35 @@ public void testThrows_whenClassInManifestIsNotAModule() { parser.parse(); } - @Test(expected = RuntimeException.class) - public void testThrows_whenPackageNameNotFound() { - when(context.getPackageName()).thenReturn("fakePackageName"); + @Test + public void parse_withNullMetadata_doesNotThrow() throws NameNotFoundException { + PackageManager pm = mock(PackageManager.class); + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.metaData = null; + when(pm.getApplicationInfo(eq(PACKAGE_NAME), eq(PackageManager.GET_META_DATA))) + .thenReturn(applicationInfo); + when(context.getPackageManager()).thenReturn(pm); parser.parse(); } + @Test + public void parse_withMissingName_throwsRuntimeException() throws NameNotFoundException { + PackageManager pm = mock(PackageManager.class); + doThrow(new NameNotFoundException("name")).when(pm).getApplicationInfo(anyString(), anyInt()); + when(context.getPackageManager()).thenReturn(pm); + + assertThrows( + "Unable to find metadata to parse GlideModules", + RuntimeException.class, + new ThrowingRunnable() { + @Override + public void run() { + parser.parse(); + } + }); + } + private void addModuleToManifest(Class moduleClass) { addToManifest(moduleClass.getName()); }