summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Fabian Kozynski <kozynski@google.com> 2019-02-04 09:21:38 -0500
committer Fabian Kozynski <kozynski@google.com> 2019-02-04 14:20:27 -0500
commitbf6fef3fe6cf95d1d3fcfab4b40b9f293602ae09 (patch)
treebe146595797ba2dc384f0dad6f9c902e6643c12f
parent1ec11dbda282e02b3f1db03a454d0e9db91a6b0e (diff)
Fix ArrayIndexOOB crash with invalid sim slot
Added guards for multiple ArrayIndexOOB Exceptions. CarrierTextController needs to be refactored to show proper names and not need split Test: atest Bug: 123753387 Change-Id: I55fa40ec26d91da0379440b010c20b61a0941f66
-rw-r--r--packages/SystemUI/src/com/android/keyguard/CarrierTextController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java76
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java121
3 files changed, 195 insertions, 22 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 2ce69650b65c..d5bd2b202803 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -21,12 +21,15 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
+import android.os.Handler;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.WirelessUtils;
@@ -206,6 +209,7 @@ public class CarrierTextController {
protected void updateCarrierText() {
boolean allSimsMissing = true;
boolean anySimReadyAndInService = false;
+ boolean missingSimsWithSubs = false;
CharSequence displayText = null;
List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
@@ -252,6 +256,7 @@ public class CarrierTextController {
// described above.
displayText = makeCarrierStringOnEmergencyCapable(
getMissingSimMessage(), subs.get(0).getCarrierName());
+ missingSimsWithSubs = true;
} else {
// We don't have a SubscriptionInfo to get the emergency calls only from.
// Grab it from the old sticky broadcast if possible instead. We can use it
@@ -288,12 +293,14 @@ public class CarrierTextController {
displayText = getAirplaneModeMessage();
}
+ Handler handler = Dependency.get(Dependency.MAIN_HANDLER);
+ final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
+ displayText,
+ displayText.toString().split(mSeparator.toString()),
+ anySimReadyAndInService && !missingSimsWithSubs,
+ subsIds);
if (mCarrierTextCallback != null) {
- mCarrierTextCallback.updateCarrierInfo(new CarrierTextCallbackInfo(
- displayText,
- displayText.toString().split(mSeparator.toString()),
- anySimReadyAndInService,
- subsIds));
+ handler.post(() -> mCarrierTextCallback.updateCarrierInfo(info));
}
}
@@ -487,7 +494,8 @@ public class CarrierTextController {
public final boolean anySimReady;
public final int[] subscriptionIds;
- CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
+ @VisibleForTesting
+ public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
boolean anySimReady, int[] subscriptionIds) {
this.carrierText = carrierText;
this.listOfCarriers = listOfCarriers;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index c0ed4b97eaff..b865ce8d261a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -54,6 +54,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.graph.SignalDrawable;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.R.dimen;
import com.android.systemui.plugins.ActivityStarter;
@@ -134,6 +135,15 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
mDeviceProvisionedController = deviceProvisionedController;
}
+ @VisibleForTesting
+ public QSFooterImpl(Context context, AttributeSet attrs) {
+ this(context, attrs,
+ Dependency.get(ActivityStarter.class),
+ Dependency.get(UserInfoController.class),
+ Dependency.get(NetworkController.class),
+ Dependency.get(DeviceProvisionedController.class));
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -476,32 +486,62 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
mInfos[0].visible && mInfos[1].visible ? View.VISIBLE : View.GONE);
}
+ @VisibleForTesting
+ protected int getSlotIndex(int subscriptionId) {
+ return SubscriptionManager.getSlotIndex(subscriptionId);
+ }
+
@Override
public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
if (info.anySimReady) {
boolean[] slotSeen = new boolean[SIM_SLOTS];
- for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
- int slot = SubscriptionManager.getSlotIndex(info.subscriptionIds[i]);
- mInfos[slot].visible = true;
- slotSeen[slot] = true;
- mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
- mCarrierGroups[slot].setVisibility(View.VISIBLE);
- }
- for (int i = 0; i < SIM_SLOTS; i++) {
- if (!slotSeen[i]) {
+ if (info.listOfCarriers.length == info.subscriptionIds.length) {
+ for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
+ int slot = getSlotIndex(info.subscriptionIds[i]);
+ if (slot >= SIM_SLOTS) {
+ Log.w(TAG, "updateInfoCarrier - slot: " + slot);
+ continue;
+ }
+ if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ Log.e(TAG,
+ "Invalid SIM slot index for subscription: "
+ + info.subscriptionIds[i]);
+ continue;
+ }
+ mInfos[slot].visible = true;
+ slotSeen[slot] = true;
+ mCarrierTexts[slot].setText(info.listOfCarriers[i].toString().trim());
+ mCarrierGroups[slot].setVisibility(View.VISIBLE);
+ }
+ for (int i = 0; i < SIM_SLOTS; i++) {
+ if (!slotSeen[i]) {
+ mInfos[i].visible = false;
+ mCarrierGroups[i].setVisibility(View.GONE);
+ }
+ }
+ } else {
+ // If there are sims ready but there are not the same number of carrier names as
+ // subscription ids, just show the full text in the first slot
+ mInfos[0].visible = true;
+ mCarrierTexts[0].setText(info.carrierText);
+ mCarrierGroups[0].setVisibility(View.VISIBLE);
+ for (int i = 1; i < SIM_SLOTS; i++) {
mInfos[i].visible = false;
+ mCarrierTexts[i].setText("");
mCarrierGroups[i].setVisibility(View.GONE);
}
}
- handleUpdateState();
} else {
mInfos[0].visible = false;
- mInfos[1].visible = false;
mCarrierTexts[0].setText(info.carrierText);
mCarrierGroups[0].setVisibility(View.VISIBLE);
- mCarrierGroups[1].setVisibility(View.GONE);
- handleUpdateState();
+ for (int i = 1; i < SIM_SLOTS; i++) {
+ mInfos[i].visible = false;
+ mCarrierTexts[i].setText("");
+ mCarrierGroups[i].setVisibility(View.GONE);
+ }
}
+ handleUpdateState();
}
@Override
@@ -510,9 +550,14 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
int qsType, boolean activityIn, boolean activityOut,
String typeContentDescription,
String description, boolean isWide, int subId, boolean roaming) {
- int slotIndex = SubscriptionManager.getSlotIndex(subId);
+ int slotIndex = getSlotIndex(subId);
if (slotIndex >= SIM_SLOTS) {
- Log.e(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+ Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+ return;
+ }
+ if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
+ return;
}
mInfos[slotIndex].visible = statusIcon.visible;
mInfos[slotIndex].mobileSignalIconId = statusIcon.icon;
@@ -539,7 +584,6 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
boolean roaming;
}
-
/**
* TextView that changes its ellipsize value with its visibility.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
index 850396299ae5..374a73c1d451 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
@@ -16,27 +16,35 @@ package com.android.systemui.qs;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
+import android.telephony.SubscriptionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.view.View;
+import com.android.keyguard.CarrierTextController.CarrierTextCallbackInfo;
import com.android.systemui.R;
import com.android.systemui.R.id;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -68,4 +76,117 @@ public class QSFooterImplTest extends LeakCheckedTest {
// Verify Settings wasn't launched.
verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
}
+
+ @Test // throws no Exception
+ public void testUpdateCarrierText_sameLengts() {
+ QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+ when(spiedFooter.getSlotIndex(anyInt())).thenAnswer(
+ new Answer<Integer>() {
+ @Override
+ public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
+ return invocationOnMock.getArgument(0);
+ }
+ });
+
+ // listOfCarriers length 1, subscriptionIds length 1, anySims false
+ CarrierTextCallbackInfo c1 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ false,
+ new int[]{0});
+ spiedFooter.updateCarrierInfo(c1);
+
+ // listOfCarriers length 1, subscriptionIds length 1, anySims true
+ CarrierTextCallbackInfo c2 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0});
+ spiedFooter.updateCarrierInfo(c2);
+
+ // listOfCarriers length 2, subscriptionIds length 2, anySims false
+ CarrierTextCallbackInfo c3 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ false,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c3);
+
+ // listOfCarriers length 2, subscriptionIds length 2, anySims true
+ CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c4);
+ }
+
+ @Test // throws no Exception
+ public void testUpdateCarrierText_differentLength() {
+ QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+ when(spiedFooter.getSlotIndex(anyInt())).thenAnswer(
+ new Answer<Integer>() {
+ @Override
+ public Integer answer(InvocationOnMock invocationOnMock) throws Throwable {
+ return invocationOnMock.getArgument(0);
+ }
+ });
+
+ // listOfCarriers length 2, subscriptionIds length 1, anySims false
+ CarrierTextCallbackInfo c1 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ false,
+ new int[]{0});
+ spiedFooter.updateCarrierInfo(c1);
+
+ // listOfCarriers length 2, subscriptionIds length 1, anySims true
+ CarrierTextCallbackInfo c2 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0});
+ spiedFooter.updateCarrierInfo(c2);
+
+ // listOfCarriers length 1, subscriptionIds length 2, anySims false
+ CarrierTextCallbackInfo c3 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ false,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c3);
+
+ // listOfCarriers length 1, subscriptionIds length 2, anySims true
+ CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{""},
+ true,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c4);
+ }
+
+ @Test // throws no Exception
+ public void testUpdateCarrierText_invalidSim() {
+ QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+ when(spiedFooter.getSlotIndex(anyInt())).thenReturn(
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ CarrierTextCallbackInfo c4 = new CarrierTextCallbackInfo(
+ "",
+ new CharSequence[]{"", ""},
+ true,
+ new int[]{0, 1});
+ spiedFooter.updateCarrierInfo(c4);
+ }
+
+ @Test // throws no Exception
+ public void testSetMobileDataIndicators_invalidSim() {
+ QSFooterImpl spiedFooter = Mockito.spy(mFooter);
+ when(spiedFooter.getSlotIndex(anyInt())).thenReturn(
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ spiedFooter.setMobileDataIndicators(
+ mock(NetworkController.IconState.class),
+ mock(NetworkController.IconState.class),
+ 0, 0, true, true, "", "", true, 0, true);
+ }
+
}