Merge "Fix proto invalid write type"
diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp
index 6652780..bc27852 100644
--- a/framework-t/Sources.bp
+++ b/framework-t/Sources.bp
@@ -131,8 +131,8 @@
         "src/android/net/EthernetNetworkUpdateRequest.java",
         "src/android/net/EthernetNetworkUpdateRequest.aidl",
         "src/android/net/IEthernetManager.aidl",
-        "src/android/net/IEthernetNetworkManagementListener.aidl",
         "src/android/net/IEthernetServiceListener.aidl",
+        "src/android/net/INetworkInterfaceOutcomeReceiver.aidl",
         "src/android/net/ITetheredInterfaceCallback.aidl",
     ],
     path: "src",
@@ -154,17 +154,17 @@
     ],
 }
 
+// TODO: remove this empty filegroup.
 filegroup {
     name: "framework-connectivity-tiramisu-sources",
-    srcs: [
-        ":framework-connectivity-ethernet-sources",
-    ],
+    srcs: [],
     visibility: ["//frameworks/base"],
 }
 
 filegroup {
     name: "framework-connectivity-tiramisu-updatable-sources",
     srcs: [
+        ":framework-connectivity-ethernet-sources",
         ":framework-connectivity-ipsec-sources",
         ":framework-connectivity-netstats-sources",
         ":framework-connectivity-nsd-sources",
diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java
index 0414bb7..bf518b2 100644
--- a/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -699,7 +699,9 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK})
     @NonNull public android.net.NetworkStats getMobileUidStats() {
         try {
             return mService.getUidStatsForTransport(TRANSPORT_CELLULAR);
@@ -723,7 +725,9 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK})
     @NonNull public android.net.NetworkStats getWifiUidStats() {
         try {
             return mService.getUidStatsForTransport(TRANSPORT_WIFI);
@@ -740,8 +744,9 @@
      * {@link #unregisterUsageCallback} is called.
      *
      * @param template Template used to match networks. See {@link NetworkTemplate}.
-     * @param thresholdBytes Threshold in bytes to be notified on. The provided value that lower
-     *                       than 2MiB will be clamped for non-privileged callers.
+     * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB
+     *                       will be clamped for callers except callers with the NETWORK_STACK
+     *                       permission.
      * @param executor The executor on which callback will be invoked. The provided {@link Executor}
      *                 must run callback sequentially, otherwise the order of callbacks cannot be
      *                 guaranteed.
@@ -750,6 +755,9 @@
      * @hide
      */
     @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK}, conditional = true)
     public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes,
             @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) {
         Objects.requireNonNull(template, "NetworkTemplate cannot be null");
@@ -1053,9 +1061,9 @@
     @RequiresPermission(anyOf = {
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
             android.Manifest.permission.NETWORK_STACK})
-    public void setUidForeground(int uid, boolean uidForeground) {
+    public void noteUidForeground(int uid, boolean uidForeground) {
         try {
-            mService.setUidForeground(uid, uidForeground);
+            mService.noteUidForeground(uid, uidForeground);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
index 9bffbfb..61b34d0 100644
--- a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
+++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
@@ -34,8 +34,9 @@
     private ConnectivityFrameworkInitializerTiramisu() {}
 
     /**
-     * Called by {@link SystemServiceRegistry}'s static initializer and registers nsd services to
-     * {@link Context}, so that {@link Context#getSystemService} can return them.
+     * Called by {@link SystemServiceRegistry}'s static initializer and registers NetworkStats, nsd,
+     * ipsec and ethernet services to {@link Context}, so that {@link Context#getSystemService} can
+     * return them.
      *
      * @throws IllegalStateException if this is called anywhere besides
      * {@link SystemServiceRegistry}.
@@ -68,5 +69,14 @@
                     return new NetworkStatsManager(context, service);
                 }
         );
+
+        SystemServiceRegistry.registerContextAwareService(
+                Context.ETHERNET_SERVICE,
+                EthernetManager.class,
+                (context, serviceBinder) -> {
+                    IEthernetManager service = IEthernetManager.Stub.asInterface(serviceBinder);
+                    return new EthernetManager(context, service);
+                }
+        );
     }
 }
diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java
index 72243f9..4f61dbf 100644
--- a/framework-t/src/android/net/EthernetManager.java
+++ b/framework-t/src/android/net/EthernetManager.java
@@ -30,17 +30,17 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Build;
+import android.os.OutcomeReceiver;
 import android.os.RemoteException;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.BackgroundThread;
+import com.android.modules.utils.BackgroundThread;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Objects;
 import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
 
 /**
  * A class that manages and configures Ethernet interfaces.
@@ -443,41 +443,45 @@
         return new TetheredInterfaceRequest(mService, cbInternal);
     }
 
-    private static final class InternalNetworkManagementListener
-            extends IEthernetNetworkManagementListener.Stub {
+    private static final class NetworkInterfaceOutcomeReceiver
+            extends INetworkInterfaceOutcomeReceiver.Stub {
         @NonNull
         private final Executor mExecutor;
         @NonNull
-        private final BiConsumer<Network, EthernetNetworkManagementException> mListener;
+        private final OutcomeReceiver<String, EthernetNetworkManagementException> mCallback;
 
-        InternalNetworkManagementListener(
+        NetworkInterfaceOutcomeReceiver(
                 @NonNull final Executor executor,
-                @NonNull final BiConsumer<Network, EthernetNetworkManagementException> listener) {
+                @NonNull final OutcomeReceiver<String, EthernetNetworkManagementException>
+                        callback) {
             Objects.requireNonNull(executor, "Pass a non-null executor");
-            Objects.requireNonNull(listener, "Pass a non-null listener");
+            Objects.requireNonNull(callback, "Pass a non-null callback");
             mExecutor = executor;
-            mListener = listener;
+            mCallback = callback;
         }
 
         @Override
-        public void onComplete(
-                @Nullable final Network network,
-                @Nullable final EthernetNetworkManagementException e) {
-            mExecutor.execute(() -> mListener.accept(network, e));
+        public void onResult(@NonNull String iface) {
+            mExecutor.execute(() -> mCallback.onResult(iface));
+        }
+
+        @Override
+        public void onError(@NonNull EthernetNetworkManagementException e) {
+            mExecutor.execute(() -> mCallback.onError(e));
         }
     }
 
-    private InternalNetworkManagementListener getInternalNetworkManagementListener(
+    private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver(
             @Nullable final Executor executor,
-            @Nullable final BiConsumer<Network, EthernetNetworkManagementException> listener) {
-        if (null != listener) {
-            Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+            @Nullable final OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
+        if (null != callback) {
+            Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback");
         }
-        final InternalNetworkManagementListener proxy;
-        if (null == listener) {
+        final NetworkInterfaceOutcomeReceiver proxy;
+        if (null == callback) {
             proxy = null;
         } else {
-            proxy = new InternalNetworkManagementListener(executor, listener);
+            proxy = new NetworkInterfaceOutcomeReceiver(executor, callback);
         }
         return proxy;
     }
@@ -492,14 +496,17 @@
      * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities}
      * object for this network to put inside the {@code request}.
      *
-     * If non-null, the listener will be called exactly once after this is called, unless
-     * a synchronous exception was thrown.
+     * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+     * finished execution.
      *
      * @param iface the name of the interface to act upon.
      * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's
      *                {@link StaticIpConfiguration} and {@link NetworkCapabilities} values.
-     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
-     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+     * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+     * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+     *                 operation. On success, {@link OutcomeReceiver#onResult} is called with the
+     *                 interface name. On error, {@link OutcomeReceiver#onError} is called with more
+     *                 information about the error.
      * @throws SecurityException if the process doesn't hold
      *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
      * @throws UnsupportedOperationException if called on a non-automotive device or on an
@@ -511,16 +518,15 @@
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
             android.Manifest.permission.NETWORK_STACK,
             android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
-    @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
     public void updateConfiguration(
             @NonNull String iface,
             @NonNull EthernetNetworkUpdateRequest request,
             @Nullable @CallbackExecutor Executor executor,
-            @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+            @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
         Objects.requireNonNull(iface, "iface must be non-null");
         Objects.requireNonNull(request, "request must be non-null");
-        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
-                executor, listener);
+        final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+                executor, callback);
         try {
             mService.updateConfiguration(iface, request, proxy);
         } catch (RemoteException e) {
@@ -531,15 +537,17 @@
     /**
      * Set an ethernet network's link state up.
      *
-     * When the link is successfully turned up, the listener will be called with the resulting
-     * network. If any error or unexpected condition happens while the system tries to turn the
-     * interface up, the listener will be called with an appropriate exception.
-     * The listener is guaranteed to be called exactly once for each call to this method, but this
-     * may take an unbounded amount of time depending on the actual network conditions.
+     * When the link is successfully turned up, the callback will be called with the network
+     * interface was torn down, if any. If any error or unexpected condition happens while the
+     * system tries to turn the interface down, the callback will be called with an appropriate
+     * exception. The callback is guaranteed to be called exactly once for each call to this method.
      *
      * @param iface the name of the interface to act upon.
-     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
-     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+     * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+     * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+     *                 operation. On success, {@link OutcomeReceiver#onResult} is called with the
+     *                 interface name. On error, {@link OutcomeReceiver#onError} is called with more
+     *                 information about the error.
      * @throws SecurityException if the process doesn't hold
      *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
      * @throws UnsupportedOperationException if called on a non-automotive device.
@@ -554,10 +562,10 @@
     public void connectNetwork(
             @NonNull String iface,
             @Nullable @CallbackExecutor Executor executor,
-            @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+            @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
         Objects.requireNonNull(iface, "iface must be non-null");
-        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
-                executor, listener);
+        final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+                executor, callback);
         try {
             mService.connectNetwork(iface, proxy);
         } catch (RemoteException e) {
@@ -568,14 +576,17 @@
     /**
      * Set an ethernet network's link state down.
      *
-     * When the link is successfully turned down, the listener will be called with the network that
-     * was torn down, if any. If any error or unexpected condition happens while the system tries to
-     * turn the interface down, the listener will be called with an appropriate exception.
-     * The listener is guaranteed to be called exactly once for each call to this method.
+     * When the link is successfully turned down, the callback will be called with the network
+     * interface was torn down, if any. If any error or unexpected condition happens while the
+     * system tries to turn the interface down, the callback will be called with an appropriate
+     * exception. The callback is guaranteed to be called exactly once for each call to this method.
      *
      * @param iface the name of the interface to act upon.
-     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
-     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+     * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+     * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+     *                 operation. On success, {@link OutcomeReceiver#onResult} is called with the
+     *                 interface name. On error, {@link OutcomeReceiver#onError} is called with more
+     *                 information about the error.
      * @throws SecurityException if the process doesn't hold
      *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
      * @throws UnsupportedOperationException if called on a non-automotive device.
@@ -590,10 +601,10 @@
     public void disconnectNetwork(
             @NonNull String iface,
             @Nullable @CallbackExecutor Executor executor,
-            @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+            @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
         Objects.requireNonNull(iface, "iface must be non-null");
-        final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
-                executor, listener);
+        final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+                executor, callback);
         try {
             mService.disconnectNetwork(iface, proxy);
         } catch (RemoteException e) {
diff --git a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
index a626971..1691942 100644
--- a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
+++ b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
@@ -24,36 +24,54 @@
 
 import java.util.Objects;
 
-/** @hide */
+/**
+ * Represents a request to update an existing Ethernet interface.
+ *
+ * @see EthernetManager#updateConfiguration
+ *
+ * @hide
+ */
 @SystemApi
 public final class EthernetNetworkUpdateRequest implements Parcelable {
-    @NonNull
+    @Nullable
     private final IpConfiguration mIpConfig;
-    @NonNull
+    @Nullable
     private final NetworkCapabilities mNetworkCapabilities;
 
-    @NonNull
+    /**
+     * Setting the {@link IpConfiguration} is optional in {@link EthernetNetworkUpdateRequest}.
+     * When set to null, the existing IpConfiguration is not updated.
+     *
+     * @return the new {@link IpConfiguration} or null.
+     */
+    @Nullable
     public IpConfiguration getIpConfiguration() {
-        return new IpConfiguration(mIpConfig);
+        return mIpConfig == null ? null : new IpConfiguration(mIpConfig);
     }
 
-    @NonNull
+    /**
+     * Setting the {@link NetworkCapabilities} is optional in {@link EthernetNetworkUpdateRequest}.
+     * When set to null, the existing NetworkCapabilities are not updated.
+     *
+     * @return the new {@link NetworkCapabilities} or null.
+     */
+    @Nullable
     public NetworkCapabilities getNetworkCapabilities() {
-        return new NetworkCapabilities(mNetworkCapabilities);
+        return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities);
     }
 
-    private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig,
-            @NonNull final NetworkCapabilities networkCapabilities) {
-        Objects.requireNonNull(ipConfig);
-        Objects.requireNonNull(networkCapabilities);
-        mIpConfig = new IpConfiguration(ipConfig);
-        mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
+    private EthernetNetworkUpdateRequest(@Nullable final IpConfiguration ipConfig,
+            @Nullable final NetworkCapabilities networkCapabilities) {
+        mIpConfig = ipConfig;
+        mNetworkCapabilities = networkCapabilities;
     }
 
     private EthernetNetworkUpdateRequest(@NonNull final Parcel source) {
         Objects.requireNonNull(source);
-        mIpConfig = IpConfiguration.CREATOR.createFromParcel(source);
-        mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source);
+        mIpConfig = source.readParcelable(IpConfiguration.class.getClassLoader(),
+                IpConfiguration.class);
+        mNetworkCapabilities = source.readParcelable(NetworkCapabilities.class.getClassLoader(),
+                NetworkCapabilities.class);
     }
 
     /**
@@ -74,8 +92,10 @@
          */
         public Builder(@NonNull final EthernetNetworkUpdateRequest request) {
             Objects.requireNonNull(request);
-            mBuilderIpConfig = new IpConfiguration(request.mIpConfig);
-            mBuilderNetworkCapabilities = new NetworkCapabilities(request.mNetworkCapabilities);
+            mBuilderIpConfig = null == request.mIpConfig
+                    ? null : new IpConfiguration(request.mIpConfig);
+            mBuilderNetworkCapabilities = null == request.mNetworkCapabilities
+                    ? null : new NetworkCapabilities(request.mNetworkCapabilities);
         }
 
         /**
@@ -84,9 +104,8 @@
          * @return The builder to facilitate chaining.
          */
         @NonNull
-        public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) {
-            Objects.requireNonNull(ipConfig);
-            mBuilderIpConfig = new IpConfiguration(ipConfig);
+        public Builder setIpConfiguration(@Nullable final IpConfiguration ipConfig) {
+            mBuilderIpConfig = ipConfig == null ? null : new IpConfiguration(ipConfig);
             return this;
         }
 
@@ -96,17 +115,23 @@
          * @return The builder to facilitate chaining.
          */
         @NonNull
-        public Builder setNetworkCapabilities(@NonNull final NetworkCapabilities nc) {
-            Objects.requireNonNull(nc);
-            mBuilderNetworkCapabilities = new NetworkCapabilities(nc);
+        public Builder setNetworkCapabilities(@Nullable final NetworkCapabilities nc) {
+            mBuilderNetworkCapabilities = nc == null ? null : new NetworkCapabilities(nc);
             return this;
         }
 
         /**
          * Build {@link EthernetNetworkUpdateRequest} return the current update request.
+         *
+         * @throws IllegalStateException when both mBuilderNetworkCapabilities and mBuilderIpConfig
+         *                               are null.
          */
         @NonNull
         public EthernetNetworkUpdateRequest build() {
+            if (mBuilderIpConfig == null && mBuilderNetworkCapabilities == null) {
+                throw new IllegalStateException(
+                        "Cannot construct an empty EthernetNetworkUpdateRequest");
+            }
             return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities);
         }
     }
@@ -135,8 +160,8 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        mIpConfig.writeToParcel(dest, flags);
-        mNetworkCapabilities.writeToParcel(dest, flags);
+        dest.writeParcelable(mIpConfig, flags);
+        dest.writeParcelable(mNetworkCapabilities, flags);
     }
 
     @Override
diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl
index 544d02b..95ae907 100644
--- a/framework-t/src/android/net/IEthernetManager.aidl
+++ b/framework-t/src/android/net/IEthernetManager.aidl
@@ -18,8 +18,9 @@
 
 import android.net.IpConfiguration;
 import android.net.IEthernetServiceListener;
-import android.net.IEthernetNetworkManagementListener;
+import android.net.EthernetNetworkManagementException;
 import android.net.EthernetNetworkUpdateRequest;
+import android.net.INetworkInterfaceOutcomeReceiver;
 import android.net.ITetheredInterfaceCallback;
 
 /**
@@ -39,7 +40,7 @@
     void requestTetheredInterface(in ITetheredInterfaceCallback callback);
     void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
     void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request,
-        in IEthernetNetworkManagementListener listener);
-    void connectNetwork(String iface, in IEthernetNetworkManagementListener listener);
-    void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener);
+        in INetworkInterfaceOutcomeReceiver listener);
+    void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener);
+    void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener);
 }
diff --git a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
similarity index 80%
rename from framework-t/src/android/net/IEthernetNetworkManagementListener.aidl
rename to framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
index 93edccf..85795ea 100644
--- a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl
+++ b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
@@ -17,9 +17,9 @@
 package android.net;
 
 import android.net.EthernetNetworkManagementException;
-import android.net.Network;
 
 /** @hide */
-oneway interface IEthernetNetworkManagementListener {
-    void onComplete(in Network network, in EthernetNetworkManagementException exception);
+oneway interface INetworkInterfaceOutcomeReceiver {
+    void onResult(in String iface);
+    void onError(in EthernetNetworkManagementException e);
 }
\ No newline at end of file
diff --git a/framework-t/src/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl
index efe626d..c86f7fd 100644
--- a/framework-t/src/android/net/INetworkStatsService.aidl
+++ b/framework-t/src/android/net/INetworkStatsService.aidl
@@ -91,7 +91,7 @@
             in INetworkStatsProvider provider);
 
     /** Mark given UID as being in foreground for stats purposes. */
-    void setUidForeground(int uid, boolean uidForeground);
+    void noteUidForeground(int uid, boolean uidForeground);
 
     /** Advise persistence threshold; may be overridden internally. */
     void advisePersistThreshold(long thresholdBytes);
diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java
index 56faa52..da5f88d 100644
--- a/framework-t/src/android/net/NetworkIdentity.java
+++ b/framework-t/src/android/net/NetworkIdentity.java
@@ -20,6 +20,7 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -86,6 +87,7 @@
 
     final int mType;
     final int mRatType;
+    final int mSubId;
     final String mSubscriberId;
     final String mWifiNetworkKey;
     final boolean mRoaming;
@@ -96,7 +98,7 @@
     /** @hide */
     public NetworkIdentity(
             int type, int ratType, @Nullable String subscriberId, @Nullable String wifiNetworkKey,
-            boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged) {
+            boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged, int subId) {
         mType = type;
         mRatType = ratType;
         mSubscriberId = subscriberId;
@@ -105,12 +107,13 @@
         mMetered = metered;
         mDefaultNetwork = defaultNetwork;
         mOemManaged = oemManaged;
+        mSubId = subId;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered,
-                mDefaultNetwork, mOemManaged);
+                mDefaultNetwork, mOemManaged, mSubId);
     }
 
     @Override
@@ -122,7 +125,8 @@
                     && Objects.equals(mWifiNetworkKey, ident.mWifiNetworkKey)
                     && mMetered == ident.mMetered
                     && mDefaultNetwork == ident.mDefaultNetwork
-                    && mOemManaged == ident.mOemManaged;
+                    && mOemManaged == ident.mOemManaged
+                    && mSubId == ident.mSubId;
         }
         return false;
     }
@@ -150,6 +154,7 @@
         builder.append(", metered=").append(mMetered);
         builder.append(", defaultNetwork=").append(mDefaultNetwork);
         builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
+        builder.append(", subId=").append(mSubId);
         return builder.append("}").toString();
     }
 
@@ -256,6 +261,11 @@
         return mOemManaged;
     }
 
+    /** Get the SubId of this instance. */
+    public int getSubId() {
+        return mSubId;
+    }
+
     /**
      * Assemble a {@link NetworkIdentity} from the passed arguments.
      *
@@ -276,7 +286,8 @@
     public static NetworkIdentity buildNetworkIdentity(Context context,
             @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, int ratType) {
         final NetworkIdentity.Builder builder = new NetworkIdentity.Builder()
-                .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork);
+                .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork)
+                .setSubId(snapshot.getSubId());
         if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) {
             builder.setRatType(ratType);
         }
@@ -325,6 +336,9 @@
         if (res == 0) {
             res = Integer.compare(left.mOemManaged, right.mOemManaged);
         }
+        if (res == 0) {
+            res = Integer.compare(left.mSubId, right.mSubId);
+        }
         return res;
     }
 
@@ -345,6 +359,7 @@
         private boolean mMetered;
         private boolean mDefaultNetwork;
         private int mOemManaged;
+        private int mSubId;
 
         /**
          * Creates a new Builder.
@@ -359,6 +374,7 @@
             mMetered = false;
             mDefaultNetwork = false;
             mOemManaged = NetworkTemplate.OEM_MANAGED_NO;
+            mSubId = INVALID_SUBSCRIPTION_ID;
         }
 
         /**
@@ -537,6 +553,19 @@
             return this;
         }
 
+        /**
+         * Set the Subscription Id.
+         *
+         * @param subId the Subscription Id of the network. Or INVALID_SUBSCRIPTION_ID if not
+         *              applicable.
+         * @return this builder.
+         */
+        @NonNull
+        public Builder setSubId(int subId) {
+            mSubId = subId;
+            return this;
+        }
+
         private void ensureValidParameters() {
             // Assert non-mobile network cannot have a ratType.
             if (mType != TYPE_MOBILE && mRatType != NetworkTemplate.NETWORK_TYPE_ALL) {
@@ -559,7 +588,7 @@
         public NetworkIdentity build() {
             ensureValidParameters();
             return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey,
-                    mRoaming, mMetered, mDefaultNetwork, mOemManaged);
+                    mRoaming, mMetered, mDefaultNetwork, mOemManaged, mSubId);
         }
     }
 }
diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java
index dfa347f..ad3a958 100644
--- a/framework-t/src/android/net/NetworkIdentitySet.java
+++ b/framework-t/src/android/net/NetworkIdentitySet.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
 import android.annotation.NonNull;
 import android.service.NetworkIdentitySetProto;
@@ -42,6 +43,7 @@
     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;
+    private static final int VERSION_ADD_SUB_ID = 7;
 
     /**
      * Construct a {@link NetworkIdentitySet} object.
@@ -103,8 +105,15 @@
                 oemNetCapabilities = NetworkIdentity.OEM_NONE;
             }
 
+            final int subId;
+            if (version >= VERSION_ADD_SUB_ID) {
+                subId = in.readInt();
+            } else {
+                subId = INVALID_SUBSCRIPTION_ID;
+            }
+
             add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered,
-                    defaultNetwork, oemNetCapabilities));
+                    defaultNetwork, oemNetCapabilities, subId));
         }
     }
 
@@ -113,7 +122,7 @@
      * @hide
      */
     public void writeToStream(DataOutput out) throws IOException {
-        out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK);
+        out.writeInt(VERSION_ADD_SUB_ID);
         out.writeInt(size());
         for (NetworkIdentity ident : this) {
             out.writeInt(ident.getType());
@@ -124,6 +133,7 @@
             out.writeBoolean(ident.isMetered());
             out.writeBoolean(ident.isDefaultNetwork());
             out.writeInt(ident.getOemManaged());
+            out.writeInt(ident.getSubId());
         }
     }
 
diff --git a/framework-t/src/android/net/NetworkStateSnapshot.java b/framework-t/src/android/net/NetworkStateSnapshot.java
index 3915634..d3f785a 100644
--- a/framework-t/src/android/net/NetworkStateSnapshot.java
+++ b/framework-t/src/android/net/NetworkStateSnapshot.java
@@ -17,6 +17,8 @@
 package android.net;
 
 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -98,12 +100,29 @@
         return mLinkProperties;
     }
 
-    /** Get the Subscriber Id of the network associated with this snapshot. */
+    /**
+     * Get the Subscriber Id of the network associated with this snapshot.
+     * @deprecated Please use #getSubId, which doesn't return personally identifiable
+     * information.
+     */
+    @Deprecated
     @Nullable
     public String getSubscriberId() {
         return mSubscriberId;
     }
 
+    /** Get the subId of the network associated with this snapshot. */
+    public int getSubId() {
+        if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+            final NetworkSpecifier spec = mNetworkCapabilities.getNetworkSpecifier();
+            if (spec instanceof TelephonyNetworkSpecifier) {
+                return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
+            }
+        }
+        return INVALID_SUBSCRIPTION_ID;
+    }
+
+
     /**
      * Get the legacy type of the network associated with this snapshot.
      * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}.
diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java
index f681ba1..06f2a62 100644
--- a/framework-t/src/android/net/NetworkStats.java
+++ b/framework-t/src/android/net/NetworkStats.java
@@ -327,16 +327,11 @@
          * @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is
          *            for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only
          *            counting iface stats.
-         * @param set usage state of this {@link Entry}. Should be one of the following
-         *            values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
+         * @param set usage state of this {@link Entry}.
          * @param tag tag of this {@link Entry}.
-         * @param metered metered state of this {@link Entry}. Should be one of the following
-         *                values: {link #METERED_YES}, {link #METERED_NO}.
-         * @param roaming roaming state of this {@link Entry}. Should be one of the following
-         *                values: {link #ROAMING_YES}, {link #ROAMING_NO}.
-         * @param defaultNetwork default network status of this {@link Entry}. Should be one
-         *                       of the following values: {link #DEFAULT_NETWORK_YES},
-         *                       {link #DEFAULT_NETWORK_NO}.
+         * @param metered metered state of this {@link Entry}.
+         * @param roaming roaming state of this {@link Entry}.
+         * @param defaultNetwork default network status of this {@link Entry}.
          * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should
          *                represent the contents of IP packets, including IP headers.
          * @param rxPackets Number of packets received for this {@link Entry}. Statistics should
@@ -401,8 +396,7 @@
         }
 
         /**
-         * @return the set state of this entry. Should be one of the following
-         * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
+         * @return the set state of this entry.
          */
         @State public int getSet() {
             return set;
@@ -416,24 +410,21 @@
         }
 
         /**
-         * @return the metered state. Should be one of the following
-         * values: {link #METERED_YES}, {link #METERED_NO}.
+         * @return the metered state.
          */
         @Meteredness public int getMetered() {
             return metered;
         }
 
         /**
-         * @return the roaming state. Should be one of the following
-         * values: {link #ROAMING_YES}, {link #ROAMING_NO}.
+         * @return the roaming state.
          */
         @Roaming public int getRoaming() {
             return roaming;
         }
 
         /**
-         * @return the default network state. Should be one of the following
-         * values: {link #DEFAULT_NETWORK_YES}, {link #DEFAULT_NETWORK_NO}.
+         * @return the default network state.
          */
         @DefaultNetwork public int getDefaultNetwork() {
             return defaultNetwork;
diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java
index 735c44d..e385b33 100644
--- a/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/framework-t/src/android/net/NetworkStatsCollection.java
@@ -36,6 +36,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.net.NetworkStats.State;
 import android.net.NetworkStatsHistory.Entry;
 import android.os.Binder;
 import android.service.NetworkStatsCollectionKeyProto;
@@ -102,7 +103,7 @@
 
     private ArrayMap<Key, NetworkStatsHistory> mStats = new ArrayMap<>();
 
-    private final long mBucketDuration;
+    private final long mBucketDurationMillis;
 
     private long mStartMillis;
     private long mEndMillis;
@@ -115,8 +116,8 @@
      * @param bucketDuration duration of the buckets in this object, in milliseconds.
      * @hide
      */
-    public NetworkStatsCollection(long bucketDuration) {
-        mBucketDuration = bucketDuration;
+    public NetworkStatsCollection(long bucketDurationMillis) {
+        mBucketDurationMillis = bucketDurationMillis;
         reset();
     }
 
@@ -148,7 +149,7 @@
         if (mStartMillis == Long.MAX_VALUE) {
             return Long.MAX_VALUE;
         } else {
-            return mStartMillis + mBucketDuration;
+            return mStartMillis + mBucketDurationMillis;
         }
     }
 
@@ -184,10 +185,10 @@
                 || time == SubscriptionPlan.TIME_UNKNOWN) {
             return time;
         } else {
-            final long mod = time % mBucketDuration;
+            final long mod = time % mBucketDurationMillis;
             if (mod > 0) {
                 time -= mod;
-                time += mBucketDuration;
+                time += mBucketDurationMillis;
             }
             return time;
         }
@@ -200,7 +201,7 @@
                 || time == SubscriptionPlan.TIME_UNKNOWN) {
             return time;
         } else {
-            final long mod = time % mBucketDuration;
+            final long mod = time % mBucketDurationMillis;
             if (mod > 0) {
                 time -= mod;
             }
@@ -247,10 +248,10 @@
         // 180 days of history should be enough for anyone; if we end up needing
         // more, we'll dynamically grow the history object.
         final int bucketEstimate = (int) NetworkStatsUtils.constrain(
-                ((end - start) / mBucketDuration), 0,
-                (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration);
+                ((end - start) / mBucketDurationMillis), 0,
+                (180 * DateUtils.DAY_IN_MILLIS) / mBucketDurationMillis);
         final NetworkStatsHistory combined = new NetworkStatsHistory(
-                mBucketDuration, bucketEstimate, fields);
+                mBucketDurationMillis, bucketEstimate, fields);
 
         // shortcut when we know stats will be empty
         if (start == end) return combined;
@@ -343,7 +344,7 @@
 
             // Finally we can slice data as originally requested
             final NetworkStatsHistory sliced = new NetworkStatsHistory(
-                    mBucketDuration, bucketEstimate, fields);
+                    mBucketDurationMillis, bucketEstimate, fields);
             sliced.recordHistory(combined, start, end);
             return sliced;
         } else {
@@ -458,9 +459,9 @@
         // update when no existing, or when bucket duration changed
         NetworkStatsHistory updated = null;
         if (existing == null) {
-            updated = new NetworkStatsHistory(mBucketDuration, 10);
-        } else if (existing.getBucketDuration() != mBucketDuration) {
-            updated = new NetworkStatsHistory(existing, mBucketDuration);
+            updated = new NetworkStatsHistory(mBucketDurationMillis, 10);
+        } else if (existing.getBucketDuration() != mBucketDurationMillis) {
+            updated = new NetworkStatsHistory(existing, mBucketDurationMillis);
         }
 
         if (updated != null) {
@@ -702,7 +703,7 @@
 
     private int estimateBuckets() {
         return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5)
-                / mBucketDuration);
+                / mBucketDurationMillis);
     }
 
     private ArrayList<Key> getSortedKeys() {
@@ -828,7 +829,7 @@
      * Builder class for {@link NetworkStatsCollection}.
      */
     public static final class Builder {
-        private final long mBucketDuration;
+        private final long mBucketDurationMillis;
         private final ArrayMap<Key, NetworkStatsHistory> mEntries = new ArrayMap<>();
 
         /**
@@ -836,8 +837,8 @@
          *
          * @param bucketDuration Duration of the buckets of the object, in milliseconds.
          */
-        public Builder(long bucketDuration) {
-            mBucketDuration = bucketDuration;
+        public Builder(long bucketDurationMillis) {
+            mBucketDurationMillis = bucketDurationMillis;
         }
 
         /**
@@ -855,7 +856,7 @@
             final List<Entry> historyEntries = history.getEntries();
 
             final NetworkStatsHistory.Builder historyBuilder =
-                    new NetworkStatsHistory.Builder(mBucketDuration, historyEntries.size());
+                    new NetworkStatsHistory.Builder(mBucketDurationMillis, historyEntries.size());
             for (Entry entry : historyEntries) {
                 historyBuilder.addEntry(entry);
             }
@@ -871,7 +872,8 @@
          */
         @NonNull
         public NetworkStatsCollection build() {
-            final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
+            final NetworkStatsCollection collection =
+                    new NetworkStatsCollection(mBucketDurationMillis);
             for (int i = 0; i < mEntries.size(); i++) {
                 collection.recordHistory(mEntries.keyAt(i), mEntries.valueAt(i));
             }
@@ -883,7 +885,7 @@
      * the identifier that associate with the {@link NetworkStatsHistory} object to identify
      * a certain record in the {@link NetworkStatsCollection} object.
      */
-    public static class Key {
+    public static final class Key {
         /** @hide */
         public final NetworkIdentitySet ident;
         /** @hide */
@@ -903,7 +905,7 @@
          * @param set Set of the record, see {@code NetworkStats#SET_*}.
          * @param tag Tag of the record, see {@link TrafficStats#setThreadStatsTag(int)}.
          */
-        public Key(@NonNull Set<NetworkIdentity> ident, int uid, int set, int tag) {
+        public Key(@NonNull Set<NetworkIdentity> ident, int uid, @State int set, int tag) {
             this(new NetworkIdentitySet(Objects.requireNonNull(ident)), uid, set, tag);
         }
 
diff --git a/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
index 7eaa01e..01ff02d 100644
--- a/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
+++ b/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
@@ -26,6 +26,7 @@
 oneway interface INetworkStatsProviderCallback {
     void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
     void notifyAlertReached();
-    void notifyWarningOrLimitReached();
+    void notifyWarningReached();
+    void notifyLimitReached();
     void unregister();
 }
diff --git a/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
index 23fc069..d37a53d 100644
--- a/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
+++ b/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
@@ -152,19 +152,19 @@
         try {
             // Reuse the code path to notify warning reached with limit reached
             // since framework handles them in the same way.
-            getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+            getProviderCallbackBinderOrThrow().notifyWarningReached();
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
     }
 
     /**
-     * Notify system that the quota set by {@link #onSetLimit} or limit set by
+     * Notify system that the limit set by {@link #onSetLimit} or limit set by
      * {@link #onSetWarningAndLimit} has been reached.
      */
     public void notifyLimitReached() {
         try {
-            getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+            getProviderCallbackBinderOrThrow().notifyLimitReached();
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java
index 512fbce..209f372 100644
--- a/framework-t/src/android/net/nsd/NsdManager.java
+++ b/framework-t/src/android/net/nsd/NsdManager.java
@@ -45,6 +45,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * The Network Service Discovery Manager class provides the API to discover services
@@ -285,8 +286,12 @@
     private final Context mContext;
 
     private int mListenerKey = FIRST_LISTENER_KEY;
+    @GuardedBy("mMapLock")
     private final SparseArray mListenerMap = new SparseArray();
+    @GuardedBy("mMapLock")
     private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>();
+    @GuardedBy("mMapLock")
+    private final SparseArray<Executor> mExecutorMap = new SparseArray<>();
     private final Object mMapLock = new Object();
     // Map of listener key sent by client -> per-network discovery tracker
     @GuardedBy("mPerNetworkDiscoveryMap")
@@ -299,6 +304,7 @@
         final String mServiceType;
         final int mProtocolType;
         final DiscoveryListener mBaseListener;
+        final Executor mBaseExecutor;
         final ArrayMap<Network, DelegatingDiscoveryListener> mPerNetworkListeners =
                 new ArrayMap<>();
 
@@ -308,7 +314,8 @@
                 final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener(
                         network, mBaseListener);
                 mPerNetworkListeners.put(network, wrappedListener);
-                discoverServices(mServiceType, mProtocolType, network, wrappedListener);
+                discoverServices(mServiceType, mProtocolType, network, mBaseExecutor,
+                        wrappedListener);
             }
 
             @Override
@@ -355,9 +362,10 @@
         }
 
         private PerNetworkDiscoveryTracker(String serviceType, int protocolType,
-                DiscoveryListener baseListener) {
+                Executor baseExecutor, DiscoveryListener baseListener) {
             mServiceType = serviceType;
             mProtocolType = protocolType;
+            mBaseExecutor = baseExecutor;
             mBaseListener = baseListener;
         }
 
@@ -644,9 +652,11 @@
             final int key = message.arg2;
             final Object listener;
             final NsdServiceInfo ns;
+            final Executor executor;
             synchronized (mMapLock) {
                 listener = mListenerMap.get(key);
                 ns = mServiceMap.get(key);
+                executor = mExecutorMap.get(key);
             }
             if (listener == null) {
                 Log.d(TAG, "Stale key " + message.arg2);
@@ -657,56 +667,64 @@
             }
             switch (what) {
                 case DISCOVER_SERVICES_STARTED:
-                    String s = getNsdServiceInfoType((NsdServiceInfo) message.obj);
-                    ((DiscoveryListener) listener).onDiscoveryStarted(s);
+                    final String s = getNsdServiceInfoType((NsdServiceInfo) message.obj);
+                    executor.execute(() -> ((DiscoveryListener) listener).onDiscoveryStarted(s));
                     break;
                 case DISCOVER_SERVICES_FAILED:
                     removeListener(key);
-                    ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns),
-                            message.arg1);
+                    executor.execute(() -> ((DiscoveryListener) listener).onStartDiscoveryFailed(
+                            getNsdServiceInfoType(ns), message.arg1));
                     break;
                 case SERVICE_FOUND:
-                    ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj);
+                    executor.execute(() -> ((DiscoveryListener) listener).onServiceFound(
+                            (NsdServiceInfo) message.obj));
                     break;
                 case SERVICE_LOST:
-                    ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj);
+                    executor.execute(() -> ((DiscoveryListener) listener).onServiceLost(
+                            (NsdServiceInfo) message.obj));
                     break;
                 case STOP_DISCOVERY_FAILED:
                     // TODO: failure to stop discovery should be internal and retried internally, as
                     // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED
                     removeListener(key);
-                    ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns),
-                            message.arg1);
+                    executor.execute(() -> ((DiscoveryListener) listener).onStopDiscoveryFailed(
+                            getNsdServiceInfoType(ns), message.arg1));
                     break;
                 case STOP_DISCOVERY_SUCCEEDED:
                     removeListener(key);
-                    ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns));
+                    executor.execute(() -> ((DiscoveryListener) listener).onDiscoveryStopped(
+                            getNsdServiceInfoType(ns)));
                     break;
                 case REGISTER_SERVICE_FAILED:
                     removeListener(key);
-                    ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1);
+                    executor.execute(() -> ((RegistrationListener) listener).onRegistrationFailed(
+                            ns, message.arg1));
                     break;
                 case REGISTER_SERVICE_SUCCEEDED:
-                    ((RegistrationListener) listener).onServiceRegistered(
-                            (NsdServiceInfo) message.obj);
+                    executor.execute(() -> ((RegistrationListener) listener).onServiceRegistered(
+                            (NsdServiceInfo) message.obj));
                     break;
                 case UNREGISTER_SERVICE_FAILED:
                     removeListener(key);
-                    ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1);
+                    executor.execute(() -> ((RegistrationListener) listener).onUnregistrationFailed(
+                            ns, message.arg1));
                     break;
                 case UNREGISTER_SERVICE_SUCCEEDED:
                     // TODO: do not unregister listener until service is unregistered, or provide
                     // alternative way for unregistering ?
                     removeListener(message.arg2);
-                    ((RegistrationListener) listener).onServiceUnregistered(ns);
+                    executor.execute(() -> ((RegistrationListener) listener).onServiceUnregistered(
+                            ns));
                     break;
                 case RESOLVE_SERVICE_FAILED:
                     removeListener(key);
-                    ((ResolveListener) listener).onResolveFailed(ns, message.arg1);
+                    executor.execute(() -> ((ResolveListener) listener).onResolveFailed(
+                            ns, message.arg1));
                     break;
                 case RESOLVE_SERVICE_SUCCEEDED:
                     removeListener(key);
-                    ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj);
+                    executor.execute(() -> ((ResolveListener) listener).onServiceResolved(
+                            (NsdServiceInfo) message.obj));
                     break;
                 default:
                     Log.d(TAG, "Ignored " + message);
@@ -722,7 +740,7 @@
     }
 
     // Assert that the listener is not in the map, then add it and returns its key
-    private int putListener(Object listener, NsdServiceInfo s) {
+    private int putListener(Object listener, Executor e, NsdServiceInfo s) {
         checkListener(listener);
         final int key;
         synchronized (mMapLock) {
@@ -733,6 +751,7 @@
             key = nextListenerKey();
             mListenerMap.put(key, listener);
             mServiceMap.put(key, s);
+            mExecutorMap.put(key, e);
         }
         return key;
     }
@@ -741,6 +760,7 @@
         synchronized (mMapLock) {
             mListenerMap.remove(key);
             mServiceMap.remove(key);
+            mExecutorMap.remove(key);
         }
     }
 
@@ -779,12 +799,33 @@
      */
     public void registerService(NsdServiceInfo serviceInfo, int protocolType,
             RegistrationListener listener) {
+        registerService(serviceInfo, protocolType, Runnable::run, listener);
+    }
+
+    /**
+     * Register a service to be discovered by other services.
+     *
+     * <p> The function call immediately returns after sending a request to register service
+     * to the framework. The application is notified of a successful registration
+     * through the callback {@link RegistrationListener#onServiceRegistered} or a failure
+     * through {@link RegistrationListener#onRegistrationFailed}.
+     *
+     * <p> The application should call {@link #unregisterService} when the service
+     * registration is no longer required, and/or whenever the application is stopped.
+     * @param serviceInfo The service being registered
+     * @param protocolType The service discovery protocol
+     * @param executor Executor to run listener callbacks with
+     * @param listener The listener notifies of a successful registration and is used to
+     * unregister this service through a call on {@link #unregisterService}. Cannot be null.
+     */
+    public void registerService(@NonNull NsdServiceInfo serviceInfo, int protocolType,
+            @NonNull Executor executor, @NonNull RegistrationListener listener) {
         if (serviceInfo.getPort() <= 0) {
             throw new IllegalArgumentException("Invalid port number");
         }
         checkServiceInfo(serviceInfo);
         checkProtocol(protocolType);
-        int key = putListener(listener, serviceInfo);
+        int key = putListener(listener, executor, serviceInfo);
         try {
             mService.registerService(key, serviceInfo);
         } catch (RemoteException e) {
@@ -815,14 +856,6 @@
     }
 
     /**
-     * Same as {@link #discoverServices(String, int, Network, DiscoveryListener)} with a null
-     * {@link Network}.
-     */
-    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
-        discoverServices(serviceType, protocolType, (Network) null, listener);
-    }
-
-    /**
      * Initiate service discovery to browse for instances of a service type. Service discovery
      * consumes network bandwidth and will continue until the application calls
      * {@link #stopServiceDiscovery}.
@@ -846,13 +879,45 @@
      * @param serviceType The service type being discovered. Examples include "_http._tcp" for
      * http services or "_ipp._tcp" for printers
      * @param protocolType The service discovery protocol
-     * @param network Network to discover services on, or null to discover on all available networks
      * @param listener  The listener notifies of a successful discovery and is used
      * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
      * Cannot be null. Cannot be in use for an active service discovery.
      */
+    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
+        discoverServices(serviceType, protocolType, (Network) null, Runnable::run, listener);
+    }
+
+    /**
+     * Initiate service discovery to browse for instances of a service type. Service discovery
+     * consumes network bandwidth and will continue until the application calls
+     * {@link #stopServiceDiscovery}.
+     *
+     * <p> The function call immediately returns after sending a request to start service
+     * discovery to the framework. The application is notified of a success to initiate
+     * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure
+     * through {@link DiscoveryListener#onStartDiscoveryFailed}.
+     *
+     * <p> Upon successful start, application is notified when a service is found with
+     * {@link DiscoveryListener#onServiceFound} or when a service is lost with
+     * {@link DiscoveryListener#onServiceLost}.
+     *
+     * <p> Upon failure to start, service discovery is not active and application does
+     * not need to invoke {@link #stopServiceDiscovery}
+     *
+     * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
+     * service type is no longer required, and/or whenever the application is paused or
+     * stopped.
+     * @param serviceType The service type being discovered. Examples include "_http._tcp" for
+     * http services or "_ipp._tcp" for printers
+     * @param protocolType The service discovery protocol
+     * @param network Network to discover services on, or null to discover on all available networks
+     * @param executor Executor to run listener callbacks with
+     * @param listener  The listener notifies of a successful discovery and is used
+     * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
+     */
     public void discoverServices(@NonNull String serviceType, int protocolType,
-            @Nullable Network network, @NonNull DiscoveryListener listener) {
+            @Nullable Network network, @NonNull Executor executor,
+            @NonNull DiscoveryListener listener) {
         if (TextUtils.isEmpty(serviceType)) {
             throw new IllegalArgumentException("Service type cannot be empty");
         }
@@ -862,7 +927,7 @@
         s.setServiceType(serviceType);
         s.setNetwork(network);
 
-        int key = putListener(listener, s);
+        int key = putListener(listener, executor, s);
         try {
             mService.discoverServices(key, s);
         } catch (RemoteException e) {
@@ -899,18 +964,18 @@
      * themselves are encouraged to use this method instead of other overloads of
      * {@code discoverServices}, as they will receive proper notifications when a service becomes
      * available or unavailable due to network changes.
-     *
      * @param serviceType The service type being discovered. Examples include "_http._tcp" for
      * http services or "_ipp._tcp" for printers
      * @param protocolType The service discovery protocol
      * @param networkRequest Request specifying networks that should be considered when discovering
+     * @param executor Executor to run listener callbacks with
      * @param listener  The listener notifies of a successful discovery and is used
      * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
-     * Cannot be null. Cannot be in use for an active service discovery.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public void discoverServices(@NonNull String serviceType, int protocolType,
-            @NonNull NetworkRequest networkRequest, @NonNull DiscoveryListener listener) {
+            @NonNull NetworkRequest networkRequest, @NonNull Executor executor,
+            @NonNull DiscoveryListener listener) {
         if (TextUtils.isEmpty(serviceType)) {
             throw new IllegalArgumentException("Service type cannot be empty");
         }
@@ -920,10 +985,10 @@
         NsdServiceInfo s = new NsdServiceInfo();
         s.setServiceType(serviceType);
 
-        final int baseListenerKey = putListener(listener, s);
+        final int baseListenerKey = putListener(listener, executor, s);
 
         final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker(
-                serviceType, protocolType, listener);
+                serviceType, protocolType, executor, listener);
 
         synchronized (mPerNetworkDiscoveryMap) {
             mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo);
@@ -974,8 +1039,21 @@
      * Cannot be in use for an active service resolution.
      */
     public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) {
+        resolveService(serviceInfo, Runnable::run, listener);
+    }
+
+    /**
+     * Resolve a discovered service. An application can resolve a service right before
+     * establishing a connection to fetch the IP and port details on which to setup
+     * the connection.
+     * @param serviceInfo service to be resolved
+     * @param executor Executor to run listener callbacks with
+     * @param listener to receive callback upon success or failure.
+     */
+    public void resolveService(@NonNull NsdServiceInfo serviceInfo,
+            @NonNull Executor executor, @NonNull ResolveListener listener) {
         checkServiceInfo(serviceInfo);
-        int key = putListener(listener, serviceInfo);
+        int key = putListener(listener, executor, serviceInfo);
         try {
             mService.resolveService(key, serviceInfo);
         } catch (RemoteException e) {
diff --git a/service-t/Sources.bp b/service-t/Sources.bp
index 5100e7c..4b799c5 100644
--- a/service-t/Sources.bp
+++ b/service-t/Sources.bp
@@ -102,17 +102,16 @@
     ],
     path: "src",
     visibility: [
-        "//frameworks/opt/net/ethernet",
+        "//frameworks/opt/net/ethernet/tests",
     ],
 }
 
 // Connectivity-T common libraries.
 
+// TODO: remove this empty filegroup.
 filegroup {
     name: "services.connectivity-tiramisu-sources",
-    srcs: [
-        ":services.connectivity-ethernet-sources",
-    ],
+    srcs: [],
     path: "src",
     visibility: ["//frameworks/base/services/core"],
 }
@@ -120,6 +119,7 @@
 filegroup {
     name: "services.connectivity-tiramisu-updatable-sources",
     srcs: [
+        ":services.connectivity-ethernet-sources",
         ":services.connectivity-ipsec-sources",
         ":services.connectivity-netstats-sources",
         ":services.connectivity-nsd-sources",
diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java
index 151c90d..3b93f1a 100644
--- a/service-t/src/com/android/server/net/NetworkStatsFactory.java
+++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java
@@ -25,9 +25,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.net.NetworkStats;
 import android.net.UnderlyingNetworkInfo;
+import android.os.ServiceSpecificException;
 import android.os.StrictMode;
 import android.os.SystemClock;
 
@@ -35,6 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ProcFileReader;
 import com.android.net.module.util.CollectionUtils;
+import com.android.server.BpfNetMaps;
 
 import libcore.io.IoUtils;
 
@@ -74,6 +75,8 @@
 
     private final Context mContext;
 
+    private final BpfNetMaps mBpfNetMaps;
+
     /**
      * Guards persistent data access in this class
      *
@@ -170,6 +173,7 @@
         mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
         mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
         mUseBpfStats = useBpfStats;
+        mBpfNetMaps = new BpfNetMaps();
         synchronized (mPersistentDataLock) {
             mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
             mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
@@ -297,12 +301,14 @@
     }
 
     @GuardedBy("mPersistentDataLock")
-    private void requestSwapActiveStatsMapLocked() {
-        // Do a active map stats swap. When the binder call successfully returns,
-        // the system server should be able to safely read and clean the inactive map
-        // without race problem.
-        final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
-        cm.swapActiveStatsMap();
+    private void requestSwapActiveStatsMapLocked() throws IOException {
+        try {
+            // Do a active map stats swap. Once the swap completes, this code
+            // can read and clean the inactive map without races.
+            mBpfNetMaps.swapActiveStatsMap();
+        } catch (ServiceSpecificException e) {
+            throw new IOException(e);
+        }
     }
 
     /**
@@ -328,11 +334,7 @@
                 final NetworkStats stats =
                         new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */);
                 if (mUseBpfStats) {
-                    try {
-                        requestSwapActiveStatsMapLocked();
-                    } catch (RuntimeException e) {
-                        throw new IOException(e);
-                    }
+                    requestSwapActiveStatsMapLocked();
                     // Stats are always read from the inactive map, so they must be read after the
                     // swap
                     if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java
index 1953624..fdfc893 100644
--- a/service-t/src/com/android/server/net/NetworkStatsObservers.java
+++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java
@@ -19,8 +19,11 @@
 import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES;
 
 import android.app.usage.NetworkStatsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.DataUsageRequest;
 import android.net.NetworkIdentitySet;
+import android.net.NetworkStack;
 import android.net.NetworkStats;
 import android.net.NetworkStatsAccess;
 import android.net.NetworkStatsCollection;
@@ -74,9 +77,9 @@
      *
      * @return the normalized request wrapped within {@link RequestInfo}.
      */
-    public DataUsageRequest register(DataUsageRequest inputRequest, IUsageCallback callback,
-            int callingUid, @NetworkStatsAccess.Level int accessLevel) {
-        DataUsageRequest request = buildRequest(inputRequest, callingUid);
+    public DataUsageRequest register(Context context, DataUsageRequest inputRequest,
+            IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) {
+        DataUsageRequest request = buildRequest(context, inputRequest, callingUid);
         RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid,
                 accessLevel);
 
@@ -194,10 +197,13 @@
         }
     }
 
-    private DataUsageRequest buildRequest(DataUsageRequest request, int callingUid) {
-        // For non-system uid, cap the minimum threshold to a safe default to avoid too
-        // many callbacks.
-        long thresholdInBytes = (callingUid == Process.SYSTEM_UID ? request.thresholdInBytes
+    private DataUsageRequest buildRequest(Context context, DataUsageRequest request,
+                int callingUid) {
+        // For non-NETWORK_STACK permission uid, cap the minimum threshold to a safe default to
+        // avoid too many callbacks.
+        final long thresholdInBytes = (context.checkPermission(
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Process.myPid(), callingUid)
+                == PackageManager.PERMISSION_GRANTED ? request.thresholdInBytes
                 : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes));
         if (thresholdInBytes > request.thresholdInBytes) {
             Log.w(TAG, "Threshold was too low for " + request
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 1f63c3a..e3794e4 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -565,7 +565,7 @@
                 return new BpfMap<U32, U8>(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR,
                         U32.class, U8.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create uid counter set map: " + e);
+                Log.wtf(TAG, "Cannot open uid counter set map: " + e);
                 return null;
             }
         }
@@ -576,7 +576,7 @@
                 return new BpfMap<CookieTagMapKey, CookieTagMapValue>(COOKIE_TAG_MAP_PATH,
                         BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create cookie tag map: " + e);
+                Log.wtf(TAG, "Cannot open cookie tag map: " + e);
                 return null;
             }
         }
@@ -587,7 +587,7 @@
                 return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_A_PATH,
                         BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create stats map A: " + e);
+                Log.wtf(TAG, "Cannot open stats map A: " + e);
                 return null;
             }
         }
@@ -598,7 +598,7 @@
                 return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_B_PATH,
                         BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create stats map B: " + e);
+                Log.wtf(TAG, "Cannot open stats map B: " + e);
                 return null;
             }
         }
@@ -609,7 +609,7 @@
                 return new BpfMap<UidStatsMapKey, StatsMapValue>(APP_UID_STATS_MAP_PATH,
                         BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create app uid stats map: " + e);
+                Log.wtf(TAG, "Cannot open app uid stats map: " + e);
                 return null;
             }
         }
@@ -1123,7 +1123,7 @@
 
     @Override
     public NetworkStats getUidStatsForTransport(int transport) {
-        enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+        PermissionUtils.enforceNetworkStackPermission(mContext);
         try {
             final String[] relevantIfaces =
                     transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces;
@@ -1194,7 +1194,7 @@
     }
 
     @VisibleForTesting
-    public void setUidForeground(int uid, boolean uidForeground) {
+    public void noteUidForeground(int uid, boolean uidForeground) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
         synchronized (mStatsLock) {
             final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
@@ -1285,7 +1285,7 @@
         DataUsageRequest normalizedRequest;
         final long token = Binder.clearCallingIdentity();
         try {
-            normalizedRequest = mStatsObservers.register(
+            normalizedRequest = mStatsObservers.register(mContext,
                     request, callback, callingUid, accessLevel);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -1540,10 +1540,15 @@
                         NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) {
 
                     // Copy the identify from IMS one but mark it as metered.
-                    NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
-                            ident.getRatType(), ident.getSubscriberId(), ident.getWifiNetworkKey(),
-                            ident.isRoaming(), true /* metered */,
-                            true /* onDefaultNetwork */, ident.getOemManaged());
+                    NetworkIdentity vtIdent = new NetworkIdentity.Builder()
+                            .setType(ident.getType())
+                            .setRatType(ident.getRatType())
+                            .setSubscriberId(ident.getSubscriberId())
+                            .setWifiNetworkKey(ident.getWifiNetworkKey())
+                            .setRoaming(ident.isRoaming()).setMetered(true)
+                            .setDefaultNetwork(true)
+                            .setOemManaged(ident.getOemManaged())
+                            .setSubId(ident.getSubId()).build();
                     final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot);
                     findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent);
                     findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent);
@@ -2388,10 +2393,17 @@
         }
 
         @Override
-        public void notifyWarningOrLimitReached() {
-            Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
+        public void notifyWarningReached() {
+            Log.d(TAG, mTag + ": notifyWarningReached");
             BinderUtils.withCleanCallingIdentity(() ->
-                    mNetworkPolicyManager.notifyStatsProviderWarningOrLimitReached());
+                    mNetworkPolicyManager.notifyStatsProviderWarningReached());
+        }
+
+        @Override
+        public void notifyLimitReached() {
+            Log.d(TAG, mTag + ": notifyLimitReached");
+            BinderUtils.withCleanCallingIdentity(() ->
+                    mNetworkPolicyManager.notifyStatsProviderLimitReached());
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/tests/unit/java/com/android/server/net/IpConfigStoreTest.java
similarity index 92%
rename from services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java
rename to tests/unit/java/com/android/server/net/IpConfigStoreTest.java
index 2f77126..ad0be58 100644
--- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java
+++ b/tests/unit/java/com/android/server/net/IpConfigStoreTest.java
@@ -48,10 +48,16 @@
  */
 @RunWith(AndroidJUnit4.class)
 public class IpConfigStoreTest {
+    private static final int KEY_CONFIG = 17;
+    private static final String IFACE_1 = "eth0";
+    private static final String IFACE_2 = "eth1";
+    private static final String IP_ADDR_1 = "192.168.1.10/24";
+    private static final String IP_ADDR_2 = "192.168.1.20/24";
+    private static final String DNS_IP_ADDR_1 = "1.2.3.4";
+    private static final String DNS_IP_ADDR_2 = "5.6.7.8";
 
     @Test
     public void backwardCompatibility2to3() throws IOException {
-        final int KEY_CONFIG = 17;
         ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
         DataOutputStream outputStream = new DataOutputStream(byteStream);
 
@@ -73,13 +79,6 @@
 
     @Test
     public void staticIpMultiNetworks() throws Exception {
-        final String IFACE_1 = "eth0";
-        final String IFACE_2 = "eth1";
-        final String IP_ADDR_1 = "192.168.1.10/24";
-        final String IP_ADDR_2 = "192.168.1.20/24";
-        final String DNS_IP_ADDR_1 = "1.2.3.4";
-        final String DNS_IP_ADDR_2 = "5.6.7.8";
-
         final ArrayList<InetAddress> dnsServers = new ArrayList<>();
         dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1));
         dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2));
@@ -144,11 +143,11 @@
 
     /** Synchronously writes into given byte steam */
     private static class MockedDelayedDiskWrite extends DelayedDiskWrite {
-        final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+        final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream();
 
         @Override
         public void write(String filePath, Writer w) {
-            DataOutputStream outputStream = new DataOutputStream(byteStream);
+            DataOutputStream outputStream = new DataOutputStream(mByteStream);
 
             try {
                 w.onWriteCalled(outputStream);