NetworkProvider: Do not propagate callbacks for unregistered offers

Previously, after calling unregisterNetworkOffer(), onNetworkNeeded() /
onNetworkUnneeded callbacks are still being called until CS's handler
thread has finished running. While this behavior could be taken care of
in the network provider implemention (e.g. the ethernet service), it is
much simpler to deal with in NetworkProvider.java.

As NetworkProvider.java wraps the passed callback object inside a proxy
that it forwards to CS, it should be as simple as adding a boolean to
the proxy that is checked inside the executor thread before the
implementation's callback is called. Since for every call to
registerNetworkOffer() with a new callback object a new proxy object is
created, this should be safe. Even if the callback object is reused on
the user side (such as ethernet service does right now), this should be
okay, as the implementation will only receive callbacks from the active
proxy.

Test: atest NetworkProviderTest
Bug: 171872016
Change-Id: Iaf84b5801ad3ee44895e933763927151ea5824dd
diff --git a/framework/src/android/net/NetworkProvider.java b/framework/src/android/net/NetworkProvider.java
index 4dd642e..3615075 100644
--- a/framework/src/android/net/NetworkProvider.java
+++ b/framework/src/android/net/NetworkProvider.java
@@ -192,21 +192,36 @@
     private class NetworkOfferCallbackProxy extends INetworkOfferCallback.Stub {
         @NonNull public final NetworkOfferCallback callback;
         @NonNull private final Executor mExecutor;
+        /**
+         * Boolean flag that prevents onNetworkNeeded / onNetworkUnneeded callbacks from being
+         * propagated after unregisterNetworkOffer has been called. Since unregisterNetworkOffer
+         * runs on the CS handler thread, it will not go into effect immediately.
+         */
+        private volatile boolean mIsStale;
 
         NetworkOfferCallbackProxy(@NonNull final NetworkOfferCallback callback,
                 @NonNull final Executor executor) {
             this.callback = callback;
             this.mExecutor = executor;
+            this.mIsStale = false;
         }
 
         @Override
         public void onNetworkNeeded(final @NonNull NetworkRequest request) {
-            mExecutor.execute(() -> callback.onNetworkNeeded(request));
+            mExecutor.execute(() -> {
+                if (!mIsStale) callback.onNetworkNeeded(request);
+            });
         }
 
         @Override
         public void onNetworkUnneeded(final @NonNull NetworkRequest request) {
-            mExecutor.execute(() -> callback.onNetworkUnneeded(request));
+            mExecutor.execute(() -> {
+                if (!mIsStale) callback.onNetworkUnneeded(request);
+            });
+        }
+
+        public void markStale() {
+            mIsStale = true;
         }
     }
 
@@ -327,6 +342,7 @@
         final NetworkOfferCallbackProxy proxy = findProxyForCallback(callback);
         if (null == proxy) return;
         synchronized (mProxies) {
+            proxy.markStale();
             mProxies.remove(proxy);
         }
         mContext.getSystemService(ConnectivityManager.class).unofferNetwork(proxy);