1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.phone; 18 19 import static com.android.TestContext.STUB_PERMISSION_ENABLE_ALL; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.junit.Assert.assertThrows; 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyInt; 26 import static org.mockito.ArgumentMatchers.anyString; 27 import static org.mockito.ArgumentMatchers.eq; 28 import static org.mockito.ArgumentMatchers.nullable; 29 import static org.mockito.Mockito.doNothing; 30 import static org.mockito.Mockito.doReturn; 31 import static org.mockito.Mockito.verify; 32 33 import android.content.Intent; 34 import android.content.SharedPreferences; 35 import android.content.pm.PackageInfo; 36 import android.content.pm.PackageManager; 37 import android.content.res.Resources; 38 import android.os.Build; 39 import android.os.Handler; 40 import android.os.HandlerThread; 41 import android.os.Message; 42 import android.os.PersistableBundle; 43 import android.os.UserHandle; 44 import android.service.carrier.CarrierIdentifier; 45 import android.telephony.CarrierConfigManager; 46 import android.telephony.SubscriptionManager; 47 import android.telephony.TelephonyManager; 48 import android.testing.TestableLooper; 49 50 import androidx.test.InstrumentationRegistry; 51 import androidx.test.ext.junit.runners.AndroidJUnit4; 52 53 import com.android.TelephonyTestBase; 54 import com.android.internal.telephony.IccCardConstants; 55 import com.android.internal.telephony.SubscriptionInfoUpdater; 56 57 import org.junit.After; 58 import org.junit.Before; 59 import org.junit.Ignore; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 import org.mockito.Mock; 63 import org.mockito.Mockito; 64 65 import java.io.FileDescriptor; 66 import java.io.PrintWriter; 67 import java.io.StringWriter; 68 import java.util.List; 69 70 /** 71 * Unit Test for CarrierConfigLoader. 72 */ 73 @RunWith(AndroidJUnit4.class) 74 public class CarrierConfigLoaderTest extends TelephonyTestBase { 75 76 private static final int DEFAULT_PHONE_ID = 0; 77 private static final int DEFAULT_SUB_ID = SubscriptionManager.getDefaultSubscriptionId(); 78 private static final String PLATFORM_CARRIER_CONFIG_PACKAGE = "com.android.carrierconfig"; 79 private static final long PLATFORM_CARRIER_CONFIG_PACKAGE_VERSION_CODE = 1; 80 private static final String CARRIER_CONFIG_EXAMPLE_KEY = 81 CarrierConfigManager.KEY_CARRIER_USSD_METHOD_INT; 82 private static final int CARRIER_CONFIG_EXAMPLE_VALUE = 83 CarrierConfigManager.USSD_OVER_CS_PREFERRED; 84 85 @Mock Resources mResources; 86 @Mock PackageManager mPackageManager; 87 @Mock PackageInfo mPackageInfo; 88 @Mock SubscriptionInfoUpdater mSubscriptionInfoUpdater; 89 @Mock SharedPreferences mSharedPreferences; 90 91 private TelephonyManager mTelephonyManager; 92 private CarrierConfigLoader mCarrierConfigLoader; 93 private Handler mHandler; 94 private HandlerThread mHandlerThread; 95 private TestableLooper mTestableLooper; 96 97 @Before setUp()98 public void setUp() throws Exception { 99 super.setUp(); 100 101 doReturn(mSharedPreferences).when(mContext).getSharedPreferences(anyString(), anyInt()); 102 doReturn(Build.FINGERPRINT).when(mSharedPreferences).getString(eq("build_fingerprint"), 103 any()); 104 doReturn(mPackageManager).when(mContext).getPackageManager(); 105 doReturn(mResources).when(mContext).getResources(); 106 doReturn(InstrumentationRegistry.getTargetContext().getFilesDir()).when( 107 mContext).getFilesDir(); 108 doReturn(PLATFORM_CARRIER_CONFIG_PACKAGE).when(mResources).getString( 109 eq(R.string.platform_carrier_config_package)); 110 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 111 doReturn(1).when(mTelephonyManager).getSupportedModemCount(); 112 doReturn(1).when(mTelephonyManager).getActiveModemCount(); 113 doReturn("spn").when(mTelephonyManager).getSimOperatorNameForPhone(anyInt()); 114 doReturn("310260").when(mTelephonyManager).getSimOperatorNumericForPhone(anyInt()); 115 doReturn(mPackageInfo).when(mPackageManager).getPackageInfo( 116 eq(PLATFORM_CARRIER_CONFIG_PACKAGE), eq(0) /*flags*/); 117 doReturn(PLATFORM_CARRIER_CONFIG_PACKAGE_VERSION_CODE).when( 118 mPackageInfo).getLongVersionCode(); 119 120 mHandlerThread = new HandlerThread("CarrierConfigLoaderTest"); 121 mHandlerThread.start(); 122 123 mTestableLooper = new TestableLooper(mHandlerThread.getLooper()); 124 mCarrierConfigLoader = new CarrierConfigLoader(mContext, mSubscriptionInfoUpdater, 125 mTestableLooper.getLooper()); 126 mHandler = mCarrierConfigLoader.getHandler(); 127 128 // Clear all configs to have the same starting point. 129 mCarrierConfigLoader.clearConfigForPhone(DEFAULT_PHONE_ID, false); 130 } 131 132 @After tearDown()133 public void tearDown() throws Exception { 134 mContext.revokeAllPermissions(); 135 mTestableLooper.destroy(); 136 mHandlerThread.quit(); 137 super.tearDown(); 138 } 139 140 /** 141 * Verifies that SecurityException should throw when call #updateConfigForPhoneId() without 142 * MODIFY_PHONE_STATE permission. 143 */ 144 @Test testUpdateConfigForPhoneId_noPermission()145 public void testUpdateConfigForPhoneId_noPermission() throws Exception { 146 assertThrows(SecurityException.class, 147 () -> mCarrierConfigLoader.updateConfigForPhoneId(DEFAULT_PHONE_ID, 148 IccCardConstants.INTENT_VALUE_ICC_ABSENT)); 149 } 150 151 /** 152 * Verifies that IllegalArgumentException should throw when call #updateConfigForPhoneId() with 153 * invalid phoneId. 154 */ 155 @Test testUpdateConfigForPhoneId_invalidPhoneId()156 public void testUpdateConfigForPhoneId_invalidPhoneId() throws Exception { 157 mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL); 158 159 assertThrows(IllegalArgumentException.class, 160 () -> mCarrierConfigLoader.updateConfigForPhoneId( 161 SubscriptionManager.INVALID_PHONE_INDEX, 162 IccCardConstants.INTENT_VALUE_ICC_ABSENT)); 163 } 164 165 /** 166 * Verifies that when call #updateConfigForPhoneId() with SIM absence, both carrier config from 167 * default app and carrier should be cleared but no-sim config should be loaded. 168 */ 169 @Test testUpdateConfigForPhoneId_simAbsent()170 public void testUpdateConfigForPhoneId_simAbsent() throws Exception { 171 // Bypass case if default subId is not supported by device to reduce flakiness 172 if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) { 173 return; 174 } 175 mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL); 176 doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class)); 177 178 // Prepare a cached config to fetch from xml 179 PersistableBundle config = getTestConfig(); 180 mCarrierConfigLoader.saveNoSimConfigToXml(PLATFORM_CARRIER_CONFIG_PACKAGE, config); 181 mCarrierConfigLoader.updateConfigForPhoneId(DEFAULT_PHONE_ID, 182 IccCardConstants.INTENT_VALUE_ICC_ABSENT); 183 mTestableLooper.processAllMessages(); 184 185 assertThat(mCarrierConfigLoader.getConfigFromDefaultApp(DEFAULT_PHONE_ID)).isNull(); 186 assertThat(mCarrierConfigLoader.getConfigFromCarrierApp(DEFAULT_PHONE_ID)).isNull(); 187 assertThat(mCarrierConfigLoader.getNoSimConfig().getInt(CARRIER_CONFIG_EXAMPLE_KEY)) 188 .isEqualTo(CARRIER_CONFIG_EXAMPLE_VALUE); 189 verify(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class)); 190 } 191 192 /** 193 * Verifies that with cached config in XML, calling #updateConfigForPhoneId() with SIM loaded 194 * will return the right config in the XML. 195 */ 196 @Test testUpdateConfigForPhoneId_simLoaded_withCachedConfigInXml()197 public void testUpdateConfigForPhoneId_simLoaded_withCachedConfigInXml() throws Exception { 198 // Bypass case if default subId is not supported by device to reduce flakiness 199 if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) { 200 return; 201 } 202 mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL); 203 204 // Prepare to make sure we can save the config into the XML file which used as cache 205 List<String> carrierPackages = List.of(PLATFORM_CARRIER_CONFIG_PACKAGE); 206 doReturn(carrierPackages).when(mTelephonyManager).getCarrierPackageNamesForIntentAndPhone( 207 nullable(Intent.class), anyInt()); 208 209 // Save the sample config into the XML file 210 PersistableBundle config = getTestConfig(); 211 CarrierIdentifier carrierId = mCarrierConfigLoader.getCarrierIdentifierForPhoneId( 212 DEFAULT_PHONE_ID); 213 mCarrierConfigLoader.saveConfigToXml(PLATFORM_CARRIER_CONFIG_PACKAGE, "", 214 DEFAULT_PHONE_ID, carrierId, config); 215 mCarrierConfigLoader.updateConfigForPhoneId(DEFAULT_PHONE_ID, 216 IccCardConstants.INTENT_VALUE_ICC_LOADED); 217 mTestableLooper.processAllMessages(); 218 219 assertThat(mCarrierConfigLoader.getConfigFromDefaultApp(DEFAULT_PHONE_ID).getInt( 220 CARRIER_CONFIG_EXAMPLE_KEY)).isEqualTo(CARRIER_CONFIG_EXAMPLE_VALUE); 221 222 } 223 224 /** 225 * Verifies that SecurityException should throw if call #overrideConfig() without 226 * MODIFY_PHONE_STATE permission. 227 */ 228 @Test testOverrideConfig_noPermission()229 public void testOverrideConfig_noPermission() throws Exception { 230 assertThrows(SecurityException.class, 231 () -> mCarrierConfigLoader.overrideConfig(DEFAULT_SUB_ID, PersistableBundle.EMPTY, 232 false)); 233 } 234 235 /** 236 * Verifies IllegalArgumentException should throw if call #overrideConfig() with invalid subId. 237 */ 238 @Test testOverrideConfig_invalidSubId()239 public void testOverrideConfig_invalidSubId() throws Exception { 240 mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL); 241 242 assertThrows(IllegalArgumentException.class, () -> mCarrierConfigLoader.overrideConfig( 243 SubscriptionManager.INVALID_SUBSCRIPTION_ID, new PersistableBundle(), false)); 244 } 245 246 /** 247 * Verifies that override config is not null when calling #overrideConfig with null bundle. 248 */ 249 @Test testOverrideConfig_withNullBundle()250 public void testOverrideConfig_withNullBundle() throws Exception { 251 // Bypass case if default subId is not supported by device to reduce flakiness 252 if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) { 253 return; 254 } 255 mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL); 256 257 mCarrierConfigLoader.overrideConfig(DEFAULT_SUB_ID, null /*overrides*/, 258 false/*persistent*/); 259 mTestableLooper.processAllMessages(); 260 261 assertThat(mCarrierConfigLoader.getOverrideConfig(DEFAULT_PHONE_ID).isEmpty()).isTrue(); 262 verify(mSubscriptionInfoUpdater).updateSubscriptionByCarrierConfigAndNotifyComplete( 263 eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE), 264 any(PersistableBundle.class), any(Message.class)); 265 } 266 267 /** 268 * Verifies that override config is not null when calling #overrideConfig with non-null bundle. 269 */ 270 @Test testOverrideConfig_withNonNullBundle()271 public void testOverrideConfig_withNonNullBundle() throws Exception { 272 // Bypass case if default subId is not supported by device to reduce flakiness 273 if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) { 274 return; 275 } 276 mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL); 277 278 PersistableBundle config = getTestConfig(); 279 mCarrierConfigLoader.overrideConfig(DEFAULT_SUB_ID, config /*overrides*/, 280 false/*persistent*/); 281 mTestableLooper.processAllMessages(); 282 283 assertThat(mCarrierConfigLoader.getOverrideConfig(DEFAULT_PHONE_ID).getInt( 284 CARRIER_CONFIG_EXAMPLE_KEY)).isEqualTo(CARRIER_CONFIG_EXAMPLE_VALUE); 285 verify(mSubscriptionInfoUpdater).updateSubscriptionByCarrierConfigAndNotifyComplete( 286 eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE), 287 any(PersistableBundle.class), any(Message.class)); 288 } 289 290 /** 291 * Verifies that IllegalArgumentException should throw when calling 292 * #notifyConfigChangedForSubId() with invalid subId. 293 */ 294 @Test testNotifyConfigChangedForSubId_invalidSubId()295 public void testNotifyConfigChangedForSubId_invalidSubId() throws Exception { 296 mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL); 297 298 assertThrows(IllegalArgumentException.class, 299 () -> mCarrierConfigLoader.notifyConfigChangedForSubId( 300 SubscriptionManager.INVALID_SUBSCRIPTION_ID)); 301 } 302 303 // TODO(b/184040111): Enable test case when support disabling carrier privilege 304 // Phone/System UID always has carrier privilege (TelephonyPermission#getCarrierPrivilegeStatus) 305 // when running the test here. 306 /** 307 * Verifies that SecurityException should throw when calling notifyConfigChangedForSubId without 308 * MODIFY_PHONE_STATE permission. 309 */ 310 @Ignore testNotifyConfigChangedForSubId_noPermission()311 public void testNotifyConfigChangedForSubId_noPermission() throws Exception { 312 setCarrierPrivilegesForSubId(false, DEFAULT_SUB_ID); 313 314 assertThrows(SecurityException.class, 315 () -> mCarrierConfigLoader.notifyConfigChangedForSubId(DEFAULT_SUB_ID)); 316 } 317 318 /** 319 * Verifies that SecurityException should throw when calling getDefaultCarrierServicePackageName 320 * without READ_PRIVILEGED_PHONE_STATE permission. 321 */ 322 @Test testGetDefaultCarrierServicePackageName_noPermission()323 public void testGetDefaultCarrierServicePackageName_noPermission() { 324 assertThrows(SecurityException.class, 325 () -> mCarrierConfigLoader.getDefaultCarrierServicePackageName()); 326 } 327 328 /** 329 * Verifies that the right default carrier service package name is return when calling 330 * getDefaultCarrierServicePackageName with permission. 331 */ 332 @Test testGetDefaultCarrierServicePackageName_withPermission()333 public void testGetDefaultCarrierServicePackageName_withPermission() { 334 mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL); 335 336 assertThat(mCarrierConfigLoader.getDefaultCarrierServicePackageName()) 337 .isEqualTo(PLATFORM_CARRIER_CONFIG_PACKAGE); 338 } 339 340 // TODO(b/184040111): Enable test case when support disabling carrier privilege 341 // Phone/System UID always has carrier privilege (TelephonyPermission#getCarrierPrivilegeStatus) 342 // when running the test here. 343 /** 344 * Verifies that without permission, #getConfigForSubId will return an empty PersistableBundle. 345 */ 346 @Ignore testGetConfigForSubId_noPermission()347 public void testGetConfigForSubId_noPermission() { 348 // Bypass case if default subId is not supported by device to reduce flakiness 349 if (!SubscriptionManager.isValidPhoneId(SubscriptionManager.getPhoneId(DEFAULT_SUB_ID))) { 350 return; 351 } 352 setCarrierPrivilegesForSubId(false, DEFAULT_SUB_ID); 353 354 assertThat(mCarrierConfigLoader.getConfigForSubId(DEFAULT_SUB_ID, 355 PLATFORM_CARRIER_CONFIG_PACKAGE)).isEqualTo(PersistableBundle.EMPTY); 356 } 357 358 /** 359 * Verifies that when have no DUMP permission, the #dump() method shows permission denial. 360 */ 361 @Test testDump_noPermission()362 public void testDump_noPermission() { 363 StringWriter stringWriter = new StringWriter(); 364 mCarrierConfigLoader.dump(new FileDescriptor(), new PrintWriter(stringWriter), 365 new String[0]); 366 stringWriter.flush(); 367 368 assertThat(stringWriter.toString()).contains("Permission Denial:"); 369 } 370 371 /** 372 * Verifies that when have DUMP permission, the #dump() method can dump the CarrierConfigLoader. 373 */ 374 @Test testDump_withPermission()375 public void testDump_withPermission() { 376 mContext.grantPermission(android.Manifest.permission.DUMP); 377 378 StringWriter stringWriter = new StringWriter(); 379 mCarrierConfigLoader.dump(new FileDescriptor(), new PrintWriter(stringWriter), 380 new String[0]); 381 stringWriter.flush(); 382 383 String dumpContent = stringWriter.toString(); 384 assertThat(dumpContent).contains("CarrierConfigLoader:"); 385 assertThat(dumpContent).doesNotContain("Permission Denial:"); 386 } 387 getTestConfig()388 private static PersistableBundle getTestConfig() { 389 PersistableBundle config = new PersistableBundle(); 390 config.putInt(CARRIER_CONFIG_EXAMPLE_KEY, CARRIER_CONFIG_EXAMPLE_VALUE); 391 return config; 392 } 393 setCarrierPrivilegesForSubId(boolean hasCarrierPrivileges, int subId)394 private void setCarrierPrivilegesForSubId(boolean hasCarrierPrivileges, int subId) { 395 TelephonyManager mockTelephonyManager = Mockito.mock(TelephonyManager.class); 396 doReturn(mockTelephonyManager).when(mTelephonyManager).createForSubscriptionId(subId); 397 doReturn(hasCarrierPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS 398 : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS).when( 399 mockTelephonyManager).getCarrierPrivilegeStatus(anyInt()); 400 } 401 } 402