blob: e62adc50bf2055182bed45bd2b4dc49a3366920b [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.telephony.cts;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OPSTR_READ_PHONE_STATE;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_NAME_STRING;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONED_BOOL;
import static android.telephony.CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL;
import static android.telephony.ServiceState.STATE_IN_SERVICE;
import static androidx.test.InstrumentationRegistry.getContext;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.compatibility.common.util.AppOpsUtils.setOpMode;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Looper;
import android.os.PersistableBundle;
import android.platform.test.annotations.AsbSecurityTest;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.TestThread;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class CarrierConfigManagerTest {
private static final String CARRIER_NAME_OVERRIDE = "carrier_a";
private CarrierConfigManager mConfigManager;
private TelephonyManager mTelephonyManager;
private SubscriptionManager mSubscriptionManager;
private PackageManager mPackageManager;
// Use a long timeout to accommodate devices with lower amounts of memory, as it will take
// longer for these devices to receive the broadcast (b/161963269). It is expected that all
// devices can receive the broadcast in under 5s (most should receive it well before then).
private static final int BROADCAST_TIMEOUT_MILLIS = 5000;
private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(1);
@Before
public void setUp() throws Exception {
mTelephonyManager = (TelephonyManager)
getContext().getSystemService(Context.TELEPHONY_SERVICE);
mConfigManager = (CarrierConfigManager)
getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
mSubscriptionManager =
(SubscriptionManager)
getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
mPackageManager = getContext().getPackageManager();
}
@After
public void tearDown() throws Exception {
try {
setOpMode("--uid android.telephony.cts", OPSTR_READ_PHONE_STATE, MODE_ALLOWED);
} catch (IOException e) {
fail();
}
}
/**
* Checks whether the telephony stack should be running on this device.
*
* Note: "Telephony" means only SMS/MMS and voice calls in some contexts, but we also care if
* the device supports cellular data.
*/
private boolean hasTelephony() {
return mTelephonyManager.isDataCapable();
}
private boolean isSimCardPresent() {
return mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE &&
mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_UNKNOWN &&
mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_ABSENT;
}
private boolean isSimCardAbsent() {
return mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_ABSENT;
}
private void checkConfig(PersistableBundle config) {
if (config == null) {
assertFalse(
"Config should only be null when telephony is not running.", hasTelephony());
return;
}
assertNotNull("CarrierConfigManager should not return null config", config);
if (isSimCardAbsent()) {
// Static default in CarrierConfigManager will be returned when no sim card present.
assertEquals("Config doesn't match static default.",
config.getBoolean(CarrierConfigManager.KEY_ADDITIONAL_CALL_SETTING_BOOL), true);
assertEquals("KEY_VVM_DESTINATION_NUMBER_STRING doesn't match static default.",
config.getString(CarrierConfigManager.KEY_VVM_DESTINATION_NUMBER_STRING), "");
assertEquals("KEY_VVM_PORT_NUMBER_INT doesn't match static default.",
config.getInt(CarrierConfigManager.KEY_VVM_PORT_NUMBER_INT), 0);
assertEquals("KEY_VVM_TYPE_STRING doesn't match static default.",
config.getString(CarrierConfigManager.KEY_VVM_TYPE_STRING), "");
assertEquals("KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN doesn't match static default.",
config.getBoolean(CarrierConfigManager.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL),
false);
assertEquals("KEY_VVM_PREFETCH_BOOLEAN doesn't match static default.",
config.getBoolean(CarrierConfigManager.KEY_VVM_PREFETCH_BOOL), true);
assertEquals("KEY_CARRIER_VVM_PACKAGE_NAME_STRING doesn't match static default.",
config.getString(CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING), "");
assertFalse(CarrierConfigManager.isConfigForIdentifiedCarrier(config));
// Check default value matching
assertEquals("KEY_DATA_LIMIT_NOTIFICATION_BOOL doesn't match static default.",
config.getBoolean(CarrierConfigManager.KEY_DATA_LIMIT_NOTIFICATION_BOOL),
true);
assertEquals("KEY_DATA_RAPID_NOTIFICATION_BOOL doesn't match static default.",
config.getBoolean(CarrierConfigManager.KEY_DATA_RAPID_NOTIFICATION_BOOL),
true);
assertEquals("KEY_DATA_WARNING_NOTIFICATION_BOOL doesn't match static default.",
config.getBoolean(CarrierConfigManager.KEY_DATA_WARNING_NOTIFICATION_BOOL),
true);
assertEquals("Gps.KEY_PERSIST_LPP_MODE_BOOL doesn't match static default.",
config.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL),
true);
assertEquals("KEY_MONTHLY_DATA_CYCLE_DAY_INT doesn't match static default.",
config.getInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT),
CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT);
assertEquals("KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL doesn't match static default.",
config.getBoolean(CarrierConfigManager.KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL),
false);
assertEquals("KEY_SUPPORTS_CALL_COMPOSER_BOOL doesn't match static default.",
config.getBoolean(CarrierConfigManager.KEY_SUPPORTS_CALL_COMPOSER_BOOL),
false);
assertEquals("KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING doesn't match static"
+ " default.", config.getString(
CarrierConfigManager.KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING), "");
assertEquals("KEY_CARRIER_USSD_METHOD_INT doesn't match static default.",
config.getInt(CarrierConfigManager.KEY_CARRIER_USSD_METHOD_INT),
CarrierConfigManager.USSD_OVER_CS_PREFERRED);
}
// These key should return default values if not customized.
assertNotNull(config.getIntArray(
CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY));
assertNotNull(config.getIntArray(
CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY));
assertNotNull(config.getIntArray(
CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY));
assertNotNull(config.getIntArray(
CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY));
assertNotNull(config.getIntArray(
CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY));
// Check the GPS key prefix
assertTrue("Gps.KEY_PREFIX doesn't match the prefix of the name of "
+ "Gps.KEY_PERSIST_LPP_MODE_BOOL",
CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL.startsWith(
CarrierConfigManager.Gps.KEY_PREFIX));
}
@Test
public void testGetConfig() {
PersistableBundle config = mConfigManager.getConfig();
checkConfig(config);
}
@Test
@AsbSecurityTest(cveBugId = 73136824)
public void testRevokePermission() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
}
PersistableBundle config;
try {
setOpMode("--uid android.telephony.cts", OPSTR_READ_PHONE_STATE, MODE_IGNORED);
} catch (IOException e) {
fail();
}
config = mConfigManager.getConfig();
assertTrue(config.isEmptyParcel());
try {
setOpMode("--uid android.telephony.cts", OPSTR_READ_PHONE_STATE, MODE_ALLOWED);
} catch (IOException e) {
fail();
}
config = mConfigManager.getConfig();
checkConfig(config);
}
@Test
public void testGetConfigForSubId() {
PersistableBundle config =
mConfigManager.getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
checkConfig(config);
}
/**
* Tests the CarrierConfigManager.notifyConfigChangedForSubId() API. This makes a call to
* notifyConfigChangedForSubId() API and expects a SecurityException since the test apk is not signed
* by certificate on the SIM.
*/
@Test
public void testNotifyConfigChangedForSubId() {
try {
if (isSimCardPresent()) {
mConfigManager.notifyConfigChangedForSubId(
SubscriptionManager.getDefaultSubscriptionId());
fail("Expected SecurityException. App doesn't have carrier privileges.");
}
} catch (SecurityException expected) {
}
}
/**
* The following methods may return any value depending on the state of the device. Simply
* call them to make sure they do not throw any exceptions.
*/
@Test
public void testCarrierConfigManagerResultDependentApi() {
assertNotNull(ShellIdentityUtils.invokeMethodWithShellPermissions(mConfigManager,
(cm) -> cm.getDefaultCarrierServicePackageName()));
}
/**
* This checks that {@link CarrierConfigManager#overrideConfig(int, PersistableBundle)}
* correctly overrides the Carrier Name (SPN) string.
*/
@Test
public void testCarrierConfigNameOverride() throws Exception {
if (!isSimCardPresent()
|| mTelephonyManager.getServiceState().getState() != STATE_IN_SERVICE) {
return;
}
// Adopt shell permission so the required permission (android.permission.MODIFY_PHONE_STATE)
// is granted.
UiAutomation ui = getInstrumentation().getUiAutomation();
ui.adoptShellPermissionIdentity();
int subId = SubscriptionManager.getDefaultSubscriptionId();
TestThread t = new TestThread(new Runnable() {
@Override
public void run() {
Looper.prepare();
OnSubscriptionsChangedListener listener =
new OnSubscriptionsChangedListener() {
@Override
public void onSubscriptionsChanged() {
if (CARRIER_NAME_OVERRIDE.equals(
mTelephonyManager.getSimOperatorName())) {
COUNT_DOWN_LATCH.countDown();
}
}
};
mSubscriptionManager.addOnSubscriptionsChangedListener(listener);
PersistableBundle carrierNameOverride = new PersistableBundle(3);
carrierNameOverride.putBoolean(KEY_CARRIER_NAME_OVERRIDE_BOOL, true);
carrierNameOverride.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, true);
carrierNameOverride.putString(KEY_CARRIER_NAME_STRING, CARRIER_NAME_OVERRIDE);
mConfigManager.overrideConfig(subId, carrierNameOverride);
Looper.loop();
}
});
try {
t.start();
boolean didCarrierNameUpdate =
COUNT_DOWN_LATCH.await(BROADCAST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
if (!didCarrierNameUpdate) {
fail("CarrierName not overridden in " + BROADCAST_TIMEOUT_MILLIS + " ms");
}
} finally {
mConfigManager.overrideConfig(subId, null);
ui.dropShellPermissionIdentity();
}
}
@Test
public void testExtraRebroadcastOnUnlock() throws Throwable {
if (!hasTelephony()) {
return;
}
BlockingQueue<Boolean> queue = new ArrayBlockingQueue<Boolean>(5);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
queue.add(new Boolean(true));
// verify that REBROADCAST_ON_UNLOCK is populated
assertFalse(
intent.getBooleanExtra(CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK,
true));
}
}
};
try {
final IntentFilter filter =
new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
getContext().registerReceiver(receiver, filter);
// verify that carrier config is received
int subId = SubscriptionManager.getDefaultSubscriptionId();
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity();
mConfigManager.notifyConfigChangedForSubId(subId);
Boolean broadcastReceived = queue.poll(BROADCAST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
assertNotNull(broadcastReceived);
assertTrue(broadcastReceived);
} finally {
// unregister receiver
getContext().unregisterReceiver(receiver);
receiver = null;
}
}
@Test
public void testGetConfigByComponentForSubId() {
PersistableBundle config =
mConfigManager.getConfigByComponentForSubId(
CarrierConfigManager.Wifi.KEY_PREFIX,
SubscriptionManager.getDefaultSubscriptionId());
if (config != null) {
assertTrue(config.containsKey(CarrierConfigManager.Wifi.KEY_HOTSPOT_MAX_CLIENT_COUNT));
assertFalse(config.containsKey(KEY_CARRIER_VOLTE_PROVISIONED_BOOL));
assertFalse(config.containsKey(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING));
}
}
}