StatusBar: Catch OOM caused by third-party icons
Bug: 31825355
Test: runtest -x packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
Change-Id: I3e2a8c3da43a572a026ea0bbe1d39234035a4801
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 399b0d2..6283148 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -256,9 +256,16 @@
if (mIcon == null) {
return false;
}
- Drawable drawable = getIcon(mIcon);
+ Drawable drawable;
+ try {
+ drawable = getIcon(mIcon);
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "OOM while inflating " + mIcon.icon + " for slot " + mSlot);
+ return false;
+ }
+
if (drawable == null) {
- Log.w(TAG, "No icon for slot " + mSlot);
+ Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
return false;
}
if (withClear) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 7d9e073..68f9cb05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,36 +16,74 @@
package com.android.systemui.statusbar;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.graphics.drawable.Icon;
-import android.os.Debug;
import android.os.UserHandle;
+import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-
-import static junit.framework.Assert.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import org.mockito.ArgumentMatcher;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class StatusBarIconViewTest extends SysuiTestCase {
+ @Rule
+ public ExpectedException mThrown = ExpectedException.none();
+
private StatusBarIconView mIconView;
private StatusBarIcon mStatusBarIcon = mock(StatusBarIcon.class);
+ private PackageManager mPackageManagerSpy;
+ private Context mContext;
+ private Resources mMockResources;
+
@Before
- public void setUp() {
- mIconView = new StatusBarIconView(getContext(), "slot", null);
- mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, getContext().getPackageName(),
- Icon.createWithResource(getContext(), R.drawable.ic_android), 0, 0, "");
+ public void setUp() throws Exception {
+ // Set up context such that asking for "mockPackage" resources returns mMockResources.
+ mMockResources = mock(Resources.class);
+ mPackageManagerSpy = spy(getContext().getPackageManager());
+ doReturn(mMockResources).when(mPackageManagerSpy)
+ .getResourcesForApplicationAsUser(eq("mockPackage"), anyInt());
+ doReturn(mMockResources).when(mPackageManagerSpy)
+ .getResourcesForApplication(eq("mockPackage"));
+ doReturn(mMockResources).when(mPackageManagerSpy).getResourcesForApplication(argThat(
+ (ArgumentMatcher<ApplicationInfo>) o -> "mockPackage".equals(o.packageName)));
+ mContext = new ContextWrapper(getContext()) {
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManagerSpy;
+ }
+ };
+
+ mIconView = new StatusBarIconView(mContext, "test_slot", null);
+ mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+ Icon.createWithResource(mContext, R.drawable.ic_android), 0, 0, "");
}
@Test
@@ -55,4 +93,11 @@
assertNull(mIconView.getTag(R.id.icon_is_grayscale));
}
+ @Test
+ public void testSettingOomingIconDoesNotThrowOom() {
+ when(mMockResources.getDrawable(anyInt(), any())).thenThrow(new OutOfMemoryError("mocked"));
+ mStatusBarIcon.icon = Icon.createWithResource("mockPackage", R.drawable.ic_android);
+
+ assertFalse(mIconView.set(mStatusBarIcon));
+ }
}
\ No newline at end of file