1 /* 2 * Copyright (C) 2022 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 package android.telephony.cts; 17 18 import static android.telephony.mockmodem.MockSimService.MOCK_SIM_PROFILE_ID_TWN_CHT; 19 import static android.telephony.mockmodem.MockSimService.MOCK_SIM_PROFILE_ID_TWN_FET; 20 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assume.assumeTrue; 25 26 import android.database.Cursor; 27 import android.net.ConnectivityManager; 28 import android.net.ConnectivityManager.NetworkCallback; 29 import android.net.LinkProperties; 30 import android.net.Network; 31 import android.net.NetworkCapabilities; 32 import android.net.NetworkRequest; 33 import android.net.Uri; 34 import android.os.Build; 35 import android.telephony.AccessNetworkConstants; 36 import android.telephony.NetworkRegistrationInfo; 37 import android.telephony.ServiceState; 38 import android.telephony.SubscriptionInfo; 39 import android.telephony.SubscriptionManager; 40 import android.util.Log; 41 42 import androidx.test.platform.app.InstrumentationRegistry; 43 44 import com.android.compatibility.common.util.ApiTest; 45 import com.android.compatibility.common.util.ShellIdentityUtils; 46 47 import org.junit.After; 48 import org.junit.AfterClass; 49 import org.junit.Before; 50 import org.junit.BeforeClass; 51 import org.junit.Test; 52 53 import java.util.List; 54 import java.util.concurrent.CountDownLatch; 55 import java.util.concurrent.TimeUnit; 56 57 /** Test MockModemService interfaces. */ 58 public class ConnectivityManagerTestOnMockModem extends MockModemTestBase { 59 private static final String TAG = "ConnectivityManagerTestOnMockModem"; 60 private static final int TIMEOUT_NETWORK_VALIDATION = 20000; 61 private static final int TIMEOUT_ACTIVATE_NETWORK = 20000; 62 private static final int WAIT_MSEC = 500; 63 private static final int NETWORK_AVAILABLE_SEC = 60; 64 private static boolean sIsValidate; 65 private static boolean sIsOnAvailable; 66 private static Network sDefaultNetwork; 67 private static Object sIsValidateLock = new Object(); 68 private static Object sIsOnAvailableLock = new Object(); 69 private static CMNetworkCallback sNetworkCallback; 70 private static SubscriptionManager sSubscriptionManager; 71 private static ConnectivityManager sConnectivityManager; 72 private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; 73 private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem"; 74 private static final boolean DEBUG = !"user".equals(Build.TYPE); 75 private static final String RESOURCE_PACKAGE_NAME = "android"; 76 @SuppressWarnings("StaticAssignmentOfThrowable") 77 private static AssertionError sInitError = null; 78 private static final String APN_SETTINGS_URL = "content://telephony/carriers"; 79 private static final String COLUMN_ID = "_id"; 80 private static final String COLUMN_NAME = "name"; 81 private static final String COLUMN_APN = "apn"; 82 private static final String COLUMN_TYPE = "type"; 83 private static final String MCC_MNC_TWN_CHT = "46692"; 84 private static final String MCC_MNC_TWN_FET = "46601"; 85 86 87 private static class CMNetworkCallback extends NetworkCallback { 88 final CountDownLatch mNetworkLatch = new CountDownLatch(1); 89 90 @Override onCapabilitiesChanged(Network network, NetworkCapabilities nc)91 public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { 92 sDefaultNetwork = network; 93 Log.d( 94 TAG, 95 "Network capabilities changed. network: " 96 + network 97 + ", NetworkCapabilities: " 98 + nc); 99 100 if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) { 101 Log.d( 102 TAG, 103 "Network capabilities changed. network: " 104 + network 105 + " ,validation: Pass!"); 106 synchronized (sIsValidateLock) { 107 sIsValidate = true; 108 sIsValidateLock.notify(); 109 } 110 } else { 111 Log.d( 112 TAG, 113 "Network capabilities changed. network: " 114 + network 115 + " ,validation: Fail!"); 116 synchronized (sIsValidateLock) { 117 sIsValidate = false; 118 } 119 } 120 } 121 122 @Override onLost(Network network)123 public void onLost(Network network) { 124 sDefaultNetwork = network; 125 Log.d(TAG, "onLost(): network: " + network); 126 synchronized (sIsOnAvailableLock) { 127 sIsOnAvailable = false; 128 } 129 } 130 131 @Override onAvailable(Network network)132 public void onAvailable(Network network) { 133 sDefaultNetwork = network; 134 Log.d(TAG, "onAvailable(): network: " + network); 135 synchronized (sIsOnAvailableLock) { 136 sIsOnAvailable = true; 137 mNetworkLatch.countDown(); 138 } 139 } 140 awaitNetwork()141 public void awaitNetwork() throws InterruptedException { 142 Log.d(TAG, "awaitNetwork(): " + NETWORK_AVAILABLE_SEC + " sec"); 143 mNetworkLatch.await(NETWORK_AVAILABLE_SEC, TimeUnit.SECONDS); 144 } 145 146 @Override onLinkPropertiesChanged(Network network, LinkProperties linkProperties)147 public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {} 148 } 149 150 @BeforeClass 151 @SuppressWarnings("StaticAssignmentOfThrowable") beforeAllTests()152 public static void beforeAllTests() throws Exception { 153 TimeUnit.SECONDS.sleep(10); 154 if (!MockModemTestBase.beforeAllTestsCheck()) return; 155 156 sConnectivityManager = 157 (ConnectivityManager) getContext().getSystemService(ConnectivityManager.class); 158 159 sSubscriptionManager = 160 InstrumentationRegistry.getInstrumentation().getContext() 161 .getSystemService(SubscriptionManager.class); 162 163 registerNetworkCallback(); 164 165 Network activeNetwork = sConnectivityManager.getActiveNetwork(); 166 NetworkCapabilities nc; 167 if (activeNetwork == null) { 168 sInitError = new AssertionError("This test requires there is an active network. " 169 + "But the active network is null."); 170 return; 171 } 172 173 nc = sConnectivityManager.getNetworkCapabilities(activeNetwork); 174 175 if (!nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { 176 sInitError = new AssertionError( 177 "This test requires there is a transport type with TRANSPORT_CELLULAR."); 178 return; 179 } 180 181 if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { 182 sInitError = new AssertionError("This test requires there is a network capabilities" 183 + " with NET_CAPABILITY_INTERNET."); 184 return; 185 } 186 187 if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) { 188 sInitError = new AssertionError("This test requires there is a network capabilities" 189 + " with NET_CAPABILITY_VALIDATED."); 190 return; 191 } 192 193 unregisterNetworkCallback(); 194 195 MockModemTestBase.createMockModemAndConnectToService(); 196 } 197 198 @AfterClass afterAllTests()199 public static void afterAllTests() throws Exception { 200 MockModemTestBase.afterAllTestsBase(); 201 } 202 203 @Before beforeTest()204 public void beforeTest() { 205 super.beforeTest(); 206 if (sInitError != null) throw sInitError; 207 registerNetworkCallback(); 208 } 209 210 @After afterTest()211 public void afterTest() { 212 super.afterTest(); 213 // unregister the network call back 214 if (sNetworkCallback != null) { 215 unregisterNetworkCallback(); 216 } 217 } 218 219 hasApns(String mccmnc)220 private static boolean hasApns(String mccmnc) { 221 Uri uri = Uri.parse(APN_SETTINGS_URL); 222 223 // Query the database using a ContentResolver 224 String[] projection = new String[]{COLUMN_ID, COLUMN_NAME, COLUMN_APN, COLUMN_TYPE}; 225 String selection = "numeric = ?"; // Filter by mccmnc 226 String[] selectionArgs = new String[]{mccmnc}; // Provide the mccmnc as an argument 227 int count = 0; 228 adoptShellPermissionIdentity(); 229 try (Cursor cursor = 230 InstrumentationRegistry.getInstrumentation().getContext().getContentResolver() 231 .query(uri, projection, selection, selectionArgs, null)) { 232 233 if (cursor != null && cursor.moveToFirst()) { 234 count = cursor.getCount(); 235 Log.i(TAG, "Carrier count for " + mccmnc + ": " + count); 236 do { 237 int idIndex = cursor.getColumnIndex(COLUMN_ID); 238 int nameIndex = cursor.getColumnIndex(COLUMN_NAME); 239 int typeIndex = cursor.getColumnIndex(COLUMN_TYPE); 240 int apnIndex = cursor.getColumnIndex(COLUMN_APN); 241 242 if (idIndex != -1 && nameIndex != -1 && typeIndex != -1 && apnIndex != -1) { 243 int id = cursor.getInt(idIndex); 244 String name = cursor.getString(nameIndex); 245 String type = cursor.getString(typeIndex); 246 String apn = cursor.getString(apnIndex); 247 Log.d(TAG, "ID: " + id + ", Name: " + name + ", Apn: " 248 + apn + ", Type: " + type); 249 } 250 } while (cursor.moveToNext()); 251 } else { 252 Log.i(TAG, "No results found for carrier " + mccmnc); 253 } 254 255 } catch (Exception e) { 256 Log.e(TAG, "Error querying carriers table: " + mccmnc + ": " + e.getMessage()); 257 } finally { 258 dropShellPermissionIdentity(); 259 } 260 return count > 0; 261 } 262 263 /** Allows test app to run as shell UID to acquire privileged permissions */ adoptShellPermissionIdentity()264 public static void adoptShellPermissionIdentity() { 265 InstrumentationRegistry.getInstrumentation().getUiAutomation() 266 .adoptShellPermissionIdentity(); 267 } 268 269 /** Disallow test app to run as shell UID to acquire privileged permissions */ dropShellPermissionIdentity()270 public static void dropShellPermissionIdentity() { 271 InstrumentationRegistry.getInstrumentation().getUiAutomation() 272 .dropShellPermissionIdentity(); 273 } 274 getRegState(int domain)275 private int getRegState(int domain) { 276 int reg; 277 278 InstrumentationRegistry.getInstrumentation() 279 .getUiAutomation() 280 .adoptShellPermissionIdentity("android.permission.READ_PHONE_STATE"); 281 282 ServiceState ss = sTelephonyManager.getServiceState(); 283 assertNotNull(ss); 284 285 NetworkRegistrationInfo nri = 286 ss.getNetworkRegistrationInfo(domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 287 assertNotNull(nri); 288 289 reg = nri.getRegistrationState(); 290 Log.d(TAG, "SS: " + nri.registrationStateToString(reg)); 291 292 return reg; 293 } 294 getNetworkValidated()295 private static synchronized boolean getNetworkValidated() { 296 Log.d(TAG, "getNetworkValidated: " + sIsValidate); 297 return sIsValidate; 298 } 299 getNetworkOnAvailable()300 private static synchronized boolean getNetworkOnAvailable() { 301 Log.d(TAG, "getNetworkOnAvailable: " + sIsOnAvailable); 302 return sIsOnAvailable; 303 } 304 getDefaultNetwork()305 private static synchronized Network getDefaultNetwork() { 306 Log.d(TAG, "getDefaultNetwork: enter "); 307 return sDefaultNetwork; 308 } 309 registerNetworkCallback()310 private static void registerNetworkCallback() { 311 sNetworkCallback = new CMNetworkCallback(); 312 try { 313 sConnectivityManager.registerNetworkCallback( 314 new NetworkRequest.Builder() 315 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 316 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 317 .build(), 318 sNetworkCallback); 319 Log.d(TAG, "registered networkCallback"); 320 } catch (RuntimeException e) { 321 Log.e(TAG, "Exception during registerNetworkCallback():" + e); 322 } 323 } 324 unregisterNetworkCallback()325 private static void unregisterNetworkCallback() { 326 try { 327 sConnectivityManager.unregisterNetworkCallback(sNetworkCallback); 328 Log.d(TAG, "unregisterNetworkCallback"); 329 } catch (IllegalArgumentException e) { 330 Log.e(TAG, "IllegalArgumentException during unregisterNetworkCallback(): ", e); 331 } finally { 332 sNetworkCallback = null; 333 } 334 } 335 336 @Test 337 @ApiTest( 338 apis = { 339 "android.net.ConnectivityManager.NetworkCallback#onCapabilitiesChanged", 340 "android.net.ConnectivityManager.NetworkCallback#onAvailable" 341 }) testNetworkValidated()342 public void testNetworkValidated() throws Throwable { 343 Log.d(TAG, "ConnectivityManagerTestOnMockModem#testNetworkValidated"); 344 assumeTrue(hasApns(MCC_MNC_TWN_CHT)); 345 assumeTrue(isSimHotSwapCapable()); 346 347 int slotId = 0; 348 349 // Insert a SIM 350 sMockModemManager.insertSimCard(slotId, MOCK_SIM_PROFILE_ID_TWN_CHT); 351 352 // Enter Service 353 Log.d(TAG, "testNetworkValidated: Enter Service"); 354 sMockModemManager.changeNetworkService(slotId, MOCK_SIM_PROFILE_ID_TWN_CHT, true); 355 356 // Get the list of available subscriptions 357 List<SubscriptionInfo> subscriptionInfoList = 358 ShellIdentityUtils.invokeMethodWithShellPermissions( 359 sSubscriptionManager, (sm) -> sm.getActiveSubscriptionInfoList()); 360 361 Log.d(TAG, "subscriptionInfoList: " + subscriptionInfoList); 362 363 for (SubscriptionInfo subscriptionInfo : subscriptionInfoList) { 364 InstrumentationRegistry.getInstrumentation() 365 .getUiAutomation() 366 .adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE"); 367 if (slotId == subscriptionInfo.getSimSlotIndex()) { 368 sSubscriptionManager.setDefaultDataSubId(subscriptionInfo.getSubscriptionId()); 369 sTelephonyManager.setDataEnabled(subscriptionInfo.getSubscriptionId(), true); 370 Log.d(TAG, "Set Data on slot: " + slotId); 371 } 372 } 373 374 // make sure the network is available 375 sNetworkCallback.awaitNetwork(); 376 assertTrue(getNetworkOnAvailable()); 377 378 // make sure the network is validated 379 sConnectivityManager.reportNetworkConnectivity(getDefaultNetwork(), false); 380 waitForExpectedValidationState(true, TIMEOUT_NETWORK_VALIDATION); 381 assertTrue(getNetworkValidated()); 382 383 // Leave Service 384 Log.d(TAG, "testNetworkValidated: Leave Service"); 385 sMockModemManager.changeNetworkService(slotId, MOCK_SIM_PROFILE_ID_TWN_CHT, false); 386 387 // Remove the SIM 388 sMockModemManager.removeSimCard(slotId); 389 390 waitForNullActiveNetwork(TIMEOUT_ACTIVATE_NETWORK); 391 assertNull(sConnectivityManager.getActiveNetwork()); 392 } 393 waitForExpectedValidationState(boolean validated, long timeout)394 private static void waitForExpectedValidationState(boolean validated, long timeout) 395 throws InterruptedException { 396 Log.d( 397 TAG, 398 "Wait For Expected ValidationState: expected: " 399 + validated 400 + ", timeout: " 401 + timeout 402 + "ms"); 403 synchronized (sIsValidateLock) { 404 long expectedTimeout = System.currentTimeMillis() + timeout; 405 boolean expectedResult = validated; 406 while (System.currentTimeMillis() < expectedTimeout 407 && getNetworkValidated() != expectedResult) { 408 sIsValidateLock.wait(WAIT_MSEC); 409 } 410 } 411 } 412 413 @Test testDDSChange()414 public void testDDSChange() throws Throwable { 415 Log.d(TAG, "ConnectivityManagerTestOnMockModem#testDDSChange"); 416 assumeTrue("Skip test: Not test on single SIM device", sIsMultiSimDevice); 417 assumeTrue(hasApns(MCC_MNC_TWN_CHT)); 418 assumeTrue(hasApns(MCC_MNC_TWN_FET)); 419 420 int slotId_0 = 0; 421 int slotId_1 = 1; 422 423 // Insert a SIM 424 sMockModemManager.insertSimCard(slotId_0, MOCK_SIM_PROFILE_ID_TWN_CHT); 425 sMockModemManager.insertSimCard(slotId_1, MOCK_SIM_PROFILE_ID_TWN_FET); 426 427 // Enter Service 428 Log.d(TAG, "testDsdsServiceStateChange: Enter Service"); 429 sMockModemManager.changeNetworkService(slotId_0, MOCK_SIM_PROFILE_ID_TWN_CHT, true); 430 sMockModemManager.changeNetworkService(slotId_1, MOCK_SIM_PROFILE_ID_TWN_FET, true); 431 432 for (int slotIndex = 0; slotIndex < 2; slotIndex++) { 433 boolean isDataEnabled = sTelephonyManager.getDataEnabled(slotIndex); 434 Log.d(TAG, "Data enabled status for SIM slot " + slotIndex + ": " + isDataEnabled); 435 } 436 437 String packageName = getContext().getPackageName(); 438 Log.d(TAG, "packageName: " + packageName); 439 440 // Get the list of available subscriptions 441 List<SubscriptionInfo> subscriptionInfoList = 442 ShellIdentityUtils.invokeMethodWithShellPermissions( 443 sSubscriptionManager, (sm) -> sm.getActiveSubscriptionInfoList()); 444 445 Log.d(TAG, "subscriptionInfoList: " + subscriptionInfoList); 446 447 // Loop through the subscriptions to get the phone id 448 // Set the data enable by phone id 449 for (SubscriptionInfo subscriptionInfo : subscriptionInfoList) { 450 InstrumentationRegistry.getInstrumentation() 451 .getUiAutomation() 452 .adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE"); 453 int slotId = subscriptionInfo.getSimSlotIndex(); 454 sSubscriptionManager.setDefaultDataSubId(subscriptionInfo.getSubscriptionId()); 455 sTelephonyManager.setDataEnabled(subscriptionInfo.getSubscriptionId(), true); 456 Log.d(TAG, "Set Data on slot: " + slotId); 457 // make sure the network is available 458 sNetworkCallback.awaitNetwork(); 459 Log.d(TAG, "Check Data : " + getNetworkOnAvailable()); 460 assertTrue(getNetworkOnAvailable()); 461 } 462 463 // Leave Service 464 Log.d(TAG, "testDsdsServiceStateChange: Leave Service"); 465 sMockModemManager.changeNetworkService(slotId_0, MOCK_SIM_PROFILE_ID_TWN_CHT, false); 466 sMockModemManager.changeNetworkService(slotId_1, MOCK_SIM_PROFILE_ID_TWN_FET, false); 467 468 // Remove the SIM 469 sMockModemManager.removeSimCard(slotId_0); 470 sMockModemManager.removeSimCard(slotId_1); 471 472 waitForNullActiveNetwork(TIMEOUT_ACTIVATE_NETWORK); 473 assertNull(sConnectivityManager.getActiveNetwork()); 474 } 475 waitForNullActiveNetwork(long timeout)476 private static void waitForNullActiveNetwork(long timeout) 477 throws InterruptedException { 478 Log.d( 479 TAG, 480 "Wait For Null ActiveNetwork: " 481 + "timeout: " 482 + timeout 483 + " ms"); 484 long expectedTimeout = System.currentTimeMillis() + timeout; 485 while (System.currentTimeMillis() < expectedTimeout 486 && sConnectivityManager.getActiveNetwork() != null) { 487 TimeUnit.SECONDS.sleep(1); 488 Log.d(TAG, "ActiveNetwork: " + sConnectivityManager.getActiveNetwork()); 489 } 490 } 491 } 492 493