Merge "Revert "Use VERSION_CODES.S instead of VERSION_CODES.R + 1""
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 1d5dc1d..098d8b6 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -16,6 +16,8 @@
 
 package android.app.usage;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -28,8 +30,11 @@
 import android.net.ConnectivityManager;
 import android.net.DataUsageRequest;
 import android.net.INetworkStatsService;
+import android.net.Network;
 import android.net.NetworkStack;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkTemplate;
+import android.net.UnderlyingNetworkInfo;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.net.netstats.provider.NetworkStatsProvider;
 import android.os.Binder;
@@ -48,6 +53,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetworkIdentityUtils;
 
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -633,6 +639,50 @@
         return template;
     }
 
+    /**
+     *  Notify {@code NetworkStatsService} about network status changed.
+     *
+     *  Notifies NetworkStatsService of network state changes for data usage accounting purposes.
+     *
+     *  To avoid races that attribute data usage to wrong network, such as new network with
+     *  the same interface after SIM hot-swap, this function will not return until
+     *  {@code NetworkStatsService} finishes its work of retrieving traffic statistics from
+     *  all data sources.
+     *
+     * @param defaultNetworks the list of all networks that could be used by network traffic that
+     *                        does not explicitly select a network.
+     * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for
+     *                              each network that is currently connected.
+     * @param activeIface the active (i.e., connected) default network interface for the calling
+     *                    uid. Used to determine on which network future calls to
+     *                    {@link android.net.TrafficStats#incrementOperationCount} applies to.
+     * @param underlyingNetworkInfos the list of underlying network information for all
+     *                               currently-connected VPNs.
+     *
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK})
+    public void notifyNetworkStatus(
+            @NonNull List<Network> defaultNetworks,
+            @NonNull List<NetworkStateSnapshot> networkStateSnapshots,
+            @Nullable String activeIface,
+            @NonNull List<UnderlyingNetworkInfo> underlyingNetworkInfos) {
+        try {
+            Objects.requireNonNull(defaultNetworks);
+            Objects.requireNonNull(networkStateSnapshots);
+            Objects.requireNonNull(underlyingNetworkInfos);
+            // TODO: Change internal namings after the name is decided.
+            mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]),
+                    networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface,
+                    underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0]));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private static class CallbackHandler extends Handler {
         private final int mNetworkType;
         private final String mSubscriberId;
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 0baf11e..dc3b88a 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -19,7 +19,7 @@
 import android.net.DataUsageRequest;
 import android.net.INetworkStatsSession;
 import android.net.Network;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
@@ -68,7 +68,7 @@
     /** Force update of ifaces. */
     void forceUpdateIfaces(
          in Network[] defaultNetworks,
-         in NetworkState[] networkStates,
+         in NetworkStateSnapshot[] snapshots,
          in String activeIface,
          in UnderlyingNetworkInfo[] underlyingNetworkInfos);
     /** Force update of statistics. */
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 32b19a4..a5ece7b 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -41,6 +41,22 @@
 
     public static final int SUBTYPE_COMBINED = -1;
 
+    /**
+     * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}.
+     * @hide
+     */
+    public static final int OEM_NONE = 0x0;
+    /**
+     * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}.
+     * @hide
+     */
+    public static final int OEM_PAID = 0x1;
+    /**
+     * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}.
+     * @hide
+     */
+    public static final int OEM_PRIVATE = 0x2;
+
     final int mType;
     final int mSubType;
     final String mSubscriberId;
@@ -48,10 +64,11 @@
     final boolean mRoaming;
     final boolean mMetered;
     final boolean mDefaultNetwork;
+    final int mOemManaged;
 
     public NetworkIdentity(
             int type, int subType, String subscriberId, String networkId, boolean roaming,
-            boolean metered, boolean defaultNetwork) {
+            boolean metered, boolean defaultNetwork, int oemManaged) {
         mType = type;
         mSubType = subType;
         mSubscriberId = subscriberId;
@@ -59,12 +76,13 @@
         mRoaming = roaming;
         mMetered = metered;
         mDefaultNetwork = defaultNetwork;
+        mOemManaged = oemManaged;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered,
-                mDefaultNetwork);
+                mDefaultNetwork, mOemManaged);
     }
 
     @Override
@@ -75,7 +93,8 @@
                     && Objects.equals(mSubscriberId, ident.mSubscriberId)
                     && Objects.equals(mNetworkId, ident.mNetworkId)
                     && mMetered == ident.mMetered
-                    && mDefaultNetwork == ident.mDefaultNetwork;
+                    && mDefaultNetwork == ident.mDefaultNetwork
+                    && mOemManaged == ident.mOemManaged;
         }
         return false;
     }
@@ -102,6 +121,8 @@
         }
         builder.append(", metered=").append(mMetered);
         builder.append(", defaultNetwork=").append(mDefaultNetwork);
+        // TODO(180557699): Print a human readable string for OEM managed state.
+        builder.append(", oemManaged=").append(mOemManaged);
         return builder.append("}").toString();
     }
 
@@ -120,6 +141,7 @@
         proto.write(NetworkIdentityProto.ROAMING, mRoaming);
         proto.write(NetworkIdentityProto.METERED, mMetered);
         proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork);
+        proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged);
 
         proto.end(start);
     }
@@ -152,28 +174,47 @@
         return mDefaultNetwork;
     }
 
-    /**
-     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType},
-     * assuming that any mobile networks are using the current IMSI. The subType if applicable,
-     * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or
-     * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
-     */
-    public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
-            boolean defaultNetwork, @NetworkType int subType) {
-        final int legacyType = state.legacyNetworkType;
+    public int getOemManaged() {
+        return mOemManaged;
+    }
 
-        String subscriberId = null;
+    /**
+     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and
+     * {@code subType}, assuming that any mobile networks are using the current IMSI.
+     * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
+     * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
+     */
+    // TODO: Delete this function after NetworkPolicyManagerService finishes the migration.
+    public static NetworkIdentity buildNetworkIdentity(Context context,
+            NetworkState state, boolean defaultNetwork, @NetworkType int subType) {
+        final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network,
+                state.networkCapabilities, state.linkProperties, state.subscriberId,
+                state.legacyNetworkType);
+        return buildNetworkIdentity(context, snapshot, defaultNetwork, subType);
+    }
+
+    /**
+     * Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and
+     * {@code subType}, assuming that any mobile networks are using the current IMSI.
+     * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
+     * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
+     */
+    public static NetworkIdentity buildNetworkIdentity(Context context,
+            NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) {
+        final int legacyType = snapshot.legacyType;
+
+        final String subscriberId = snapshot.subscriberId;
         String networkId = null;
-        boolean roaming = !state.networkCapabilities.hasCapability(
+        boolean roaming = !snapshot.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
-        boolean metered = !state.networkCapabilities.hasCapability(
+        boolean metered = !snapshot.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
 
-        subscriberId = state.subscriberId;
+        final int oemManaged = getOemBitfield(snapshot.networkCapabilities);
 
         if (legacyType == TYPE_WIFI) {
-            if (state.networkCapabilities.getSsid() != null) {
-                networkId = state.networkCapabilities.getSsid();
+            if (snapshot.networkCapabilities.getSsid() != null) {
+                networkId = snapshot.networkCapabilities.getSsid();
                 if (networkId == null) {
                     // TODO: Figure out if this code path never runs. If so, remove them.
                     final WifiManager wifi = (WifiManager) context.getSystemService(
@@ -185,7 +226,24 @@
         }
 
         return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered,
-                defaultNetwork);
+                defaultNetwork, oemManaged);
+    }
+
+    /**
+     * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}.
+     * @hide
+     */
+    public static int getOemBitfield(NetworkCapabilities nc) {
+        int oemManaged = OEM_NONE;
+
+        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) {
+            oemManaged |= OEM_PAID;
+        }
+        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) {
+            oemManaged |= OEM_PRIVATE;
+        }
+
+        return oemManaged;
     }
 
     @Override
@@ -209,6 +267,9 @@
         if (res == 0) {
             res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork);
         }
+        if (res == 0) {
+            res = Integer.compare(mOemManaged, another.mOemManaged);
+        }
         return res;
     }
 }
diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java
new file mode 100644
index 0000000..b3d8d4e
--- /dev/null
+++ b/core/java/android/net/NetworkStateSnapshot.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Snapshot of network state.
+ *
+ * @hide
+ */
+@SystemApi(client = MODULE_LIBRARIES)
+public final class NetworkStateSnapshot implements Parcelable {
+    /** The network associated with this snapshot. */
+    @NonNull
+    public final Network network;
+
+    /** The {@link NetworkCapabilities} of the network associated with this snapshot. */
+    @NonNull
+    public final NetworkCapabilities networkCapabilities;
+
+    /** The {@link LinkProperties} of the network associated with this snapshot. */
+    @NonNull
+    public final LinkProperties linkProperties;
+
+    /**
+     * The Subscriber Id of the network associated with this snapshot. See
+     * {@link android.telephony.TelephonyManager#getSubscriberId()}.
+     */
+    @Nullable
+    public final String subscriberId;
+
+    /**
+     * The legacy type of the network associated with this snapshot. See
+     * {@code ConnectivityManager#TYPE_*}.
+     */
+    public final int legacyType;
+
+    public NetworkStateSnapshot(@NonNull Network network,
+            @NonNull NetworkCapabilities networkCapabilities,
+            @NonNull LinkProperties linkProperties,
+            @Nullable String subscriberId, int legacyType) {
+        this.network = Objects.requireNonNull(network);
+        this.networkCapabilities = Objects.requireNonNull(networkCapabilities);
+        this.linkProperties = Objects.requireNonNull(linkProperties);
+        this.subscriberId = subscriberId;
+        this.legacyType = legacyType;
+    }
+
+    /** @hide */
+    public NetworkStateSnapshot(@NonNull Parcel in) {
+        network = in.readParcelable(null);
+        networkCapabilities = in.readParcelable(null);
+        linkProperties = in.readParcelable(null);
+        subscriberId = in.readString();
+        legacyType = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeParcelable(network, flags);
+        out.writeParcelable(networkCapabilities, flags);
+        out.writeParcelable(linkProperties, flags);
+        out.writeString(subscriberId);
+        out.writeInt(legacyType);
+    }
+
+    @NonNull
+    public static final Creator<NetworkStateSnapshot> CREATOR =
+            new Creator<NetworkStateSnapshot>() {
+        @NonNull
+        @Override
+        public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) {
+            return new NetworkStateSnapshot(in);
+        }
+
+        @NonNull
+        @Override
+        public NetworkStateSnapshot[] newArray(int size) {
+            return new NetworkStateSnapshot[size];
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof NetworkStateSnapshot)) return false;
+        NetworkStateSnapshot that = (NetworkStateSnapshot) o;
+        return legacyType == that.legacyType
+                && Objects.equals(network, that.network)
+                && Objects.equals(networkCapabilities, that.networkCapabilities)
+                && Objects.equals(linkProperties, that.linkProperties)
+                && Objects.equals(subscriberId, that.subscriberId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType);
+    }
+}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index aa61e03..c83dd99 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -23,6 +23,7 @@
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.NetworkIdentity.OEM_NONE;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -99,6 +100,22 @@
      */
     public static final int NETWORK_TYPE_5G_NSA = -2;
 
+    /**
+     * Value to match both OEM managed and unmanaged networks (all networks).
+     * @hide
+     */
+    public static final int OEM_MANAGED_ALL = -1;
+    /**
+     * Value to match networks which are not OEM managed.
+     * @hide
+     */
+    public static final int OEM_MANAGED_NO = OEM_NONE;
+    /**
+     * Value to match any OEM managed network.
+     * @hide
+     */
+    public static final int OEM_MANAGED_YES = -2;
+
     private static boolean isKnownMatchRule(final int rule) {
         switch (rule) {
             case MATCH_MOBILE:
@@ -151,10 +168,10 @@
             @NetworkType int ratType) {
         if (TextUtils.isEmpty(subscriberId)) {
             return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
-                    METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
+                    METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
         }
         return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
-                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
     }
 
     /**
@@ -235,6 +252,9 @@
     private final int mDefaultNetwork;
     private final int mSubType;
 
+    // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
+    private final int mOemManaged;
+
     @UnsupportedAppUsage
     public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
         this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
@@ -243,11 +263,12 @@
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
             String networkId) {
         this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL);
+                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
     }
 
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId, int metered, int roaming, int defaultNetwork, int subType) {
+            String networkId, int metered, int roaming, int defaultNetwork, int subType,
+            int oemManaged) {
         mMatchRule = matchRule;
         mSubscriberId = subscriberId;
         mMatchSubscriberIds = matchSubscriberIds;
@@ -256,6 +277,7 @@
         mRoaming = roaming;
         mDefaultNetwork = defaultNetwork;
         mSubType = subType;
+        mOemManaged = oemManaged;
 
         if (!isKnownMatchRule(matchRule)) {
             Log.e(TAG, "Unknown network template rule " + matchRule
@@ -272,6 +294,7 @@
         mRoaming = in.readInt();
         mDefaultNetwork = in.readInt();
         mSubType = in.readInt();
+        mOemManaged = in.readInt();
     }
 
     @Override
@@ -284,6 +307,7 @@
         dest.writeInt(mRoaming);
         dest.writeInt(mDefaultNetwork);
         dest.writeInt(mSubType);
+        dest.writeInt(mOemManaged);
     }
 
     @Override
@@ -319,13 +343,16 @@
         if (mSubType != NETWORK_TYPE_ALL) {
             builder.append(", subType=").append(mSubType);
         }
+        if (mOemManaged != OEM_MANAGED_ALL) {
+            builder.append(", oemManaged=").append(mOemManaged);
+        }
         return builder.toString();
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
-                mDefaultNetwork, mSubType);
+                mDefaultNetwork, mSubType, mOemManaged);
     }
 
     @Override
@@ -338,7 +365,8 @@
                     && mMetered == other.mMetered
                     && mRoaming == other.mRoaming
                     && mDefaultNetwork == other.mDefaultNetwork
-                    && mSubType == other.mSubType;
+                    && mSubType == other.mSubType
+                    && mOemManaged == other.mOemManaged;
         }
         return false;
     }
@@ -384,6 +412,7 @@
         if (!matchesMetered(ident)) return false;
         if (!matchesRoaming(ident)) return false;
         if (!matchesDefaultNetwork(ident)) return false;
+        if (!matchesOemNetwork(ident)) return false;
 
         switch (mMatchRule) {
             case MATCH_MOBILE:
@@ -425,6 +454,13 @@
             || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
     }
 
+    private boolean matchesOemNetwork(NetworkIdentity ident) {
+        return (mOemManaged == OEM_MANAGED_ALL)
+            || (mOemManaged == OEM_MANAGED_YES
+                    && ident.mOemManaged != OEM_NONE)
+            || (mOemManaged == ident.mOemManaged);
+    }
+
     private boolean matchesCollapsedRatType(NetworkIdentity ident) {
         return mSubType == NETWORK_TYPE_ALL
                 || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType);
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index b48bc90..81d4b9d 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -48,7 +48,6 @@
 import android.net.util.NetdService;
 import android.os.Binder;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -64,6 +63,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.net.module.util.NetdUtils;
 
 import libcore.io.IoUtils;
 
@@ -117,9 +117,6 @@
     /* Binder context for this service */
     private final Context mContext;
 
-    /* NetworkManager instance */
-    private final INetworkManagementService mNetworkManager;
-
     /**
      * The next non-repeating global ID for tracking resources between users, this service, and
      * kernel data structures. Accessing this variable is not thread safe, so it is only read or
@@ -1014,13 +1011,13 @@
      *
      * @param context Binder context for this service
      */
-    private IpSecService(Context context, INetworkManagementService networkManager) {
-        this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE);
+    private IpSecService(Context context) {
+        this(context, IpSecServiceConfiguration.GETSRVINSTANCE);
     }
 
-    static IpSecService create(Context context, INetworkManagementService networkManager)
+    static IpSecService create(Context context)
             throws InterruptedException {
-        final IpSecService service = new IpSecService(context, networkManager);
+        final IpSecService service = new IpSecService(context);
         service.connectNativeNetdService();
         return service;
     }
@@ -1034,11 +1031,9 @@
 
     /** @hide */
     @VisibleForTesting
-    public IpSecService(Context context, INetworkManagementService networkManager,
-            IpSecServiceConfiguration config) {
+    public IpSecService(Context context, IpSecServiceConfiguration config) {
         this(
                 context,
-                networkManager,
                 config,
                 (fd, uid) -> {
                     try {
@@ -1052,10 +1047,9 @@
 
     /** @hide */
     @VisibleForTesting
-    public IpSecService(Context context, INetworkManagementService networkManager,
-            IpSecServiceConfiguration config, UidFdTagger uidFdTagger) {
+    public IpSecService(Context context, IpSecServiceConfiguration config,
+            UidFdTagger uidFdTagger) {
         mContext = context;
-        mNetworkManager = Objects.requireNonNull(networkManager);
         mSrvConfig = config;
         mUidFdTagger = uidFdTagger;
     }
@@ -1335,7 +1329,7 @@
             netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
 
             Binder.withCleanCallingIdentity(() -> {
-                mNetworkManager.setInterfaceUp(intfName);
+                NetdUtils.setInterfaceUp(netd, intfName);
             });
 
             for (int selAddrFamily : ADDRESS_FAMILIES) {
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index bce8069..22ed781 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -40,6 +40,7 @@
     private static final int VERSION_ADD_NETWORK_ID = 3;
     private static final int VERSION_ADD_METERED = 4;
     private static final int VERSION_ADD_DEFAULT_NETWORK = 5;
+    private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6;
 
     public NetworkIdentitySet() {
     }
@@ -84,13 +85,20 @@
                 defaultNetwork = true;
             }
 
+            final int oemNetCapabilities;
+            if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) {
+                oemNetCapabilities = in.readInt();
+            } else {
+                oemNetCapabilities = NetworkIdentity.OEM_NONE;
+            }
+
             add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
-                    defaultNetwork));
+                    defaultNetwork, oemNetCapabilities));
         }
     }
 
     public void writeToStream(DataOutput out) throws IOException {
-        out.writeInt(VERSION_ADD_DEFAULT_NETWORK);
+        out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK);
         out.writeInt(size());
         for (NetworkIdentity ident : this) {
             out.writeInt(ident.getType());
@@ -100,6 +108,7 @@
             out.writeBoolean(ident.getRoaming());
             out.writeBoolean(ident.getMetered());
             out.writeBoolean(ident.getDefaultNetwork());
+            out.writeInt(ident.getOemManaged());
         }
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 9706bce..e0f5346 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -24,7 +24,6 @@
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
 import static android.net.NetworkStack.checkNetworkStackPermission;
@@ -45,6 +44,7 @@
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.TrafficStats.KB_IN_BYTES;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UNSUPPORTED;
@@ -97,7 +97,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkIdentity;
 import android.net.NetworkStack;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStats.NonMonotonicObserver;
 import android.net.NetworkStatsHistory;
@@ -296,7 +296,7 @@
     /** Last states of all networks sent from ConnectivityService. */
     @GuardedBy("mStatsLock")
     @Nullable
-    private NetworkState[] mLastNetworkStates = null;
+    private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null;
 
     private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
             new DropBoxNonMonotonicObserver();
@@ -378,8 +378,9 @@
                 }
                 case MSG_UPDATE_IFACES: {
                     // If no cached states, ignore.
-                    if (mLastNetworkStates == null) break;
-                    updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface);
+                    if (mLastNetworkStateSnapshots == null) break;
+                    // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing.
+                    updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
                     break;
                 }
                 case MSG_PERFORM_POLL_REGISTER_ALERT: {
@@ -967,10 +968,9 @@
         }
     }
 
-    @Override
     public void forceUpdateIfaces(
             Network[] defaultNetworks,
-            NetworkState[] networkStates,
+            NetworkStateSnapshot[] networkStates,
             String activeIface,
             UnderlyingNetworkInfo[] underlyingNetworkInfos) {
         checkNetworkStackPermission(mContext);
@@ -1248,13 +1248,13 @@
 
     private void updateIfaces(
             Network[] defaultNetworks,
-            NetworkState[] networkStates,
+            NetworkStateSnapshot[] snapshots,
             String activeIface) {
         synchronized (mStatsLock) {
             mWakeLock.acquire();
             try {
                 mActiveIface = activeIface;
-                updateIfacesLocked(defaultNetworks, networkStates);
+                updateIfacesLocked(defaultNetworks, snapshots);
             } finally {
                 mWakeLock.release();
             }
@@ -1262,13 +1262,13 @@
     }
 
     /**
-     * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link
-     * NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
+     * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to
+     * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
      * they are combined under a single {@link NetworkIdentitySet}.
      */
     @GuardedBy("mStatsLock")
-    private void updateIfacesLocked(@Nullable Network[] defaultNetworks,
-            @NonNull NetworkState[] states) {
+    private void updateIfacesLocked(@NonNull Network[] defaultNetworks,
+            @NonNull NetworkStateSnapshot[] snapshots) {
         if (!mSystemReady) return;
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
 
@@ -1283,26 +1283,24 @@
         // Rebuild active interfaces based on connected networks
         mActiveIfaces.clear();
         mActiveUidIfaces.clear();
-        if (defaultNetworks != null) {
-            // Caller is ConnectivityService. Update the list of default networks.
-            mDefaultNetworks = defaultNetworks;
-        }
+        // Update the list of default networks.
+        mDefaultNetworks = defaultNetworks;
 
-        mLastNetworkStates = states;
+        mLastNetworkStateSnapshots = snapshots;
 
         final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
         final ArraySet<String> mobileIfaces = new ArraySet<>();
-        for (NetworkState state : states) {
-            final boolean isMobile = isNetworkTypeMobile(state.legacyNetworkType);
-            final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
+        for (NetworkStateSnapshot snapshot : snapshots) {
+            final boolean isMobile = isNetworkTypeMobile(snapshot.legacyType);
+            final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network);
             final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
-                    : getSubTypeForState(state);
-            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+                    : getSubTypeForStateSnapshot(snapshot);
+            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
                     isDefault, subType);
 
             // Traffic occurring on the base interface is always counted for
             // both total usage and UID details.
-            final String baseIface = state.linkProperties.getInterfaceName();
+            final String baseIface = snapshot.linkProperties.getInterfaceName();
             if (baseIface != null) {
                 findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
                 findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
@@ -1312,14 +1310,14 @@
                 // If IMS is metered, then the IMS network usage has already included VT usage.
                 // VT is considered always metered in framework's layer. If VT is not metered
                 // per carrier's policy, modem will report 0 usage for VT calls.
-                if (state.networkCapabilities.hasCapability(
+                if (snapshot.networkCapabilities.hasCapability(
                         NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) {
 
                     // Copy the identify from IMS one but mark it as metered.
                     NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
                             ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
                             ident.getRoaming(), true /* metered */,
-                            true /* onDefaultNetwork */);
+                            true /* onDefaultNetwork */, ident.getOemManaged());
                     findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
                     findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
                 }
@@ -1358,7 +1356,7 @@
             // (or non eBPF offloaded) TX they would appear on both, however egress interface
             // accounting is explicitly bypassed for traffic from the clat uid.
             //
-            final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
+            final List<LinkProperties> stackedLinks = snapshot.linkProperties.getStackedLinks();
             for (LinkProperties stackedLink : stackedLinks) {
                 final String stackedIface = stackedLink.getInterfaceName();
                 if (stackedIface != null) {
@@ -1381,7 +1379,7 @@
      * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different
      * transport types do not actually fill this value.
      */
-    private int getSubTypeForState(@NonNull NetworkState state) {
+    private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) {
         if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
             return 0;
         }