Add a NetworkAgent API to indicate that a network will be replaced.

This is useful for link layers that disconnect but know they will
reconnect to a similar network soon, and do not want the device
to switch to another network until the reconnect happens. An
example is wifi switching to another network that is on a
different subnet without the device switching to cellular data.

This works by immediately destroying the network, so the link
layer can reuse the same interface name for the new network. It
would be possible to delay destroying the network until the new
network connects, but in practice this does not seem useful,
because the if the link layer reuses the interface, then the
interface will be undergoing reconfiguration, and will likely
not be usable for app traffic.

This CL also moves the call to onNetworkDestroyed into
destroyNativeNetwork. This is needed to ensure that the new
API calls onNetworkDestroyed even though most teardown
operations have not happened. This causes onNetworkDestroyed to
happen before the netId is marked free, but that shouldn't cause
any behavioural changes because netId allocation is an
implementation detail of ConnectivityService and is not
observable by apps or system components.

Bug: 216567577
Test: builds, boots
Test: atest FrameworksNetTests FrameworksNetIntegrationTests
Test: atest CtsNetTestCases:android.net.cts.ConnectivityManagerTest
Test: atest CtsNetTestCases:android.net.cts.NetworkAgentTest#testDestroyAndAwaitReplacement
Change-Id: I9f9e022fef66b31a29cce560413321075e992756
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 764cffa..bdefed1 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -236,6 +236,7 @@
   public abstract class NetworkAgent {
     ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
     ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+    method public void destroyAndAwaitReplacement(@IntRange(from=0, to=0x1388) int);
     method @Nullable public android.net.Network getNetwork();
     method public void markConnected();
     method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
diff --git a/framework/src/android/net/INetworkAgentRegistry.aidl b/framework/src/android/net/INetworkAgentRegistry.aidl
index 08536ca..2b22a5c 100644
--- a/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -47,4 +47,5 @@
     void sendAddDscpPolicy(in DscpPolicy policy);
     void sendRemoveDscpPolicy(int policyId);
     void sendRemoveAllDscpPolicies();
+    void sendDestroyAndAwaitReplacement(int timeoutMillis);
 }
diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java
index 945e670..fdc9081 100644
--- a/framework/src/android/net/NetworkAgent.java
+++ b/framework/src/android/net/NetworkAgent.java
@@ -434,6 +434,14 @@
      */
     public static final int CMD_DSCP_POLICY_STATUS = BASE + 28;
 
+    /**
+     * Sent by the NetworkAgent to ConnectivityService to notify that this network is expected to be
+     * replaced within the specified time by a similar network.
+     * arg1 = timeout in milliseconds
+     * @hide
+     */
+    public static final int EVENT_DESTROY_AND_AWAIT_REPLACEMENT = BASE + 29;
+
     private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
         final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
                 config.legacyTypeName, config.legacySubTypeName);
@@ -943,6 +951,45 @@
     }
 
     /**
+     * Indicates that this agent will likely soon be replaced by another agent for a very similar
+     * network (e.g., same Wi-Fi SSID).
+     *
+     * If the network is not currently satisfying any {@link NetworkRequest}s, it will be torn down.
+     * If it is satisfying requests, then the native network corresponding to the agent will be
+     * destroyed immediately, but the agent will remain registered and will continue to satisfy
+     * requests until {@link #unregister} is called, the network is replaced by an equivalent or
+     * better network, or the specified timeout expires. During this time:
+     *
+     * <ul>
+     * <li>The agent may not send any further updates, for example by calling methods
+     *    such as {@link #sendNetworkCapabilities}, {@link #sendLinkProperties},
+     *    {@link #sendNetworkScore(NetworkScore)} and so on. Any such updates will be ignored.
+     * <li>The network will remain connected and continue to satisfy any requests that it would
+     *    otherwise satisfy (including, possibly, the default request).
+     * <li>The validation state of the network will not change, and calls to
+     *    {@link ConnectivityManager#reportNetworkConnectivity(Network, boolean)} will be ignored.
+     * </ul>
+     *
+     * Once this method is called, it is not possible to restore the agent to a functioning state.
+     * If a replacement network becomes available, then a new agent must be registered. When that
+     * replacement network is fully capable of replacing this network (including, possibly, being
+     * validated), this agent will no longer be needed and will be torn down. Otherwise, this agent
+     * can be disconnected by calling {@link #unregister}. If {@link #unregister} is not called,
+     * this agent will automatically be unregistered when the specified timeout expires. Any
+     * teardown delay previously set using{@link #setTeardownDelayMillis} is ignored.
+     *
+     * <p>This method has no effect if {@link #markConnected} has not yet been called.
+     * <p>This method may only be called once.
+     *
+     * @param timeoutMillis the timeout after which this network will be unregistered even if
+     *                      {@link #unregister} was not called.
+     */
+    public void destroyAndAwaitReplacement(
+            @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int timeoutMillis) {
+        queueOrSendMessage(reg -> reg.sendDestroyAndAwaitReplacement(timeoutMillis));
+    }
+
+    /**
      * Change the legacy subtype of this network agent.
      *
      * This is only for backward compatibility and should not be used by non-legacy network agents,