• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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