diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java index cedffe15cf..604afc3ba0 100644 --- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java @@ -293,7 +293,7 @@ public class EthernetNetworkFactory { private final Context mContext; private final NetworkProvider mNetworkProvider; private final Dependencies mDeps; - private final NetworkProvider.NetworkOfferCallback mNetworkOfferCallback; + private NetworkProvider.NetworkOfferCallback mNetworkOfferCallback; private static String sTcpBufferSizes = null; // Lazy initialized. @@ -400,8 +400,15 @@ public class EthernetNetworkFactory { } private class EthernetNetworkOfferCallback implements NetworkProvider.NetworkOfferCallback { + private boolean isStale() { + return this != mNetworkOfferCallback; + } + @Override public void onNetworkNeeded(@NonNull NetworkRequest request) { + if (isStale()) { + return; + } if (DBG) { Log.d(TAG, String.format("%s: onNetworkNeeded for request: %s", name, request)); } @@ -416,6 +423,9 @@ public class EthernetNetworkFactory { @Override public void onNetworkUnneeded(@NonNull NetworkRequest request) { + if (isStale()) { + return; + } if (DBG) { Log.d(TAG, String.format("%s: onNetworkUnneeded for request: %s", name, request)); @@ -443,7 +453,6 @@ public class EthernetNetworkFactory { mContext = context; mNetworkProvider = networkProvider; mDeps = deps; - mNetworkOfferCallback = new EthernetNetworkOfferCallback(); mHwAddress = hwAddress; } @@ -669,13 +678,21 @@ public class EthernetNetworkFactory { } private void registerNetworkOffer() { + // If mNetworkOfferCallback is already set, it should be reused to update the existing + // offer. + if (mNetworkOfferCallback == null) { + mNetworkOfferCallback = new EthernetNetworkOfferCallback(); + } mNetworkProvider.registerNetworkOffer(getNetworkScore(), new NetworkCapabilities(mCapabilities), cmd -> mHandler.post(cmd), mNetworkOfferCallback); } - public void unregisterNetworkOfferAndStop() { + private void unregisterNetworkOfferAndStop() { mNetworkProvider.unregisterNetworkOffer(mNetworkOfferCallback); + // Setting mNetworkOfferCallback to null allows the callback object to be identified + // as stale. + mNetworkOfferCallback = null; stop(); mRequestIds.clear(); } diff --git a/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java index 2178b33727..8a18ee75ee 100644 --- a/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java +++ b/tests/unit/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java @@ -726,4 +726,16 @@ public class EthernetNetworkFactoryTest { triggerOnProvisioningSuccess(); verifyRestart(initialIpConfig); } + + @Test + public void testOnNetworkNeededOnStaleNetworkOffer() throws Exception { + initEthernetNetworkFactory(); + createAndVerifyProvisionedInterface(TEST_IFACE); + mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, null); + verify(mNetworkProvider).unregisterNetworkOffer(mNetworkOfferCallback); + // It is possible that even after a network offer is unregistered, CS still sends it + // onNetworkNeeded() callbacks. + mNetworkOfferCallback.onNetworkNeeded(createDefaultRequest()); + verify(mIpClient, never()).startProvisioning(any()); + } }