Merge "BluetoothClass: Use mask to get MajorDeviceClass"
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 522add1..8b06ebe 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -19,7 +19,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.BitUtils;
+import java.util.BitSet;
 
 /**
  * Represents a core networking event defined in package android.net.metrics.
@@ -86,9 +86,7 @@
         if (ifname != null) {
             buffer.append(", ").append(ifname);
         }
-        for (int t : BitUtils.unpackBits(transports)) {
-            buffer.append(", ").append(NetworkCapabilities.transportNameOf(t));
-        }
+        buffer.append(", transports=").append(BitSet.valueOf(new long[] { transports }));
         buffer.append("): ").append(data.toString());
         return buffer.toString();
     }
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 0948a4da..efbfbf9 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -17,7 +17,6 @@
 package android.net;
 
 import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 
 import android.content.Context;
@@ -84,7 +83,7 @@
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder("{");
-        builder.append("type=").append(getNetworkTypeName(mType));
+        builder.append("type=").append(mType);
         builder.append(", subType=");
         if (mSubType == SUBTYPE_COMBINED) {
             builder.append("COMBINED");
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a643d09..f05f033 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -144,6 +144,8 @@
     public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby";
     /** @hide */
     public static final String FIREWALL_CHAIN_NAME_POWERSAVE = "powersave";
+    /** @hide */
+    public static final String FIREWALL_CHAIN_NAME_RESTRICTED = "restricted";
 
     private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
 
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index a17a498..14cb51c 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -63,7 +63,7 @@
 
     private final Messenger mMessenger;
     private final String mName;
-    private final ConnectivityManager mCm;
+    private final Context mContext;
 
     private int mProviderId = ID_NONE;
 
@@ -78,8 +78,6 @@
      */
     @SystemApi
     public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) {
-        mCm = ConnectivityManager.from(context);
-
         Handler handler = new Handler(looper) {
             @Override
             public void handleMessage(Message m) {
@@ -95,6 +93,7 @@
                 }
             }
         };
+        mContext = context;
         mMessenger = new Messenger(handler);
         mName = name;
     }
@@ -158,6 +157,6 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
     public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
-        mCm.declareNetworkRequestUnfulfillable(request);
+        ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request);
     }
 }
diff --git a/core/java/android/net/metrics/ConnectStats.java b/core/java/android/net/metrics/ConnectStats.java
index b320b75..c67259d 100644
--- a/core/java/android/net/metrics/ConnectStats.java
+++ b/core/java/android/net/metrics/ConnectStats.java
@@ -16,14 +16,14 @@
 
 package android.net.metrics;
 
-import android.net.NetworkCapabilities;
 import android.system.OsConstants;
 import android.util.IntArray;
 import android.util.SparseIntArray;
 
-import com.android.internal.util.BitUtils;
 import com.android.internal.util.TokenBucket;
 
+import java.util.BitSet;
+
 /**
  * A class that aggregates connect() statistics.
  * {@hide}
@@ -120,10 +120,9 @@
     @Override
     public String toString() {
         StringBuilder builder =
-                new StringBuilder("ConnectStats(").append("netId=").append(netId).append(", ");
-        for (int t : BitUtils.unpackBits(transports)) {
-            builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
-        }
+                new StringBuilder("ConnectStats(").append("netId=").append(netId)
+                        .append(", transports=").append(BitSet.valueOf(new long[] { transports }))
+                        .append(", ");
         builder.append(String.format("%d events, ", eventCount));
         builder.append(String.format("%d success, ", connectCount));
         builder.append(String.format("%d blocking, ", connectBlockingCount));
diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index 6f383b4..8988983 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -16,12 +16,7 @@
 
 package android.net.metrics;
 
-import static android.net.ConnectivityManager.NETID_UNSET;
-
-import android.net.NetworkCapabilities;
-
-import com.android.internal.util.BitUtils;
-
+import java.util.BitSet;
 import java.util.StringJoiner;
 
 /**
@@ -32,8 +27,8 @@
 
     // The creation time in milliseconds of this DefaultNetworkEvent.
     public final long creationTimeMs;
-    // The network ID of the network or NETID_UNSET if none.
-    public int netId = NETID_UNSET;
+    // The network ID of the network or 0 if none.
+    public int netId = 0;
     // The list of transport types, as defined in NetworkCapabilities.java.
     public int transports;
     // The list of transport types of the last previous default network.
@@ -63,9 +58,7 @@
     public String toString() {
         StringJoiner j = new StringJoiner(", ", "DefaultNetworkEvent(", ")");
         j.add("netId=" + netId);
-        for (int t : BitUtils.unpackBits(transports)) {
-            j.add(NetworkCapabilities.transportNameOf(t));
-        }
+        j.add("transports=" + BitSet.valueOf(new long[] { transports }));
         j.add("ip=" + ipSupport());
         if (initialScore > 0) {
             j.add("initial_score=" + initialScore);
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index 5aa705b..bf351ce 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -16,11 +16,8 @@
 
 package android.net.metrics;
 
-import android.net.NetworkCapabilities;
-
-import com.android.internal.util.BitUtils;
-
 import java.util.Arrays;
+import java.util.BitSet;
 
 /**
  * A batch of DNS events recorded by NetdEventListenerService for a specific network.
@@ -86,10 +83,10 @@
     @Override
     public String toString() {
         StringBuilder builder =
-                new StringBuilder("DnsEvent(").append("netId=").append(netId).append(", ");
-        for (int t : BitUtils.unpackBits(transports)) {
-            builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
-        }
+                new StringBuilder("DnsEvent(").append("netId=").append(netId)
+                        .append(", transports=")
+                        .append(BitSet.valueOf(new long[] { transports }))
+                        .append(", ");
         builder.append(String.format("%d events, ", eventCount));
         builder.append(String.format("%d success)", successCount));
         return builder.toString();
diff --git a/core/java/android/net/metrics/NetworkMetrics.java b/core/java/android/net/metrics/NetworkMetrics.java
index 66d92c4..8f2f612 100644
--- a/core/java/android/net/metrics/NetworkMetrics.java
+++ b/core/java/android/net/metrics/NetworkMetrics.java
@@ -16,11 +16,9 @@
 
 package android.net.metrics;
 
-import android.net.NetworkCapabilities;
-
-import com.android.internal.util.BitUtils;
 import com.android.internal.util.TokenBucket;
 
+import java.util.BitSet;
 import java.util.StringJoiner;
 
 /**
@@ -144,9 +142,7 @@
         public String toString() {
             StringJoiner j = new StringJoiner(", ", "{", "}");
             j.add("netId=" + netId);
-            for (int t : BitUtils.unpackBits(transports)) {
-                j.add(NetworkCapabilities.transportNameOf(t));
-            }
+            j.add("transports=" + BitSet.valueOf(new long[] { transports }));
             j.add(String.format("dns avg=%dms max=%dms err=%.1f%% tot=%d",
                     (int) dnsLatencies.average(), (int) dnsLatencies.max,
                     100 * dnsErrorRate.average(), dnsErrorRate.count));
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9b006d0..e0a484f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -171,7 +171,6 @@
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.Pair;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.Xml;
@@ -1973,7 +1972,7 @@
     private void registerNetdEventCallback() {
         final IIpConnectivityMetrics ipConnectivityMetrics = mDeps.getIpConnectivityMetrics();
         if (ipConnectivityMetrics == null) {
-            Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
+            Log.wtf(TAG, "Missing IIpConnectivityMetrics");
             return;
         }
 
@@ -2439,7 +2438,7 @@
             if (VDBG || DDBG) log("Setting MTU size: " + iface + ", " + mtu);
             mNetd.interfaceSetMtu(iface, mtu);
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "exception in interfaceSetMtu()" + e);
+            loge("exception in interfaceSetMtu()" + e);
         }
     }
 
@@ -2461,7 +2460,7 @@
         if (tcpBufferSizes.equals(mCurrentTcpBufferSizes)) return;
 
         try {
-            if (VDBG || DDBG) Slog.d(TAG, "Setting tx/rx TCP buffers to " + tcpBufferSizes);
+            if (VDBG || DDBG) log("Setting tx/rx TCP buffers to " + tcpBufferSizes);
 
             String rmemValues = String.join(" ", values[0], values[1], values[2]);
             String wmemValues = String.join(" ", values[3], values[4], values[5]);
@@ -2762,7 +2761,7 @@
                 case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
                     NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
                     if (networkCapabilities.hasConnectivityManagedCapability()) {
-                        Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
+                        Log.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
                     }
                     if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
                         // Make sure the original object is not mutated. NetworkAgent normally
@@ -3067,7 +3066,7 @@
             // Legacy version of notifyNetworkTestedWithExtras.
             // Would only be called if the system has a NetworkStack module older than the
             // framework, which does not happen in practice.
-            Slog.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
+            Log.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
         }
 
         @Override
@@ -3544,7 +3543,7 @@
                 numRequests = nai.numForegroundNetworkRequests();
                 break;
             default:
-                Slog.wtf(TAG, "Invalid reason. Cannot happen.");
+                Log.wtf(TAG, "Invalid reason. Cannot happen.");
                 return true;
         }
 
@@ -3706,7 +3705,7 @@
         synchronized (mUidToNetworkRequestCount) {
             final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
             if (requests < 1) {
-                Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
+                Log.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
             } else if (requests == 1) {
                 mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
             } else {
@@ -3751,7 +3750,7 @@
         }
 
         if (!nai.networkAgentConfig.explicitlySelected) {
-            Slog.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network");
+            Log.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network");
         }
 
         if (accept != nai.networkAgentConfig.acceptUnvalidated) {
@@ -4021,7 +4020,7 @@
                 highPriority = nai.networkAgentConfig.explicitlySelected;
                 break;
             default:
-                Slog.wtf(TAG, "Unknown notification type " + type);
+                Log.wtf(TAG, "Unknown notification type " + type);
                 return;
         }
 
@@ -4343,7 +4342,7 @@
         synchronized (this) {
             if (!mNetTransitionWakeLock.isHeld()) {
                 mWakelockLogs.log(String.format("RELEASE: already released (%s)", event));
-                Slog.w(TAG, "expected Net Transition WakeLock to be held");
+                Log.w(TAG, "expected Net Transition WakeLock to be held");
                 return;
             }
             mNetTransitionWakeLock.release();
@@ -4515,7 +4514,7 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            Slog.wtf(TAG, "Should never be reached.");
+            Log.wtf(TAG, "Should never be reached.");
         }
 
         @Override
@@ -4530,15 +4529,19 @@
     }
 
     private static void log(String s) {
-        Slog.d(TAG, s);
+        Log.d(TAG, s);
+    }
+
+    private static void logw(String s) {
+        Log.w(TAG, s);
     }
 
     private static void loge(String s) {
-        Slog.e(TAG, s);
+        Log.e(TAG, s);
     }
 
     private static void loge(String s, Throwable t) {
-        Slog.e(TAG, s, t);
+        Log.e(TAG, s, t);
     }
 
     /**
@@ -4825,7 +4828,7 @@
     @Override
     public boolean updateLockdownVpn() {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-            Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM");
+            logw("Lockdown VPN only available to AID_SYSTEM");
             return false;
         }
 
@@ -4835,21 +4838,21 @@
             if (mLockdownEnabled) {
                 byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
                 if (profileTag == null) {
-                    Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore");
+                    loge("Lockdown VPN configured but cannot be read from keystore");
                     return false;
                 }
                 String profileName = new String(profileTag);
                 final VpnProfile profile = VpnProfile.decode(
                         profileName, mKeyStore.get(Credentials.VPN + profileName));
                 if (profile == null) {
-                    Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName);
+                    loge("Lockdown VPN configured invalid profile " + profileName);
                     setLockdownTracker(null);
                     return true;
                 }
                 int user = UserHandle.getUserId(Binder.getCallingUid());
                 Vpn vpn = mVpns.get(user);
                 if (vpn == null) {
-                    Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
+                    logw("VPN for user " + user + " not ready yet. Skipping lockdown");
                     return false;
                 }
                 setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
@@ -4909,7 +4912,7 @@
             if (vpn == null) {
                 // Shouldn't happen as all code paths that point here should have checked the Vpn
                 // exists already.
-                Slog.wtf(TAG, "User " + userId + " has no Vpn configuration");
+                Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
                 return false;
             }
 
@@ -4925,7 +4928,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
             return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
@@ -4946,7 +4949,7 @@
 
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
             if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist, mKeyStore)) {
@@ -4968,7 +4971,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return null;
             }
             return vpn.getAlwaysOnPackage();
@@ -4983,7 +4986,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
             return vpn.getLockdown();
@@ -4998,7 +5001,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return null;
             }
             return vpn.getLockdownAllowlist();
@@ -5183,7 +5186,7 @@
 
     private void onPackageReplaced(String packageName, int uid) {
         if (TextUtils.isEmpty(packageName) || uid < 0) {
-            Slog.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
+            Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
             return;
         }
         final int userId = UserHandle.getUserId(uid);
@@ -5194,7 +5197,7 @@
             }
             // Legacy always-on VPN won't be affected since the package name is not set.
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
-                Slog.d(TAG, "Restarting always-on VPN package " + packageName + " for user "
+                log("Restarting always-on VPN package " + packageName + " for user "
                         + userId);
                 vpn.startAlwaysOnVpn(mKeyStore);
             }
@@ -5203,7 +5206,7 @@
 
     private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
         if (TextUtils.isEmpty(packageName) || uid < 0) {
-            Slog.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
+            Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
             return;
         }
 
@@ -5215,7 +5218,7 @@
             }
             // Legacy always-on VPN won't be affected since the package name is not set.
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
-                Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user "
+                log("Removing always-on VPN package " + packageName + " for user "
                         + userId);
                 vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
             }
@@ -5831,7 +5834,7 @@
             // Avoid creating duplicates. even if an app makes a direct AIDL call.
             // This will never happen if an app calls ConnectivityManager#registerNetworkProvider,
             // as that will throw if a duplicate provider is registered.
-            Slog.e(TAG, "Attempt to register existing NetworkProviderInfo "
+            loge("Attempt to register existing NetworkProviderInfo "
                     + mNetworkProviderInfos.get(npi.messenger).name);
             return;
         }
@@ -6441,7 +6444,7 @@
             // stop being matched by the updated agent.
             String diff = nai.networkCapabilities.describeImmutableDifferences(nc);
             if (!TextUtils.isEmpty(diff)) {
-                Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
+                Log.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
             }
         }
 
@@ -7001,7 +7004,7 @@
             }
             newSatisfier.unlingerRequest(nri.request);
             if (!newSatisfier.addRequest(nri.request)) {
-                Slog.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
+                Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
                         + nri.request);
             }
         } else {
@@ -7349,7 +7352,7 @@
             networkAgent.everConnected = true;
 
             if (networkAgent.linkProperties == null) {
-                Slog.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
+                Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
             }
 
             // NetworkCapabilities need to be set before sending the private DNS config to
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1c99465..821a967 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -24,12 +24,14 @@
 import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
 import static android.net.INetd.FIREWALL_CHAIN_NONE;
 import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
 import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
 import static android.net.INetd.FIREWALL_DENYLIST;
 import static android.net.INetd.FIREWALL_RULE_ALLOW;
 import static android.net.INetd.FIREWALL_RULE_DENY;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkStats.SET_DEFAULT;
@@ -88,7 +90,6 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
@@ -122,7 +123,7 @@
      * Helper class that encapsulates NetworkManagementService dependencies and makes them
      * easier to mock in unit tests.
      */
-    static class SystemServices {
+    static class Dependencies {
         public IBinder getService(String name) {
             return ServiceManager.getService(name);
         }
@@ -132,6 +133,10 @@
         public INetd getNetd() {
             return NetdService.get();
         }
+
+        public int getCallingUid() {
+            return Binder.getCallingUid();
+        }
     }
 
     private static final String TAG = "NetworkManagement";
@@ -157,7 +162,7 @@
 
     private final Handler mDaemonHandler;
 
-    private final SystemServices mServices;
+    private final Dependencies mDeps;
 
     private INetd mNetdService;
 
@@ -215,6 +220,11 @@
      */
     @GuardedBy("mRulesLock")
     private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
+    /**
+     * Contains the per-UID firewall rules that are used when Restricted Networking Mode is enabled.
+     */
+    @GuardedBy("mRulesLock")
+    private SparseIntArray mUidFirewallRestrictedRules = new SparseIntArray();
     /** Set of states for the child firewall chains. True if the chain is active. */
     @GuardedBy("mRulesLock")
     final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -254,33 +264,32 @@
      * @param context  Binder context for this service
      */
     private NetworkManagementService(
-            Context context, SystemServices services) {
+            Context context, Dependencies deps) {
         mContext = context;
-        mServices = services;
+        mDeps = deps;
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
         mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
 
-        mServices.registerLocalService(new LocalService());
+        mDeps.registerLocalService(new LocalService());
 
         synchronized (mTetheringStatsProviders) {
             mTetheringStatsProviders.put(new NetdTetheringStatsProvider(), "netd");
         }
     }
 
-    @VisibleForTesting
-    NetworkManagementService() {
+    private NetworkManagementService() {
         mContext = null;
         mDaemonHandler = null;
-        mServices = null;
+        mDeps = null;
         mNetdUnsolicitedEventListener = null;
     }
 
-    static NetworkManagementService create(Context context, SystemServices services)
+    static NetworkManagementService create(Context context, Dependencies deps)
             throws InterruptedException {
         final NetworkManagementService service =
-                new NetworkManagementService(context, services);
+                new NetworkManagementService(context, deps);
         if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
         if (DBG) Slog.d(TAG, "Connecting native netd service");
         service.connectNativeNetdService();
@@ -289,7 +298,7 @@
     }
 
     public static NetworkManagementService create(Context context) throws InterruptedException {
-        return create(context, new SystemServices());
+        return create(context, new Dependencies());
     }
 
     public void systemReady() {
@@ -310,7 +319,7 @@
                 return mBatteryStats;
             }
             mBatteryStats =
-                    IBatteryStats.Stub.asInterface(mServices.getService(BatteryStats.SERVICE_NAME));
+                    IBatteryStats.Stub.asInterface(mDeps.getService(BatteryStats.SERVICE_NAME));
             return mBatteryStats;
         }
     }
@@ -511,7 +520,7 @@
     }
 
     private void connectNativeNetdService() {
-        mNetdService = mServices.getNetd();
+        mNetdService = mDeps.getNetd();
         try {
             mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener);
             if (DBG) Slog.d(TAG, "Register unsolicited event listener");
@@ -602,9 +611,15 @@
             syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, "standby ");
             syncFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, "dozable ");
             syncFirewallChainLocked(FIREWALL_CHAIN_POWERSAVE, "powersave ");
+            syncFirewallChainLocked(FIREWALL_CHAIN_RESTRICTED, "restricted ");
 
-            final int[] chains =
-                    {FIREWALL_CHAIN_STANDBY, FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_POWERSAVE};
+            final int[] chains = {
+                    FIREWALL_CHAIN_STANDBY,
+                    FIREWALL_CHAIN_DOZABLE,
+                    FIREWALL_CHAIN_POWERSAVE,
+                    FIREWALL_CHAIN_RESTRICTED
+            };
+
             for (int chain : chains) {
                 if (getFirewallChainState(chain)) {
                     setFirewallChainEnabled(chain, true);
@@ -1437,7 +1452,7 @@
 
     @Override
     public void setUidCleartextNetworkPolicy(int uid, int policy) {
-        if (Binder.getCallingUid() != uid) {
+        if (mDeps.getCallingUid() != uid) {
             NetworkStack.checkNetworkStackPermission(mContext);
         }
 
@@ -1695,6 +1710,8 @@
                 return FIREWALL_CHAIN_NAME_DOZABLE;
             case FIREWALL_CHAIN_POWERSAVE:
                 return FIREWALL_CHAIN_NAME_POWERSAVE;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return FIREWALL_CHAIN_NAME_RESTRICTED;
             default:
                 throw new IllegalArgumentException("Bad child chain: " + chain);
         }
@@ -1708,6 +1725,8 @@
                 return FIREWALL_ALLOWLIST;
             case FIREWALL_CHAIN_POWERSAVE:
                 return FIREWALL_ALLOWLIST;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return FIREWALL_ALLOWLIST;
             default:
                 return isFirewallEnabled() ? FIREWALL_ALLOWLIST : FIREWALL_DENYLIST;
         }
@@ -1752,6 +1771,9 @@
                     case FIREWALL_CHAIN_POWERSAVE:
                         mNetdService.firewallReplaceUidChain("fw_powersave", true, uids);
                         break;
+                    case FIREWALL_CHAIN_RESTRICTED:
+                        mNetdService.firewallReplaceUidChain("fw_restricted", true, uids);
+                        break;
                     case FIREWALL_CHAIN_NONE:
                     default:
                         Slog.d(TAG, "setFirewallUidRules() called on invalid chain: " + chain);
@@ -1836,6 +1858,8 @@
                 return mUidFirewallDozableRules;
             case FIREWALL_CHAIN_POWERSAVE:
                 return mUidFirewallPowerSaveRules;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return mUidFirewallRestrictedRules;
             case FIREWALL_CHAIN_NONE:
                 return mUidFirewallRules;
             default:
@@ -1851,8 +1875,8 @@
         return rule;
     }
 
-    private static void enforceSystemUid() {
-        final int uid = Binder.getCallingUid();
+    private void enforceSystemUid() {
+        final int uid = mDeps.getCallingUid();
         if (uid != Process.SYSTEM_UID) {
             throw new SecurityException("Only available to AID_SYSTEM");
         }
@@ -1910,17 +1934,22 @@
         synchronized (mRulesLock) {
             dumpUidFirewallRule(pw, "", mUidFirewallRules);
 
-            pw.print("UID firewall standby chain enabled: "); pw.println(
-                    getFirewallChainState(FIREWALL_CHAIN_STANDBY));
+            pw.print("UID firewall standby chain enabled: ");
+            pw.println(getFirewallChainState(FIREWALL_CHAIN_STANDBY));
             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
 
-            pw.print("UID firewall dozable chain enabled: "); pw.println(
-                    getFirewallChainState(FIREWALL_CHAIN_DOZABLE));
+            pw.print("UID firewall dozable chain enabled: ");
+            pw.println(getFirewallChainState(FIREWALL_CHAIN_DOZABLE));
             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
 
-            pw.println("UID firewall powersave chain enabled: " +
-                    getFirewallChainState(FIREWALL_CHAIN_POWERSAVE));
+            pw.print("UID firewall powersave chain enabled: ");
+            pw.println(getFirewallChainState(FIREWALL_CHAIN_POWERSAVE));
             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
+
+            pw.print("UID firewall restricted mode chain enabled: ");
+            pw.println(getFirewallChainState(FIREWALL_CHAIN_RESTRICTED));
+            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_RESTRICTED,
+                    mUidFirewallRestrictedRules);
         }
 
         synchronized (mIdleTimerLock) {
@@ -2071,6 +2100,11 @@
                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of power saver mode");
                 return true;
             }
+            if (getFirewallChainState(FIREWALL_CHAIN_RESTRICTED)
+                    && mUidFirewallRestrictedRules.get(uid) != FIREWALL_RULE_ALLOW) {
+                if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of restricted mode");
+                return true;
+            }
             if (mUidRejectOnMetered.get(uid)) {
                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data"
                         + " in the background");
@@ -2096,60 +2130,10 @@
         }
     }
 
-    @VisibleForTesting
-    class LocalService extends NetworkManagementInternal {
+    private class LocalService extends NetworkManagementInternal {
         @Override
         public boolean isNetworkRestrictedForUid(int uid) {
             return isNetworkRestrictedInternal(uid);
         }
     }
-
-    @VisibleForTesting
-    Injector getInjector() {
-        return new Injector();
-    }
-
-    @VisibleForTesting
-    class Injector {
-        void setDataSaverMode(boolean dataSaverMode) {
-            mDataSaverMode = dataSaverMode;
-        }
-
-        void setFirewallChainState(int chain, boolean state) {
-            NetworkManagementService.this.setFirewallChainState(chain, state);
-        }
-
-        void setFirewallRule(int chain, int uid, int rule) {
-            synchronized (mRulesLock) {
-                getUidFirewallRulesLR(chain).put(uid, rule);
-            }
-        }
-
-        void setUidOnMeteredNetworkList(boolean denylist, int uid, boolean enable) {
-            synchronized (mRulesLock) {
-                if (denylist) {
-                    mUidRejectOnMetered.put(uid, enable);
-                } else {
-                    mUidAllowOnMetered.put(uid, enable);
-                }
-            }
-        }
-
-        void reset() {
-            synchronized (mRulesLock) {
-                setDataSaverMode(false);
-                final int[] chains = {
-                        FIREWALL_CHAIN_DOZABLE,
-                        FIREWALL_CHAIN_STANDBY,
-                        FIREWALL_CHAIN_POWERSAVE
-                };
-                for (int chain : chains) {
-                    setFirewallChainState(chain, false);
-                    getUidFirewallRulesLR(chain).clear();
-                }
-                mUidAllowOnMetered.clear();
-                mUidRejectOnMetered.clear();
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index c789186..1f0fb5e 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -45,8 +45,8 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.Log;
 import android.util.Pair;
-import android.util.Slog;
 
 import java.net.InetAddress;
 import java.util.Arrays;
@@ -279,7 +279,7 @@
     }
 
     public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
-        Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
+        Log.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
         return (cfg != null)
                 ? mPrivateDnsMap.put(network.netId, cfg)
                 : mPrivateDnsMap.remove(network.netId);
@@ -389,7 +389,7 @@
             mPrivateDnsValidationMap.remove(netId);
         }
 
-        Slog.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
+        Log.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
                 + "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers),
                 Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds,
                 paramsParcel.successThreshold, paramsParcel.minSamples,
@@ -400,7 +400,7 @@
         try {
             mDnsResolver.setResolverConfiguration(paramsParcel);
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error setting DNS configuration: " + e);
+            Log.e(TAG, "Error setting DNS configuration: " + e);
             return;
         }
     }
@@ -431,8 +431,8 @@
                 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
                 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
         if (mSampleValidity < 0 || mSampleValidity > 65535) {
-            Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
-                    DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
+            Log.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default="
+                    + DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
             mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
         }
 
@@ -440,17 +440,17 @@
                 DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
                 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
         if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
-            Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
-                    DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
+            Log.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default="
+                    + DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
             mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
         }
 
         mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
         mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
         if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
-            Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
-                    "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
-                    DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
+            Log.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples
+                    + "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", "
+                    + DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
             mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
             mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
         }
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 17828a0..21ef356 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -60,8 +60,8 @@
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.util.DebugUtils;
+import android.util.Log;
 import android.util.Range;
-import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -230,7 +230,7 @@
             mUsageCallback = new UsageCallback() {
                 @Override
                 public void onThresholdReached(int networkType, String subscriberId) {
-                    if (DBG) Slog.d(TAG, "onThresholdReached for network " + network);
+                    if (DBG) Log.d(TAG, "onThresholdReached for network " + network);
                     mMultipathBudget = 0;
                     updateMultipathBudget();
                 }
@@ -252,7 +252,7 @@
             final long bytes = getNetworkTotalBytes(
                     start.toInstant().toEpochMilli(),
                     end.toInstant().toEpochMilli());
-            if (DBG) Slog.d(TAG, "Non-default data usage: " + bytes);
+            if (DBG) Log.d(TAG, "Non-default data usage: " + bytes);
             return bytes;
         }
 
@@ -261,7 +261,7 @@
                 return LocalServices.getService(NetworkStatsManagerInternal.class)
                         .getNetworkTotalBytes(mNetworkTemplate, start, end);
             } catch (RuntimeException e) {
-                Slog.w(TAG, "Failed to get data usage: " + e);
+                Log.w(TAG, "Failed to get data usage: " + e);
                 return -1;
             }
         }
@@ -326,17 +326,17 @@
         void updateMultipathBudget() {
             long quota = LocalServices.getService(NetworkPolicyManagerInternal.class)
                     .getSubscriptionOpportunisticQuota(this.network, QUOTA_TYPE_MULTIPATH);
-            if (DBG) Slog.d(TAG, "Opportunistic quota from data plan: " + quota + " bytes");
+            if (DBG) Log.d(TAG, "Opportunistic quota from data plan: " + quota + " bytes");
 
             // Fallback to user settings-based quota if not available from phone plan
             if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
                 quota = getUserPolicyOpportunisticQuotaBytes();
-                if (DBG) Slog.d(TAG, "Opportunistic quota from user policy: " + quota + " bytes");
+                if (DBG) Log.d(TAG, "Opportunistic quota from user policy: " + quota + " bytes");
             }
 
             if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
                 quota = getDefaultDailyMultipathQuotaBytes();
-                if (DBG) Slog.d(TAG, "Setting quota: " + quota + " bytes");
+                if (DBG) Log.d(TAG, "Setting quota: " + quota + " bytes");
             }
 
             // TODO: re-register if day changed: budget may have run out but should be refreshed.
@@ -344,7 +344,7 @@
                 // If there is already a usage callback pending , there's no need to re-register it
                 // if the quota hasn't changed. The callback will simply fire as expected when the
                 // budget is spent.
-                if (DBG) Slog.d(TAG, "Quota still " + quota + ", not updating.");
+                if (DBG) Log.d(TAG, "Quota still " + quota + ", not updating.");
                 return;
             }
             mQuota = quota;
@@ -364,8 +364,9 @@
             // since last time, so even if this is called very often the budget will not snap to 0
             // as soon as there are less than 2MB left for today.
             if (budget > NetworkStatsManager.MIN_THRESHOLD_BYTES) {
-                if (DBG) Slog.d(TAG, "Setting callback for " + budget +
-                        " bytes on network " + network);
+                if (DBG) {
+                    Log.d(TAG, "Setting callback for " + budget + " bytes on network " + network);
+                }
                 registerUsageCallback(budget);
             } else {
                 maybeUnregisterUsageCallback();
@@ -402,7 +403,7 @@
 
         private void maybeUnregisterUsageCallback() {
             if (haveMultipathBudget()) {
-                if (DBG) Slog.d(TAG, "Unregistering callback, budget was " + mMultipathBudget);
+                if (DBG) Log.d(TAG, "Unregistering callback, budget was " + mMultipathBudget);
                 mStatsManager.unregisterUsageCallback(mUsageCallback);
                 mMultipathBudget = 0;
             }
@@ -467,9 +468,9 @@
                 try {
                     mMultipathTrackers.put(network, new MultipathTracker(network, nc));
                 } catch (IllegalStateException e) {
-                    Slog.e(TAG, "Can't track mobile network " + network + ": " + e.getMessage());
+                    Log.e(TAG, "Can't track mobile network " + network + ": " + e.getMessage());
                 }
-                if (DBG) Slog.d(TAG, "Tracking mobile network " + network);
+                if (DBG) Log.d(TAG, "Tracking mobile network " + network);
             }
 
             @Override
@@ -479,7 +480,7 @@
                     existing.shutdown();
                     mMultipathTrackers.remove(network);
                 }
-                if (DBG) Slog.d(TAG, "No longer tracking mobile network " + network);
+                if (DBG) Log.d(TAG, "No longer tracking mobile network " + network);
             }
         };
 
@@ -524,16 +525,16 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            Slog.wtf(TAG, "Should never be reached.");
+            Log.wtf(TAG, "Should never be reached.");
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (!Settings.Global.getUriFor(NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES)
                     .equals(uri)) {
-                Slog.wtf(TAG, "Unexpected settings observation: " + uri);
+                Log.wtf(TAG, "Unexpected settings observation: " + uri);
             }
-            if (DBG) Slog.d(TAG, "Settings change: updating budgets.");
+            if (DBG) Log.d(TAG, "Settings change: updating budgets.");
             updateAllMultipathBudgets();
         }
     }
@@ -541,7 +542,7 @@
     private final class ConfigChangeReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (DBG) Slog.d(TAG, "Configuration change: updating budgets.");
+            if (DBG) Log.d(TAG, "Configuration change: updating budgets.");
             updateAllMultipathBudgets();
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 163788f..d9c2e80 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -30,7 +30,7 @@
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -176,7 +176,7 @@
         try {
             mNMService.registerObserver(this);
         } catch (RemoteException e) {
-            Slog.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
+            Log.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
             return;
         }
 
@@ -185,7 +185,7 @@
         try {
             addrStr = mNetd.clatdStart(baseIface, mNat64PrefixInUse.toString());
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
+            Log.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
         }
         mIface = CLAT_PREFIX + baseIface;
         mBaseIface = baseIface;
@@ -193,7 +193,7 @@
         try {
             mIPv6Address = (Inet6Address) InetAddresses.parseNumericAddress(addrStr);
         } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
-            Slog.e(TAG, "Invalid IPv6 address " + addrStr);
+            Log.e(TAG, "Invalid IPv6 address " + addrStr);
         }
         if (mPrefixDiscoveryRunning && !isPrefixDiscoveryNeeded()) {
             stopPrefixDiscovery();
@@ -218,7 +218,7 @@
         try {
             mNMService.unregisterObserver(this);
         } catch (RemoteException | IllegalStateException e) {
-            Slog.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
+            Log.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
         }
         mNat64PrefixInUse = null;
         mIface = null;
@@ -242,37 +242,37 @@
     @VisibleForTesting
     protected void start() {
         if (isStarted()) {
-            Slog.e(TAG, "startClat: already started");
+            Log.e(TAG, "startClat: already started");
             return;
         }
 
         if (mNetwork.linkProperties == null) {
-            Slog.e(TAG, "startClat: Can't start clat with null LinkProperties");
+            Log.e(TAG, "startClat: Can't start clat with null LinkProperties");
             return;
         }
 
         String baseIface = mNetwork.linkProperties.getInterfaceName();
         if (baseIface == null) {
-            Slog.e(TAG, "startClat: Can't start clat on null interface");
+            Log.e(TAG, "startClat: Can't start clat on null interface");
             return;
         }
         // TODO: should we only do this if mNetd.clatdStart() succeeds?
-        Slog.i(TAG, "Starting clatd on " + baseIface);
+        Log.i(TAG, "Starting clatd on " + baseIface);
         enterStartingState(baseIface);
     }
 
     @VisibleForTesting
     protected void stop() {
         if (!isStarted()) {
-            Slog.e(TAG, "stopClat: already stopped");
+            Log.e(TAG, "stopClat: already stopped");
             return;
         }
 
-        Slog.i(TAG, "Stopping clatd on " + mBaseIface);
+        Log.i(TAG, "Stopping clatd on " + mBaseIface);
         try {
             mNetd.clatdStop(mBaseIface);
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error stopping clatd on " + mBaseIface + ": " + e);
+            Log.e(TAG, "Error stopping clatd on " + mBaseIface + ": " + e);
         }
 
         String iface = mIface;
@@ -294,7 +294,7 @@
         try {
             mDnsResolver.startPrefix64Discovery(getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
+            Log.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
         }
         mPrefixDiscoveryRunning = true;
     }
@@ -303,7 +303,7 @@
         try {
             mDnsResolver.stopPrefix64Discovery(getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
+            Log.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
         }
         mPrefixDiscoveryRunning = false;
     }
@@ -320,7 +320,7 @@
         try {
             mDnsResolver.setPrefix64(getNetId(), prefixString);
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to "
+            Log.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to "
                     + prefix + ": " + e);
         }
     }
@@ -328,7 +328,7 @@
     private void maybeHandleNat64PrefixChange() {
         final IpPrefix newPrefix = selectNat64Prefix();
         if (!Objects.equals(mNat64PrefixInUse, newPrefix)) {
-            Slog.d(TAG, "NAT64 prefix changed from " + mNat64PrefixInUse + " to "
+            Log.d(TAG, "NAT64 prefix changed from " + mNat64PrefixInUse + " to "
                     + newPrefix);
             stop();
             // It's safe to call update here, even though this method is called from update, because
@@ -418,7 +418,7 @@
             return;
         }
 
-        Slog.d(TAG, "clatd running, updating NAI for " + mIface);
+        Log.d(TAG, "clatd running, updating NAI for " + mIface);
         for (LinkProperties stacked: oldLp.getStackedLinks()) {
             if (Objects.equals(mIface, stacked.getInterfaceName())) {
                 lp.addStackedLink(stacked);
@@ -451,7 +451,7 @@
             return new LinkAddress(
                     InetAddresses.parseNumericAddress(config.ipv4Addr), config.prefixLength);
         } catch (IllegalArgumentException | RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error getting link properties: " + e);
+            Log.e(TAG, "Error getting link properties: " + e);
             return null;
         }
     }
@@ -480,11 +480,11 @@
 
         LinkAddress clatAddress = getLinkAddress(iface);
         if (clatAddress == null) {
-            Slog.e(TAG, "clatAddress was null for stacked iface " + iface);
+            Log.e(TAG, "clatAddress was null for stacked iface " + iface);
             return;
         }
 
-        Slog.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
+        Log.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
                 mIface, mIface, mBaseIface));
         enterRunningState();
         LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
@@ -503,7 +503,7 @@
             return;
         }
 
-        Slog.i(TAG, "interface " + iface + " removed");
+        Log.i(TAG, "interface " + iface + " removed");
         // If we're running, and the interface was removed, then we didn't call stop(), and it's
         // likely that clatd crashed. Ensure we call stop() so we can start clatd again. Calling
         // stop() will also update LinkProperties, and if clatd crashed, the LinkProperties update
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 7f4fb40..7795ed3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -35,7 +35,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.Slog;
+import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.widget.Toast;
@@ -175,7 +175,7 @@
         final int previousEventId = mNotificationTypeMap.get(id);
         final NotificationType previousNotifyType = NotificationType.getFromId(previousEventId);
         if (priority(previousNotifyType) > priority(notifyType)) {
-            Slog.d(TAG, String.format(
+            Log.d(TAG, String.format(
                     "ignoring notification %s for network %s with existing notification %s",
                     notifyType, id, previousNotifyType));
             return;
@@ -183,7 +183,7 @@
         clearNotification(id);
 
         if (DBG) {
-            Slog.d(TAG, String.format(
+            Log.d(TAG, String.format(
                     "showNotification tag=%s event=%s transport=%s name=%s highPriority=%s",
                     tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
         }
@@ -253,7 +253,7 @@
             // are sent, but they are not implemented yet.
             return;
         } else {
-            Slog.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
+            Log.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
                     + getTransportName(transportType));
             return;
         }
@@ -294,7 +294,7 @@
         try {
             mNotificationManager.notify(tag, eventId, notification);
         } catch (NullPointerException npe) {
-            Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
+            Log.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
         }
     }
 
@@ -317,13 +317,13 @@
         final String tag = tagFor(id);
         final int eventId = mNotificationTypeMap.get(id);
         if (DBG) {
-            Slog.d(TAG, String.format("clearing notification tag=%s event=%s", tag,
+            Log.d(TAG, String.format("clearing notification tag=%s event=%s", tag,
                    nameOf(eventId)));
         }
         try {
             mNotificationManager.cancel(tag, eventId);
         } catch (NullPointerException npe) {
-            Slog.d(TAG, String.format(
+            Log.d(TAG, String.format(
                     "failed to clear notification tag=%s event=%s", tag, nameOf(eventId)), npe);
         }
         mNotificationTypeMap.delete(id);
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index 26cc3ee..5cb3d94 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -35,7 +35,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -168,7 +168,7 @@
                 proxyProperties = new ProxyInfo(host, port, exclList);
             }
             if (!proxyProperties.isValid()) {
-                if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
+                if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
                 return;
             }
 
@@ -223,7 +223,7 @@
         if (mPacManager.setCurrentProxyScriptUrl(proxyInfo) == PacManager.DONT_SEND_BROADCAST) {
             return;
         }
-        if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
+        if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -255,7 +255,7 @@
             if (proxyInfo != null && (!TextUtils.isEmpty(proxyInfo.getHost()) ||
                     !Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))) {
                 if (!proxyInfo.isValid()) {
-                    if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+                    if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
                     return;
                 }
                 mGlobalProxy = new ProxyInfo(proxyInfo);
@@ -296,7 +296,7 @@
         synchronized (mProxyLock) {
             if (Objects.equals(mDefaultProxy, proxyInfo)) return;
             if (proxyInfo != null &&  !proxyInfo.isValid()) {
-                if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+                if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
                 return;
             }
 
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 64c3c28..ea1d8da 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -37,7 +37,7 @@
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.TextUtils;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -128,7 +128,7 @@
         final int egressType = (egressInfo == null) ? TYPE_NONE : egressInfo.getType();
         final String egressIface = (egressProp == null) ?
                 null : egressProp.getInterfaceName();
-        Slog.d(TAG, "handleStateChanged: egress=" + egressType
+        Log.d(TAG, "handleStateChanged: egress=" + egressType
                 + " " + mAcceptedEgressIface + "->" + egressIface);
 
         if (egressDisconnected || egressChanged) {
@@ -149,7 +149,7 @@
 
         } else if (egressInfo.isConnected() && !vpnInfo.isConnectedOrConnecting()) {
             if (mProfile.isValidLockdownProfile()) {
-                Slog.d(TAG, "Active network connected; starting VPN");
+                Log.d(TAG, "Active network connected; starting VPN");
                 EventLogTags.writeLockdownVpnConnecting(egressType);
                 showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected);
 
@@ -160,11 +160,11 @@
                     mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp);
                 } catch (IllegalStateException e) {
                     mAcceptedEgressIface = null;
-                    Slog.e(TAG, "Failed to start VPN", e);
+                    Log.e(TAG, "Failed to start VPN", e);
                     showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
                 }
             } else {
-                Slog.e(TAG, "Invalid VPN profile; requires IP-based server and DNS");
+                Log.e(TAG, "Invalid VPN profile; requires IP-based server and DNS");
                 showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
             }
 
@@ -172,8 +172,8 @@
             final String iface = vpnConfig.interfaze;
             final List<LinkAddress> sourceAddrs = vpnConfig.addresses;
 
-            Slog.d(TAG, "VPN connected using iface=" + iface +
-                    ", sourceAddr=" + sourceAddrs.toString());
+            Log.d(TAG, "VPN connected using iface=" + iface
+                    + ", sourceAddr=" + sourceAddrs.toString());
             EventLogTags.writeLockdownVpnConnected(egressType);
             showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected);
 
@@ -190,7 +190,7 @@
     }
 
     private void initLocked() {
-        Slog.d(TAG, "initLocked()");
+        Log.d(TAG, "initLocked()");
 
         mVpn.setEnableTeardown(false);
         mVpn.setLockdown(true);
@@ -204,7 +204,7 @@
     }
 
     private void shutdownLocked() {
-        Slog.d(TAG, "shutdownLocked()");
+        Log.d(TAG, "shutdownLocked()");
 
         mAcceptedEgressIface = null;
         mErrorCount = 0;
@@ -222,7 +222,7 @@
      */
     @GuardedBy("mConnService.mVpns")
     public void reset() {
-        Slog.d(TAG, "reset()");
+        Log.d(TAG, "reset()");
         synchronized (mStateLock) {
             // cycle tracker, reset error count, and trigger retry
             shutdownLocked();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 006d78e..5bd352c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -17,11 +17,13 @@
 
 import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
 import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
 import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
 import static android.net.INetd.FIREWALL_RULE_ALLOW;
 import static android.net.INetd.FIREWALL_RULE_DENY;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.os.Process.INVALID_UID;
@@ -339,6 +341,8 @@
                 return FIREWALL_CHAIN_NAME_STANDBY;
             case FIREWALL_CHAIN_POWERSAVE:
                 return FIREWALL_CHAIN_NAME_POWERSAVE;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return FIREWALL_CHAIN_NAME_RESTRICTED;
             default:
                 return String.valueOf(chain);
         }
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 189b21f..7e6abf8 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -376,6 +376,13 @@
                     return -1;
             }
         }
+
+        PackageOptimizationInfo getPackageOptimizationInfo(ArtManagerInternal artManagerInternal) {
+            return artManagerInternal == null || launchedActivityAppRecordRequiredAbi == null
+                    ? PackageOptimizationInfo.createWithNoInfo()
+                    : artManagerInternal.getPackageOptimizationInfo(applicationInfo,
+                            launchedActivityAppRecordRequiredAbi, launchedActivityName);
+        }
     }
 
     ActivityMetricsLogger(ActivityStackSupervisor supervisor, Looper looper) {
@@ -836,14 +843,8 @@
                     info.bindApplicationDelayMs);
         }
         builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
-        final ArtManagerInternal artManagerInternal = getArtManagerInternal();
         final PackageOptimizationInfo packageOptimizationInfo =
-                (artManagerInternal == null) || (info.launchedActivityAppRecordRequiredAbi == null)
-                ? PackageOptimizationInfo.createWithNoInfo()
-                : artManagerInternal.getPackageOptimizationInfo(
-                        info.applicationInfo,
-                        info.launchedActivityAppRecordRequiredAbi,
-                        info.launchedActivityName);
+                info.getPackageOptimizationInfo(getArtManagerInternal());
         builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_REASON,
                 packageOptimizationInfo.getCompilationReason());
         builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_FILTER,
@@ -962,6 +963,8 @@
         builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
                 info.mProcessRunning ? 1 : 0);
         mMetricsLogger.write(builder);
+        final PackageOptimizationInfo packageOptimizationInfo =
+                infoSnapshot.getPackageOptimizationInfo(getArtManagerInternal());
         FrameworkStatsLog.write(
                 FrameworkStatsLog.APP_START_FULLY_DRAWN,
                 info.mLastLaunchedActivity.info.applicationInfo.uid,
@@ -971,7 +974,9 @@
                         : FrameworkStatsLog.APP_START_FULLY_DRAWN__TYPE__WITHOUT_BUNDLE,
                 info.mLastLaunchedActivity.info.name,
                 info.mProcessRunning,
-                startupTimeMs);
+                startupTimeMs,
+                packageOptimizationInfo.getCompilationReason(),
+                packageOptimizationInfo.getCompilationFilter());
 
         // Ends the trace started at the beginning of this function. This is located here to allow
         // the trace slice to have a noticable duration.
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
deleted file mode 100644
index 33ea1d6..0000000
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2017 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 com.android.server;
-
-import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
-import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
-import static android.net.INetd.FIREWALL_RULE_ALLOW;
-import static android.net.INetd.FIREWALL_RULE_DENY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.util.DebugUtils.valueToString;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.net.NetworkPolicyManager;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.function.BiFunction;
-
-/**
- * Test class for {@link NetworkManagementInternal}.
- *
- * To run the tests, use
- *
- * runtest -c com.android.server.NetworkManagementInternalTest frameworks-services
- *
- * or the following steps:
- *
- * Build: m FrameworksServicesTests
- * Install: adb install -r \
- *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
- * Run: adb shell am instrument -e class com.android.server.NetworkManagementInternalTest -w \
- *     com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NetworkManagementInternalTest {
-    private static final int TEST_UID = 111;
-
-    private NetworkManagementService.Injector mInjector;
-    private NetworkManagementInternal mNmi;
-
-    @Before
-    public void setUp() {
-        final NetworkManagementService service = new NetworkManagementService();
-        mInjector = service.getInjector();
-        mNmi = service.new LocalService();
-    }
-
-    @Test
-    public void testIsNetworkRestrictedForUid() {
-        // No firewall chains enabled
-        assertFalse(mNmi.isNetworkRestrictedForUid(TEST_UID));
-
-        // Restrict usage of mobile data in background
-        mInjector.setUidOnMeteredNetworkList(true, TEST_UID, true);
-        assertTrue("Should be true since mobile data usage is restricted",
-                mNmi.isNetworkRestrictedForUid(TEST_UID));
-        mInjector.reset();
-
-        // Data saver is on and uid is not allowlisted
-        mInjector.setDataSaverMode(true);
-        mInjector.setUidOnMeteredNetworkList(false, TEST_UID, false);
-        assertTrue("Should be true since data saver is on and the uid is not whitelisted",
-                mNmi.isNetworkRestrictedForUid(TEST_UID));
-        mInjector.reset();
-
-        // Data saver is on and uid is allowlisted
-        mInjector.setDataSaverMode(true);
-        mInjector.setUidOnMeteredNetworkList(false, TEST_UID, true);
-        assertFalse("Should be false since data saver is on and the uid is whitelisted",
-                mNmi.isNetworkRestrictedForUid(TEST_UID));
-        mInjector.reset();
-
-        final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
-        // Dozable chain
-        final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
-        isRestrictedForDozable.put(FIREWALL_RULE_DEFAULT, true);
-        isRestrictedForDozable.put(FIREWALL_RULE_ALLOW, false);
-        isRestrictedForDozable.put(FIREWALL_RULE_DENY, true);
-        expected.put(FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
-        // Powersaver chain
-        final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
-        isRestrictedForPowerSave.put(FIREWALL_RULE_DEFAULT, true);
-        isRestrictedForPowerSave.put(FIREWALL_RULE_ALLOW, false);
-        isRestrictedForPowerSave.put(FIREWALL_RULE_DENY, true);
-        expected.put(FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
-        // Standby chain
-        final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
-        isRestrictedForStandby.put(FIREWALL_RULE_DEFAULT, false);
-        isRestrictedForStandby.put(FIREWALL_RULE_ALLOW, false);
-        isRestrictedForStandby.put(FIREWALL_RULE_DENY, true);
-        expected.put(FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
-
-        final int[] chains = {
-                FIREWALL_CHAIN_STANDBY,
-                FIREWALL_CHAIN_POWERSAVE,
-                FIREWALL_CHAIN_DOZABLE
-        };
-        final int[] states = {
-                FIREWALL_RULE_ALLOW,
-                FIREWALL_RULE_DENY,
-                FIREWALL_RULE_DEFAULT
-        };
-        BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
-            return String.format("Unexpected value for chain: %s and state: %s",
-                    valueToString(NetworkPolicyManager.class, "FIREWALL_CHAIN_", chain),
-                    valueToString(NetworkPolicyManager.class, "FIREWALL_RULE_", state));
-        };
-        for (int chain : chains) {
-            final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
-            mInjector.setFirewallChainState(chain, true);
-            for (int state : states) {
-                mInjector.setFirewallRule(chain, TEST_UID, state);
-                assertEquals(errorMsg.apply(chain, state),
-                        expectedValues.get(state), mNmi.isNetworkRestrictedForUid(TEST_UID));
-            }
-            mInjector.reset();
-        }
-    }
-}
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index b001fe1..45c1c73 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -27,7 +27,6 @@
     static_libs: [
         "testng",
         "compatibility-tradefed",
-        "module_test_util",
         "frameworks-base-hostutils",
         "cts-install-lib-host",
     ],
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 407c65b..b7c9e59 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -27,7 +27,6 @@
 
 import com.android.ddmlib.Log;
 import com.android.tests.rollback.host.AbandonSessionsRule;
-import com.android.tests.util.ModuleTestUtils;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 import com.android.tradefed.util.ProcessInfo;
@@ -52,7 +51,6 @@
     private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex";
     private static final String APK_A = "TestAppAv1.apk";
 
-    private final ModuleTestUtils mTestUtils = new ModuleTestUtils(this);
     private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
 
     /**
@@ -101,7 +99,7 @@
         assumeTrue("Device does not support updating APEX",
                 mHostUtils.isApexUpdateSupported());
 
-        final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+        final File apexFile = mHostUtils.getTestFile(SHIM_V2);
         final String output = getDevice().executeAdbCommand("install", "--staged",
                 "--staged-ready-timeout", "60000", apexFile.getAbsolutePath());
         assertThat(output).contains("Reboot device to apply staged session");
@@ -116,7 +114,7 @@
         assumeTrue("Device does not support updating APEX",
                 mHostUtils.isApexUpdateSupported());
 
-        final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+        final File apexFile = mHostUtils.getTestFile(SHIM_V2);
         final String output = getDevice().executeAdbCommand("install", "--staged",
                 apexFile.getAbsolutePath());
         assertThat(output).contains("Reboot device to apply staged session");
@@ -131,7 +129,7 @@
         assumeTrue("Device does not support updating APEX",
                 mHostUtils.isApexUpdateSupported());
 
-        final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+        final File apexFile = mHostUtils.getTestFile(SHIM_V2);
         final String output = getDevice().executeAdbCommand("install", "--staged",
                 "--staged-ready-timeout", "0", apexFile.getAbsolutePath());
         assertThat(output).doesNotContain("Reboot device to apply staged session");
@@ -147,7 +145,7 @@
         assumeTrue("Device does not support updating APEX",
                 mHostUtils.isApexUpdateSupported());
 
-        final File apexFile = mTestUtils.getTestFile(SHIM_V2);
+        final File apexFile = mHostUtils.getTestFile(SHIM_V2);
         String output = getDevice().executeAdbCommand("install", "--staged",
                 "--enable-rollback", apexFile.getAbsolutePath());
         assertThat(output).contains("Reboot device to apply staged session");
@@ -164,8 +162,8 @@
         assumeTrue("Device does not support updating APEX",
                 mHostUtils.isApexUpdateSupported());
 
-        final File apexFile = mTestUtils.getTestFile(SHIM_V2);
-        final File apkFile = mTestUtils.getTestFile(APK_A);
+        final File apexFile = mHostUtils.getTestFile(SHIM_V2);
+        final File apkFile = mHostUtils.getTestFile(APK_A);
         final String output = getDevice().executeAdbCommand("install-multi-package",
                 apexFile.getAbsolutePath(), apkFile.getAbsolutePath());
         assertThat(output).contains("Created parent session");
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index dd3f5be..77e9f12 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -33,6 +33,9 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verifyNoMoreInteractions
 import java.util.UUID
 import kotlin.test.assertEquals
 import kotlin.test.assertNotEquals
@@ -87,8 +90,8 @@
         ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
     }
 
-    private fun createNetworkProvider(): TestNetworkProvider {
-        return TestNetworkProvider(context, mHandlerThread.looper)
+    private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
+        return TestNetworkProvider(ctx, mHandlerThread.looper)
     }
 
     @Test
@@ -169,7 +172,12 @@
 
     @Test
     fun testDeclareNetworkRequestUnfulfillable() {
-        val provider = createNetworkProvider()
+        val mockContext = mock(Context::class.java)
+        val provider = createNetworkProvider(mockContext)
+        // ConnectivityManager not required at creation time
+        verifyNoMoreInteractions(mockContext)
+        doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
+
         mCm.registerNetworkProvider(provider)
 
         val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index 968b307..ea763d2 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -16,6 +16,12 @@
 
 package com.android.server;
 
+import static android.util.DebugUtils.valueToString;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -29,15 +35,19 @@
 import android.net.INetd;
 import android.net.INetdUnsolicitedEventListener;
 import android.net.LinkAddress;
+import android.net.NetworkPolicyManager;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.app.IBatteryStats;
-import com.android.server.NetworkManagementService.SystemServices;
+import com.android.server.NetworkManagementService.Dependencies;
 import com.android.server.net.BaseNetworkObserver;
 
 import org.junit.After;
@@ -49,13 +59,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.function.BiFunction;
+
 /**
  * Tests for {@link NetworkManagementService}.
  */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NetworkManagementServiceTest {
-
     private NetworkManagementService mNMService;
 
     @Mock private Context mContext;
@@ -66,7 +77,9 @@
     @Captor
     private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
 
-    private final SystemServices mServices = new SystemServices() {
+    private final MockDependencies mDeps = new MockDependencies();
+
+    private final class MockDependencies extends Dependencies {
         @Override
         public IBinder getService(String name) {
             switch (name) {
@@ -76,14 +89,21 @@
                     throw new UnsupportedOperationException("Unknown service " + name);
             }
         }
+
         @Override
         public void registerLocalService(NetworkManagementInternal nmi) {
         }
+
         @Override
         public INetd getNetd() {
             return mNetdService;
         }
-    };
+
+        @Override
+        public int getCallingUid() {
+            return Process.SYSTEM_UID;
+        }
+    }
 
     @Before
     public void setUp() throws Exception {
@@ -91,7 +111,7 @@
         doNothing().when(mNetdService)
                 .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
         // Start the service and wait until it connects to our socket.
-        mNMService = NetworkManagementService.create(mContext, mServices);
+        mNMService = NetworkManagementService.create(mContext, mDeps);
     }
 
     @After
@@ -192,4 +212,105 @@
         // Make sure nothing else was called.
         verifyNoMoreInteractions(observer);
     }
+
+    @Test
+    public void testFirewallEnabled() {
+        mNMService.setFirewallEnabled(true);
+        assertTrue(mNMService.isFirewallEnabled());
+
+        mNMService.setFirewallEnabled(false);
+        assertFalse(mNMService.isFirewallEnabled());
+    }
+
+    private static final int TEST_UID = 111;
+
+    @Test
+    public void testNetworkRestrictedDefault() {
+        assertFalse(mNMService.isNetworkRestricted(TEST_UID));
+    }
+
+    @Test
+    public void testMeteredNetworkRestrictions() throws RemoteException {
+        // Make sure the mocked netd method returns true.
+        doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
+
+        // Restrict usage of mobile data in background
+        mNMService.setUidMeteredNetworkDenylist(TEST_UID, true);
+        assertTrue("Should be true since mobile data usage is restricted",
+                mNMService.isNetworkRestricted(TEST_UID));
+
+        mNMService.setDataSaverModeEnabled(true);
+        verify(mNetdService).bandwidthEnableDataSaver(true);
+
+        mNMService.setUidMeteredNetworkDenylist(TEST_UID, false);
+        assertTrue("Should be true since data saver is on and the uid is not allowlisted",
+                mNMService.isNetworkRestricted(TEST_UID));
+
+        mNMService.setUidMeteredNetworkAllowlist(TEST_UID, true);
+        assertFalse("Should be false since data saver is on and the uid is allowlisted",
+                mNMService.isNetworkRestricted(TEST_UID));
+
+        // remove uid from allowlist and turn datasaver off again
+        mNMService.setUidMeteredNetworkAllowlist(TEST_UID, false);
+        mNMService.setDataSaverModeEnabled(false);
+        verify(mNetdService).bandwidthEnableDataSaver(false);
+        assertFalse("Network should not be restricted when data saver is off",
+                mNMService.isNetworkRestricted(TEST_UID));
+    }
+
+    @Test
+    public void testFirewallChains() {
+        final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
+        // Dozable chain
+        final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
+        isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+        isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(INetd.FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
+        // Powersaver chain
+        final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
+        isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+        isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(INetd.FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
+        // Standby chain
+        final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
+        isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
+        isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(INetd.FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
+        // Restricted mode chain
+        final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
+        isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+        isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(INetd.FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
+
+        final int[] chains = {
+                INetd.FIREWALL_CHAIN_STANDBY,
+                INetd.FIREWALL_CHAIN_POWERSAVE,
+                INetd.FIREWALL_CHAIN_DOZABLE,
+                INetd.FIREWALL_CHAIN_RESTRICTED
+        };
+        final int[] states = {
+                INetd.FIREWALL_RULE_ALLOW,
+                INetd.FIREWALL_RULE_DENY,
+                NetworkPolicyManager.FIREWALL_RULE_DEFAULT
+        };
+        BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
+            return String.format("Unexpected value for chain: %s and state: %s",
+                    valueToString(INetd.class, "FIREWALL_CHAIN_", chain),
+                    valueToString(INetd.class, "FIREWALL_RULE_", state));
+        };
+        for (int chain : chains) {
+            final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
+            mNMService.setFirewallChainEnabled(chain, true);
+            for (int state : states) {
+                mNMService.setFirewallUidRule(chain, TEST_UID, state);
+                assertEquals(errorMsg.apply(chain, state),
+                        expectedValues.get(state), mNMService.isNetworkRestricted(TEST_UID));
+            }
+            mNMService.setFirewallChainEnabled(chain, false);
+        }
+    }
 }