diff options
-rw-r--r-- | src/android/net/ip/IpClientLinkObserver.java | 17 | ||||
-rw-r--r-- | tests/integration/src/android/net/ip/IpClientIntegrationTest.java | 19 |
2 files changed, 32 insertions, 4 deletions
diff --git a/src/android/net/ip/IpClientLinkObserver.java b/src/android/net/ip/IpClientLinkObserver.java index dc58e7b..ee7f18b 100644 --- a/src/android/net/ip/IpClientLinkObserver.java +++ b/src/android/net/ip/IpClientLinkObserver.java @@ -238,6 +238,7 @@ public class IpClientLinkObserver implements NetworkObserver { // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in // mLinkProperties, as desired. mDnsServerRepository = new DnsServerRepository(mConfig.minRdnssLifetime); + mNetlinkMonitor.clearAlarms(); mLinkProperties.clear(); mLinkProperties.setInterfaceName(mInterfaceName); } @@ -281,18 +282,27 @@ public class IpClientLinkObserver implements NetworkObserver { mIfindex = ifindex; } + void clearAlarms() { + cancelPref64Alarm(); + } + private final AlarmManager.OnAlarmListener mExpirePref64Alarm = () -> { + // Ignore the alarm if cancelPref64Alarm has already been called. + // // TODO: in the rare case where the alarm fires and posts the lambda to the handler // thread while we are processing an RA that changes the lifetime of the same prefix, // this code will run anyway even if the alarm is rescheduled or cancelled. If the - // lifetime in the RA is zero this doesn't matter (we just harmlessly cancel the alarm - // one extra time) but if the lifetime is nonzero then the prefix will be added and - // immediately removed by this code. + // lifetime in the RA is zero this code will correctly do nothing, but if the lifetime + // is nonzero then the prefix will be added and immediately removed by this code. + if (mNat64PrefixExpiry == 0) return; updatePref64(mShim.getNat64Prefix(mLinkProperties), mNat64PrefixExpiry, mNat64PrefixExpiry); }; private void cancelPref64Alarm() { + // Clear the expiry in case the alarm just fired and has not been processed yet. + if (mNat64PrefixExpiry == 0) return; + mNat64PrefixExpiry = 0; mAlarmManager.cancel(mExpirePref64Alarm); } @@ -342,7 +352,6 @@ public class IpClientLinkObserver implements NetworkObserver { schedulePref64Alarm(); } else { mShim.setNat64Prefix(mLinkProperties, null); - mNat64PrefixExpiry = 0; cancelPref64Alarm(); } diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java index 225f598..4a3f445 100644 --- a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java +++ b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java @@ -1527,6 +1527,25 @@ public class IpClientIntegrationTest { mIpc.getHandler().post(() -> lastAlarm.onAlarm()); expectAlarmCancelled(inOrder, pref64Alarm); expectNat64PrefixUpdate(inOrder, null); + + // Re-announce the prefix. + pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer(); + ra = buildRaPacket(pio, rdnss, pref64); + mPacketReader.sendResponse(ra); + final OnAlarmListener clearAlarm = expectAlarmSet(inOrder, "PREF64", 600); + expectNat64PrefixUpdate(inOrder, prefix); + reset(mCb, mAlarm); + + // Check that the alarm is cancelled when IpClient is stopped. + mIpc.stop(); + HandlerUtilsKt.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); + expectAlarmCancelled(inOrder, clearAlarm); + expectNat64PrefixUpdate(inOrder, null); + + // Check that even if the alarm was already in the message queue while it was cancelled, it + // is safely ignored. + mIpc.getHandler().post(() -> clearAlarm.onAlarm()); + HandlerUtilsKt.waitForIdle(mIpc.getHandler(), TEST_TIMEOUT_MS); } private void addIpAddressAndWaitForIt(final String iface) throws Exception { |