Merge changes from topic "new-ipsec-api"

* changes:
  Expose new algorithms as public API
  Add new mandatory IPsec algorithms
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 7c1c1c7..72559b4 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -28,6 +28,7 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.Process;
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 
@@ -113,10 +114,11 @@
                         TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
         boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
                 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        final int appId = UserHandle.getAppId(callingUid);
         if (hasCarrierPrivileges || isDeviceOwner
-                || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) {
-            // Carrier-privileged apps and device owners, and the system can access data usage for
-            // all apps on the device.
+                || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) {
+            // Carrier-privileged apps and device owners, and the system (including the
+            // network stack) can access data usage for all apps on the device.
             return NetworkStatsAccess.Level.DEVICE;
         }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index d202a2a..5646c75 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -30,6 +30,7 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.CollectionUtils;
@@ -94,39 +95,41 @@
         // also needed to track CBRS.
         final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager);
 
-        for (final int subId : newSubs) {
-            final RatTypeListener match = CollectionUtils.find(mRatListeners,
-                    it -> it.mSubId == subId);
-            if (match != null) continue;
+        // IMSI is needed for every newly added sub. Listener stores subscriberId into it to
+        // prevent binder call to telephony when querying RAT. Keep listener registration with empty
+        // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported
+        // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration.
+        final List<Pair<Integer, String>> filteredNewSubs =
+                CollectionUtils.mapNotNull(newSubs, subId -> {
+                    final String subscriberId = mTeleManager.getSubscriberId(subId);
+                    return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId);
+                });
 
-            // Create listener for every newly added sub. Also store subscriberId into it to
-            // prevent binder call to telephony when querying RAT. If the subscriberId is empty
-            // for any reason, such as SIM PIN locked, skip registration.
-            // SubscriberId will be unavailable again if 1. modem crashed 2. reboot
-            // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized
-            // with active sub list once all subscriberIds are ready.
-            final String subscriberId = mTeleManager.getSubscriberId(subId);
-            if (TextUtils.isEmpty(subscriberId)) {
-                Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub "
-                        + subId + ", skip listener registration");
+        for (final Pair<Integer, String> sub : filteredNewSubs) {
+            // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be
+            // suddenly change regardless of subId, such as switch IMSI feature in modem side.
+            // If that happens, register new listener with new IMSI and remove old one later.
+            if (CollectionUtils.find(mRatListeners,
+                    it -> it.equalsKey(sub.first, sub.second)) != null) {
                 continue;
             }
+
             final RatTypeListener listener =
-                    new RatTypeListener(mExecutor, this, subId, subscriberId);
+                    new RatTypeListener(mExecutor, this, sub.first, sub.second);
             mRatListeners.add(listener);
 
             // Register listener to the telephony manager that associated with specific sub.
-            mTeleManager.createForSubscriptionId(subId)
+            mTeleManager.createForSubscriptionId(sub.first)
                     .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
-            Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId);
+            Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first);
         }
 
         for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
-            // If the new list contains the subId of the listener, keeps it.
-            final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId);
-            if (match != null) continue;
-
-            handleRemoveRatTypeListener(listener);
+            // If there is no subId and IMSI matched the listener, removes it.
+            if (CollectionUtils.find(filteredNewSubs,
+                    it -> listener.equalsKey(it.first, it.second)) == null) {
+                handleRemoveRatTypeListener(listener);
+            }
         }
     }
 
@@ -232,5 +235,9 @@
         public int getSubId() {
             return mSubId;
         }
+
+        boolean equalsKey(int subId, @NonNull String subscriberId) {
+            return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId);
+        }
     }
 }