From fb2d0cc090a76388f0aac0f682ebb3639b3dcdb3 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Tue, 31 Jan 2017 15:10:00 -0800 Subject: [PATCH] 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 --- .../systemui/statusbar/StatusBarIconView.java | 11 +++- .../systemui/statusbar/StatusBarIconViewTest.java | 65 ++++++++++++++++++---- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 399b0d293ac2..6283148c84f8 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 @@ public class StatusBarIconView extends AnimatedImageView { 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 7d9e0736fdad..68f9cb05ecaf 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) 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 @@ public class StatusBarIconViewTest extends SysuiTestCase { 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 -- 2.11.0