diff options
author | Remi NGUYEN VAN <reminv@google.com> | 2019-09-02 19:20:54 +0900 |
---|---|---|
committer | Remi NGUYEN VAN <reminv@google.com> | 2020-02-12 10:39:55 +0900 |
commit | dc018dd943f0c11e0b9172dee0db0966871af20d (patch) | |
tree | 964a774fb259941aa3f548a49b80992e268a88cc /src/android/net/dhcp/DhcpLeaseRepository.java | |
parent | ee23002c1f0a547ea46fa399d20caf542e68ab57 (diff) |
Add DhcpLeaseCallbacks
The callbacks will be used by Tethering to provide callbacks when DHCP
leases are updated.
The current design only supports one client as Tethering may want to
send callbacks to multiple callers, but DhcpServer is only owned by
Tethering.
Bug: 135411507
Test: atest NetworkStackTests
Change-Id: I1e44221d6fbd1b1f2d0d0057a29c7445af1cdbcf
Diffstat (limited to 'src/android/net/dhcp/DhcpLeaseRepository.java')
-rw-r--r-- | src/android/net/dhcp/DhcpLeaseRepository.java | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/src/android/net/dhcp/DhcpLeaseRepository.java b/src/android/net/dhcp/DhcpLeaseRepository.java index 4e74dc8..1dc2f7f 100644 --- a/src/android/net/dhcp/DhcpLeaseRepository.java +++ b/src/android/net/dhcp/DhcpLeaseRepository.java @@ -31,6 +31,8 @@ import android.net.IpPrefix; import android.net.MacAddress; import android.net.dhcp.DhcpServer.Clock; import android.net.util.SharedLog; +import android.os.RemoteCallbackList; +import android.os.RemoteException; import android.util.ArrayMap; import androidx.annotation.NonNull; @@ -45,6 +47,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -73,6 +76,7 @@ class DhcpLeaseRepository { @NonNull private Set<Inet4Address> mReservedAddrs; private int mSubnetAddr; + private int mPrefixLength; private int mSubnetMask; private int mNumAddresses; private long mLeaseTimeMs; @@ -84,6 +88,9 @@ class DhcpLeaseRepository { */ private long mNextExpirationCheck = EXPIRATION_NEVER; + @NonNull + private RemoteCallbackList<IDhcpLeaseCallbacks> mLeaseCallbacks = new RemoteCallbackList<>(); + static class DhcpLeaseException extends Exception { DhcpLeaseException(String message) { super(message); @@ -131,27 +138,34 @@ class DhcpLeaseRepository { long leaseTimeMs) { mPrefix = prefix; mReservedAddrs = Collections.unmodifiableSet(new HashSet<>(reservedAddrs)); - mSubnetMask = prefixLengthToV4NetmaskIntHTH(prefix.getPrefixLength()); + mPrefixLength = prefix.getPrefixLength(); + mSubnetMask = prefixLengthToV4NetmaskIntHTH(mPrefixLength); mSubnetAddr = inet4AddressToIntHTH((Inet4Address) prefix.getAddress()) & mSubnetMask; mNumAddresses = 1 << (IPV4_ADDR_BITS - prefix.getPrefixLength()); mLeaseTimeMs = leaseTimeMs; - cleanMap(mCommittedLeases); cleanMap(mDeclinedAddrs); + if (cleanMap(mCommittedLeases)) { + notifyLeasesChanged(); + } } /** * From a map keyed by {@link Inet4Address}, remove entries where the key is invalid (as * specified by {@link #isValidAddress(Inet4Address)}), or is a reserved address. + * @return true iff at least one entry was removed. */ - private <T> void cleanMap(Map<Inet4Address, T> map) { + private <T> boolean cleanMap(Map<Inet4Address, T> map) { final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator(); + boolean removed = false; while (it.hasNext()) { final Inet4Address addr = it.next().getKey(); if (!isValidAddress(addr) || mReservedAddrs.contains(addr)) { it.remove(); + removed = true; } } + return removed; } /** @@ -181,7 +195,7 @@ class DhcpLeaseRepository { mLog.log("Offering extended lease " + newLease); // Do not update lease time in the map: the offer is not committed yet. } else if (reqAddr != null && isValidAddress(reqAddr) && isAvailable(reqAddr)) { - newLease = new DhcpLease(clientId, hwAddr, reqAddr, expTime, hostname); + newLease = new DhcpLease(clientId, hwAddr, reqAddr, mPrefixLength, expTime, hostname); mLog.log("Offering requested lease " + newLease); } else { newLease = makeNewOffer(clientId, hwAddr, expTime, hostname); @@ -267,7 +281,8 @@ class DhcpLeaseRepository { if (assignedLease != null) { if (sidSet && reqAddr != null) { // Client in SELECTING state; remove any current lease before creating a new one. - mCommittedLeases.remove(assignedLease.getNetAddr()); + // Do not notify of change as it will be done when the new lease is committed. + removeLease(assignedLease.getNetAddr(), false /* notifyChange */); } else if (!assignedLease.getNetAddr().equals(leaseAddr)) { // reqAddr null (RENEWING/REBINDING): client renewing its own lease for clientAddr. // reqAddr set with sid not set (INIT-REBOOT): client verifying configuration. @@ -314,7 +329,7 @@ class DhcpLeaseRepository { final DhcpLease lease; if (currentLease == null) { if (isValidAddress(addr) && !mReservedAddrs.contains(addr)) { - lease = new DhcpLease(clientId, hwAddr, addr, expTime, hostname); + lease = new DhcpLease(clientId, hwAddr, addr, mPrefixLength, expTime, hostname); } else { throw new InvalidAddressException("Lease not found and address unavailable"); } @@ -328,6 +343,13 @@ class DhcpLeaseRepository { private void commitLease(@NonNull DhcpLease lease) { mCommittedLeases.put(lease.getNetAddr(), lease); maybeUpdateEarliestExpiration(lease.getExpTime()); + notifyLeasesChanged(); + } + + private void removeLease(@NonNull Inet4Address address, boolean notifyChange) { + // Earliest expiration remains <= the first expiry time on remove, so no need to update it. + mCommittedLeases.remove(address); + if (notifyChange) notifyLeasesChanged(); } /** @@ -343,8 +365,8 @@ class DhcpLeaseRepository { return false; } if (currentLease.matchesClient(clientId, hwAddr)) { - mCommittedLeases.remove(addr); mLog.log("Released lease " + currentLease); + removeLease(addr, true /* notifyChange */); return true; } mLog.w(String.format("Not releasing lease %s: does not match client (cid %s, hwAddr %s)", @@ -352,6 +374,24 @@ class DhcpLeaseRepository { return false; } + private void notifyLeasesChanged() { + final List<DhcpLeaseParcelable> leaseParcelables = + new ArrayList<>(mCommittedLeases.size()); + for (DhcpLease committedLease : mCommittedLeases.values()) { + leaseParcelables.add(committedLease.toParcelable()); + } + + final int cbCount = mLeaseCallbacks.beginBroadcast(); + for (int i = 0; i < cbCount; i++) { + try { + mLeaseCallbacks.getBroadcastItem(i).onLeasesChanged(leaseParcelables); + } catch (RemoteException e) { + mLog.e("Could not send lease callback", e); + } + } + mLeaseCallbacks.finishBroadcast(); + } + public void markLeaseDeclined(@NonNull Inet4Address addr) { if (mDeclinedAddrs.containsKey(addr) || !isValidAddress(addr)) { mLog.logf("Not marking %s as declined: already declined or not assignable", @@ -383,6 +423,14 @@ class DhcpLeaseRepository { } /** + * Add callbacks that will be called on leases update. + */ + public void addLeaseCallbacks(@NonNull IDhcpLeaseCallbacks cb) { + Objects.requireNonNull(cb, "Callbacks must be non-null"); + mLeaseCallbacks.register(cb); + } + + /** * Given the expiration time of a new committed lease or declined address, update * {@link #mNextExpirationCheck} so it stays lower than or equal to the time for the first lease * to expire. @@ -541,7 +589,7 @@ class DhcpLeaseRepository { for (int i = 0; i < mNumAddresses; i++) { final Inet4Address addr = intToInet4AddressHTH(intAddr); if (isAvailable(addr) && !mDeclinedAddrs.containsKey(addr)) { - return new DhcpLease(clientId, hwAddr, addr, expTime, hostname); + return new DhcpLease(clientId, hwAddr, addr, mPrefixLength, expTime, hostname); } intAddr = getNextAddress(intAddr); } @@ -557,7 +605,7 @@ class DhcpLeaseRepository { // However declined addresses may have been requested (typically by the machine that was // already using the address) after being declined. if (isAvailable(addr)) { - return new DhcpLease(clientId, hwAddr, addr, expTime, hostname); + return new DhcpLease(clientId, hwAddr, addr, mPrefixLength, expTime, hostname); } } |