Add getAvoidBadWifi system API

This helps remove the dependency on MultinetworkPolicyTracker from
IpClient.

Test: atest FrameworksNetTests NetworkStackTests
Bug: 112869080
Change-Id: If56791dbed564772f25a859f301b8b52d84e38a3
diff --git a/api/system-current.txt b/api/system-current.txt
index 7cade61..0aad688 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3031,6 +3031,7 @@
   }
 
   public class ConnectivityManager {
+    method public boolean getAvoidBadWifi();
     method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
     method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index cee3a40..c809cca 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3699,6 +3699,19 @@
     }
 
     /**
+     * Determine whether the device is configured to avoid bad wifi.
+     * @hide
+     */
+    @SystemApi
+    public boolean getAvoidBadWifi() {
+        try {
+            return mService.getAvoidBadWifi();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * It is acceptable to briefly use multipath data to provide seamless connectivity for
      * time-sensitive user-facing operations when the system default network is temporarily
      * unresponsive. The amount of data should be limited (less than one megabyte for every call to
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 3d34574..131925e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -165,6 +165,7 @@
     void setAvoidUnvalidated(in Network network);
     void startCaptivePortalApp(in Network network);
 
+    boolean getAvoidBadWifi();
     int getMultipathPreference(in Network Network);
 
     NetworkRequest getDefaultRequest();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 919a5ab..fae7a8d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3183,6 +3183,15 @@
         return mMultinetworkPolicyTracker.getAvoidBadWifi();
     }
 
+    @Override
+    public boolean getAvoidBadWifi() {
+        if (!checkNetworkStackPermission()) {
+            throw new SecurityException("avoidBadWifi requires NETWORK_STACK permission");
+        }
+        return avoidBadWifi();
+    }
+
+
     private void rematchForAvoidBadWifiUpdate() {
         rematchAllNetworksAndRequests(null, 0);
         for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 8187ac5..233b86f 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -19,6 +19,7 @@
 import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
 
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.DhcpResults;
 import android.net.INetd;
 import android.net.IpPrefix;
@@ -37,7 +38,6 @@
 import android.net.metrics.IpManagerEvent;
 import android.net.shared.InitialConfiguration;
 import android.net.util.InterfaceParams;
-import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
 import android.net.util.SharedLog;
 import android.os.ConditionVariable;
@@ -391,6 +391,7 @@
     protected final IpClientCallbacks mCallback;
     private final Dependencies mDependencies;
     private final CountDownLatch mShutdownLatch;
+    private final ConnectivityManager mCm;
     private final INetworkManagementService mNwService;
     private final NetlinkTracker mNetlinkTracker;
     private final WakeupMessage mProvisioningTimeoutAlarm;
@@ -408,7 +409,6 @@
      */
     private LinkProperties mLinkProperties;
     private android.net.shared.ProvisioningConfiguration mConfiguration;
-    private MultinetworkPolicyTracker mMultinetworkPolicyTracker;
     private IpReachabilityMonitor mIpReachabilityMonitor;
     private DhcpClient mDhcpClient;
     private DhcpResults mDhcpResults;
@@ -476,6 +476,7 @@
         mCallback = new LoggingCallbackWrapper(callback);
         mDependencies = deps;
         mShutdownLatch = new CountDownLatch(1);
+        mCm = mContext.getSystemService(ConnectivityManager.class);
         mNwService = deps.getNMS();
 
         sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
@@ -961,8 +962,9 @@
         // Note that we can still be disconnected by IpReachabilityMonitor
         // if the IPv6 default gateway (but not the IPv6 DNS servers; see
         // accompanying code in IpReachabilityMonitor) is unreachable.
-        final boolean ignoreIPv6ProvisioningLoss = (mMultinetworkPolicyTracker != null)
-                && !mMultinetworkPolicyTracker.getAvoidBadWifi();
+        final boolean ignoreIPv6ProvisioningLoss =
+                mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
+                && mCm.getAvoidBadWifi();
 
         // Additionally:
         //
@@ -1253,7 +1255,7 @@
                             mCallback.onReachabilityLost(logMsg);
                         }
                     },
-                    mMultinetworkPolicyTracker);
+                    mConfiguration.mUsingMultinetworkPolicyTracker);
         } catch (IllegalArgumentException iae) {
             // Failed to start IpReachabilityMonitor. Log it and call
             // onProvisioningFailure() immediately.
@@ -1486,13 +1488,6 @@
                 return;
             }
 
-            if (mConfiguration.mUsingMultinetworkPolicyTracker) {
-                mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(
-                        mContext, getHandler(),
-                        () -> mLog.log("OBSERVED AvoidBadWifi changed"));
-                mMultinetworkPolicyTracker.start();
-            }
-
             if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
                 doImmediateProvisioningFailure(
                         IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
@@ -1510,11 +1505,6 @@
                 mIpReachabilityMonitor = null;
             }
 
-            if (mMultinetworkPolicyTracker != null) {
-                mMultinetworkPolicyTracker.shutdown();
-                mMultinetworkPolicyTracker = null;
-            }
-
             if (mDhcpClient != null) {
                 mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
                 mDhcpClient.doQuit();
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 29e2f0c..761db68 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -22,6 +22,7 @@
 import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST_ORGANIC;
 
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.LinkProperties;
 import android.net.RouteInfo;
 import android.net.ip.IpNeighborMonitor.NeighborEvent;
@@ -29,7 +30,6 @@
 import android.net.metrics.IpReachabilityEvent;
 import android.net.netlink.StructNdMsg;
 import android.net.util.InterfaceParams;
-import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.SharedLog;
 import android.os.Handler;
 import android.os.PowerManager;
@@ -165,7 +165,8 @@
     private final SharedLog mLog;
     private final Callback mCallback;
     private final Dependencies mDependencies;
-    private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
+    private final boolean mUsingMultinetworkPolicyTracker;
+    private final ConnectivityManager mCm;
     private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
     private LinkProperties mLinkProperties = new LinkProperties();
     private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
@@ -174,19 +175,21 @@
 
     public IpReachabilityMonitor(
             Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
-            MultinetworkPolicyTracker tracker) {
-        this(ifParams, h, log, callback, tracker, Dependencies.makeDefault(context, ifParams.name));
+            boolean usingMultinetworkPolicyTracker) {
+        this(context, ifParams, h, log, callback, usingMultinetworkPolicyTracker,
+                Dependencies.makeDefault(context, ifParams.name));
     }
 
     @VisibleForTesting
-    IpReachabilityMonitor(InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
-            MultinetworkPolicyTracker tracker, Dependencies dependencies) {
+    IpReachabilityMonitor(Context context, InterfaceParams ifParams, Handler h, SharedLog log,
+            Callback callback, boolean usingMultinetworkPolicyTracker, Dependencies dependencies) {
         if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
 
         mInterfaceParams = ifParams;
         mLog = log.forSubComponent(TAG);
         mCallback = callback;
-        mMultinetworkPolicyTracker = tracker;
+        mUsingMultinetworkPolicyTracker = usingMultinetworkPolicyTracker;
+        mCm = context.getSystemService(ConnectivityManager.class);
         mDependencies = dependencies;
 
         mIpNeighborMonitor = new IpNeighborMonitor(h, mLog,
@@ -324,7 +327,7 @@
     }
 
     private boolean avoidingBadLinks() {
-        return (mMultinetworkPolicyTracker == null) || mMultinetworkPolicyTracker.getAvoidBadWifi();
+        return !mUsingMultinetworkPolicyTracker || mCm.getAvoidBadWifi();
     }
 
     public void probeAll() {
diff --git a/tests/net/java/android/net/ip/IpClientTest.java b/tests/net/java/android/net/ip/IpClientTest.java
index 7a83757..5110ce1 100644
--- a/tests/net/java/android/net/ip/IpClientTest.java
+++ b/tests/net/java/android/net/ip/IpClientTest.java
@@ -33,6 +33,7 @@
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.res.Resources;
+import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
@@ -82,6 +83,7 @@
     private static final int TEST_TIMEOUT_MS = 400;
 
     @Mock private Context mContext;
+    @Mock private ConnectivityManager mCm;
     @Mock private INetworkManagementService mNMService;
     @Mock private INetd mNetd;
     @Mock private Resources mResources;
@@ -98,6 +100,9 @@
         MockitoAnnotations.initMocks(this);
 
         when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
+        when(mContext.getSystemServiceName(ConnectivityManager.class))
+                .thenReturn(Context.CONNECTIVITY_SERVICE);
+        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
         when(mContext.getResources()).thenReturn(mResources);
         when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
                 .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
index e65585f..e3b5ddf 100644
--- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
+++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
@@ -16,11 +16,10 @@
 
 package android.net.ip;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.when;
 
+import android.content.Context;
 import android.net.util.InterfaceParams;
 import android.net.util.SharedLog;
 import android.os.Handler;
@@ -45,6 +44,7 @@
     @Mock IpReachabilityMonitor.Callback mCallback;
     @Mock IpReachabilityMonitor.Dependencies mDependencies;
     @Mock SharedLog mLog;
+    @Mock Context mContext;
     Handler mHandler;
 
     @Before
@@ -56,7 +56,8 @@
 
     IpReachabilityMonitor makeMonitor() {
         final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null);
-        return new IpReachabilityMonitor(ifParams, mHandler, mLog, mCallback, null, mDependencies);
+        return new IpReachabilityMonitor(
+                mContext, ifParams, mHandler, mLog, mCallback, false, mDependencies);
     }
 
     @Test