Merge "Tune up TIMEOUTs of IPSec CTS for low end devices"
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
index 54509cd..ccbdbd3 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
@@ -129,6 +129,12 @@
 
     private static final IBinder BINDER = new Binder();
 
+    // Lock for accessing Shell Permissions. Use of this lock around adoptShellPermissionIdentity,
+    // runWithShellPermissionIdentity, and callWithShellPermissionIdentity ensures Shell Permission
+    // is not interrupted by another operation (which would drop all previously adopted
+    // permissions).
+    private Object mShellPermissionsIdentityLock = new Object();
+
     private Context mContext;
     private ConnectivityManager mConnectivityManager;
     private ConnectivityDiagnosticsManager mCdm;
@@ -244,20 +250,24 @@
                 CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY,
                 new String[] {getCertHashForThisPackage()});
 
-        runWithShellPermissionIdentity(
-                () -> {
-                    mCarrierConfigManager.overrideConfig(subId, carrierConfigs);
-                    mCarrierConfigManager.notifyConfigChangedForSubId(subId);
-                },
-                android.Manifest.permission.MODIFY_PHONE_STATE);
+        synchronized (mShellPermissionsIdentityLock) {
+            runWithShellPermissionIdentity(
+                    () -> {
+                        mCarrierConfigManager.overrideConfig(subId, carrierConfigs);
+                        mCarrierConfigManager.notifyConfigChangedForSubId(subId);
+                    },
+                    android.Manifest.permission.MODIFY_PHONE_STATE);
+        }
 
         // TODO(b/157779832): This should use android.permission.CHANGE_NETWORK_STATE. However, the
         // shell does not have CHANGE_NETWORK_STATE, so use CONNECTIVITY_INTERNAL until the shell
         // permissions are updated.
-        runWithShellPermissionIdentity(
-                () -> mConnectivityManager.requestNetwork(
-                        CELLULAR_NETWORK_REQUEST, testNetworkCallback),
-                android.Manifest.permission.CONNECTIVITY_INTERNAL);
+        synchronized (mShellPermissionsIdentityLock) {
+            runWithShellPermissionIdentity(
+                    () -> mConnectivityManager.requestNetwork(
+                            CELLULAR_NETWORK_REQUEST, testNetworkCallback),
+                    android.Manifest.permission.CONNECTIVITY_INTERNAL);
+        }
 
         final Network network = testNetworkCallback.waitForAvailable();
         assertNotNull(network);
@@ -536,9 +546,18 @@
     }
 
     private class CarrierConfigReceiver extends BroadcastReceiver {
+        // CountDownLatch used to wait for this BroadcastReceiver to be notified of a CarrierConfig
+        // change. This latch will be counted down if a broadcast indicates this package has carrier
+        // configs, or if an Exception occurs in #onReceive.
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private final int mSubId;
 
+        // #onReceive may encounter Exceptions while running on the Process' main Thread and
+        // #waitForCarrierConfigChanged checks the cached Exception from the test Thread. These
+        // Exceptions must be cached and thrown later, as throwing on the Process' main Thread will
+        // crash the process and cause other tests to fail.
+        private Exception mOnReceiveException;
+
         CarrierConfigReceiver(int subId) {
             mSubId = subId;
         }
@@ -546,6 +565,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+                // Received an incorrect broadcast - ignore
                 return;
             }
 
@@ -553,24 +573,64 @@
                     intent.getIntExtra(
                             CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
                             SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-            if (mSubId != subId) return;
+            if (mSubId != subId) {
+                // Received a broadcast for the wrong subId - ignore
+                return;
+            }
 
-            final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
-            if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) return;
+            final PersistableBundle carrierConfigs;
+            try {
+                synchronized (mShellPermissionsIdentityLock) {
+                    carrierConfigs = callWithShellPermissionIdentity(
+                            () -> mCarrierConfigManager.getConfigForSubId(subId),
+                            android.Manifest.permission.READ_PHONE_STATE);
+                }
+            } catch (Exception exception) {
+                // callWithShellPermissionIdentity() threw an Exception - cache it and allow
+                // waitForCarrierConfigChanged() to throw it
+                mOnReceiveException = exception;
+                mLatch.countDown();
+                return;
+            }
 
-            final String[] certs =
-                    carrierConfigs.getStringArray(
-                            CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY);
+            if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) {
+                // Configs are not for an identified carrier (meaning they are defaults) - ignore
+                return;
+            }
+
+            final String[] certs = carrierConfigs.getStringArray(
+                    CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY);
             try {
                 if (ArrayUtils.contains(certs, getCertHashForThisPackage())) {
+                    // Received an update for this package's cert hash - countdown and exit
                     mLatch.countDown();
                 }
-            } catch (Exception e) {
+                // Broadcast is for the right subId, but does not show this package as Carrier
+                // Privileged. Keep waiting for a broadcast that indicates Carrier Privileges.
+            } catch (Exception exception) {
+                // getCertHashForThisPackage() threw an Exception - cache it and allow
+                // waitForCarrierConfigChanged() to throw it
+                mOnReceiveException = exception;
+                mLatch.countDown();
             }
         }
 
+        /**
+         * Waits for the CarrierConfig changed broadcast to reach this CarrierConfigReceiver.
+         *
+         * <p>Must be called from the Test Thread.
+         *
+         * @throws Exception if an Exception occurred during any #onReceive invocation
+         */
         boolean waitForCarrierConfigChanged() throws Exception {
-            return mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS);
+            final boolean result = mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT,
+                    TimeUnit.MILLISECONDS);
+
+            if (mOnReceiveException != null) {
+                throw mOnReceiveException;
+            }
+
+            return result;
         }
     }
 }
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 7508228..45a84f8 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -62,6 +62,7 @@
 import com.android.internal.util.AsyncChannel
 import com.android.net.module.util.ArrayTrackRecord
 import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
 import com.android.testutils.RecorderCallback.CallbackEntry.Available
 import com.android.testutils.RecorderCallback.CallbackEntry.Lost
 import com.android.testutils.TestableNetworkCallback
@@ -541,6 +542,7 @@
     }
 
     @Test
+    @IgnoreUpTo(android.os.Build.VERSION_CODES.R)
     fun testAgentStartsInConnecting() {
         val mockContext = mock(Context::class.java)
         val mockCm = mock(ConnectivityManager::class.java)
diff --git a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
index 37bdd44..1d9268a 100755
--- a/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
+++ b/tests/cts/net/src/android/net/cts/TrafficStatsTest.java
@@ -59,9 +59,11 @@
         assertTrue(TrafficStats.getTotalRxBytes() >= 0);
     }
 
-    public void testValidPacketStats() {
+    public void testValidIfaceStats() {
         assertTrue(TrafficStats.getTxPackets("lo") >= 0);
         assertTrue(TrafficStats.getRxPackets("lo") >= 0);
+        assertTrue(TrafficStats.getTxBytes("lo") >= 0);
+        assertTrue(TrafficStats.getRxBytes("lo") >= 0);
     }
 
     public void testThreadStatsTag() throws Exception {
@@ -109,6 +111,8 @@
         final long uidRxPacketsBefore = TrafficStats.getUidRxPackets(Process.myUid());
         final long ifaceTxPacketsBefore = TrafficStats.getTxPackets("lo");
         final long ifaceRxPacketsBefore = TrafficStats.getRxPackets("lo");
+        final long ifaceTxBytesBefore = TrafficStats.getTxBytes("lo");
+        final long ifaceRxBytesBefore = TrafficStats.getRxBytes("lo");
 
         // Transfer 1MB of data across an explicitly localhost socket.
         final int byteCount = 1024;
@@ -189,8 +193,12 @@
         final long uidRxDeltaPackets = uidRxPacketsAfter - uidRxPacketsBefore;
         final long ifaceTxPacketsAfter = TrafficStats.getTxPackets("lo");
         final long ifaceRxPacketsAfter = TrafficStats.getRxPackets("lo");
+        final long ifaceTxBytesAfter = TrafficStats.getTxBytes("lo");
+        final long ifaceRxBytesAfter = TrafficStats.getRxBytes("lo");
         final long ifaceTxDeltaPackets = ifaceTxPacketsAfter - ifaceTxPacketsBefore;
         final long ifaceRxDeltaPackets = ifaceRxPacketsAfter - ifaceRxPacketsBefore;
+        final long ifaceTxDeltaBytes = ifaceTxBytesAfter - ifaceTxBytesBefore;
+        final long ifaceRxDeltaBytes = ifaceRxBytesAfter - ifaceRxBytesBefore;
 
         // Localhost traffic *does* count against per-UID stats.
         /*
@@ -246,9 +254,13 @@
         assertInRange("uidrxb", uidRxDeltaBytes, pktBytes + minExpExtraPktBytes,
                 pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes + deltaRxOtherPktBytes);
         assertInRange("iftxp", ifaceTxDeltaPackets, packetCount + minExpectedExtraPackets,
-                packetCount + packetCount + maxExpectedExtraPackets + deltaTxOtherPackets);
+                packetCount + packetCount + maxExpectedExtraPackets);
         assertInRange("ifrxp", ifaceRxDeltaPackets, packetCount + minExpectedExtraPackets,
-                packetCount + packetCount + maxExpectedExtraPackets + deltaRxOtherPackets);
+                packetCount + packetCount + maxExpectedExtraPackets);
+        assertInRange("iftxb", ifaceTxDeltaBytes, pktBytes + minExpExtraPktBytes,
+                pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes);
+        assertInRange("ifrxb", ifaceRxDeltaBytes, pktBytes + minExpExtraPktBytes,
+                pktBytes + pktWithNoDataBytes + maxExpExtraPktBytes);
 
         // Localhost traffic *does* count against total stats.
         // Check the total stats increased after test data transfer over localhost has been made.
@@ -264,6 +276,10 @@
                 totalTxPacketsAfter >= totalTxPacketsBefore + ifaceTxDeltaPackets);
         assertTrue("ifrxp: " + ifaceRxPacketsBefore + " -> " + ifaceRxPacketsAfter,
                 totalRxPacketsAfter >= totalRxPacketsBefore + ifaceRxDeltaPackets);
+        assertTrue("iftxb: " + ifaceTxBytesBefore + " -> " + ifaceTxBytesAfter,
+            totalTxBytesAfter >= totalTxBytesBefore + ifaceTxDeltaBytes);
+        assertTrue("ifrxb: " + ifaceRxBytesBefore + " -> " + ifaceRxBytesAfter,
+            totalRxBytesAfter >= totalRxBytesBefore + ifaceRxDeltaBytes);
 
         // Localhost traffic should *not* count against mobile stats,
         // There might be some other traffic, but nowhere near 1MB.