diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/android/net/ip/IpClient.java | 32 | ||||
-rw-r--r-- | src/android/net/ip/IpReachabilityMonitor.java | 124 |
2 files changed, 104 insertions, 52 deletions
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java index 163005a..bfeac8b 100644 --- a/src/android/net/ip/IpClient.java +++ b/src/android/net/ip/IpClient.java @@ -1364,19 +1364,6 @@ public class IpClient extends StateMachine { private boolean startIpReachabilityMonitor() { try { - // TODO: Fetch these parameters from settings, and install a - // settings observer to watch for update and re-program these - // parameters (Q: is this level of dynamic updatability really - // necessary or does reading from settings at startup suffice?). - final int numSolicits = 5; - final int interSolicitIntervalMs = 750; - setNeighborParameters(mNetd, mInterfaceName, numSolicits, interSolicitIntervalMs); - } catch (Exception e) { - mLog.e("Failed to adjust neighbor parameters", e); - // Carry on using the system defaults (currently: 3, 1000); - } - - try { mIpReachabilityMonitor = new IpReachabilityMonitor( mContext, mInterfaceParams, @@ -1388,7 +1375,8 @@ public class IpClient extends StateMachine { mCallback.onReachabilityLost(logMsg); } }, - mConfiguration.mUsingMultinetworkPolicyTracker); + mConfiguration.mUsingMultinetworkPolicyTracker, + mNetd); } catch (IllegalArgumentException iae) { // Failed to start IpReachabilityMonitor. Log it and call // onProvisioningFailure() immediately. @@ -1986,22 +1974,6 @@ public class IpClient extends StateMachine { } } - private static void setNeighborParameters( - INetd netd, String ifName, int numSolicits, int interSolicitIntervalMs) - throws RemoteException, IllegalArgumentException { - Preconditions.checkNotNull(netd); - Preconditions.checkArgument(!TextUtils.isEmpty(ifName)); - Preconditions.checkArgument(numSolicits > 0); - Preconditions.checkArgument(interSolicitIntervalMs > 0); - - for (int family : new Integer[]{INetd.IPV4, INetd.IPV6}) { - netd.setProcSysNet(family, INetd.NEIGH, ifName, "retrans_time_ms", - Integer.toString(interSolicitIntervalMs)); - netd.setProcSysNet(family, INetd.NEIGH, ifName, "ucast_solicit", - Integer.toString(numSolicits)); - } - } - // TODO: extract out into CollectionUtils. static <T> boolean any(Iterable<T> coll, Predicate<T> fn) { for (T t : coll) { diff --git a/src/android/net/ip/IpReachabilityMonitor.java b/src/android/net/ip/IpReachabilityMonitor.java index c19a24e..17b1f3c 100644 --- a/src/android/net/ip/IpReachabilityMonitor.java +++ b/src/android/net/ip/IpReachabilityMonitor.java @@ -23,6 +23,7 @@ import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST_ORGANIC; import android.content.Context; import android.net.ConnectivityManager; +import android.net.INetd; import android.net.LinkProperties; import android.net.RouteInfo; import android.net.ip.IpNeighborMonitor.NeighborEvent; @@ -36,10 +37,14 @@ import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.PowerManager.WakeLock; +import android.os.RemoteException; import android.os.SystemClock; +import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; +import com.android.networkstack.R; import java.io.PrintWriter; import java.net.Inet6Address; @@ -132,12 +137,20 @@ public class IpReachabilityMonitor { private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE); + // Upper and lower bound for NUD probe parameters. + protected static final int MAX_NUD_SOLICIT_NUM = 15; + protected static final int MIN_NUD_SOLICIT_NUM = 5; + protected static final int MAX_NUD_SOLICIT_INTERVAL_MS = 1000; + protected static final int MIN_NUD_SOLICIT_INTERVAL_MS = 750; + public interface Callback { - // This callback function must execute as quickly as possible as it is - // run on the same thread that listens to kernel neighbor updates. - // - // TODO: refactor to something like notifyProvisioningLost(String msg). - public void notifyLost(InetAddress ip, String logMsg); + /** + * This callback function must execute as quickly as possible as it is + * run on the same thread that listens to kernel neighbor updates. + * + * TODO: refactor to something like notifyProvisioningLost(String msg). + */ + void notifyLost(InetAddress ip, String logMsg); } /** @@ -168,29 +181,47 @@ public class IpReachabilityMonitor { private final boolean mUsingMultinetworkPolicyTracker; private final ConnectivityManager mCm; private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); + private final Context mContext; + private final INetd mNetd; private LinkProperties mLinkProperties = new LinkProperties(); private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>(); // Time in milliseconds of the last forced probe request. private volatile long mLastProbeTimeMs; + private int mNumSolicits; + private int mInterSolicitIntervalMs; public IpReachabilityMonitor( Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback, - boolean usingMultinetworkPolicyTracker) { + boolean usingMultinetworkPolicyTracker, final INetd netd) { this(context, ifParams, h, log, callback, usingMultinetworkPolicyTracker, - Dependencies.makeDefault(context, ifParams.name)); + Dependencies.makeDefault(context, ifParams.name), netd); } @VisibleForTesting IpReachabilityMonitor(Context context, InterfaceParams ifParams, Handler h, SharedLog log, - Callback callback, boolean usingMultinetworkPolicyTracker, Dependencies dependencies) { + Callback callback, boolean usingMultinetworkPolicyTracker, Dependencies dependencies, + final INetd netd) { if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); + mContext = context; mInterfaceParams = ifParams; mLog = log.forSubComponent(TAG); mCallback = callback; mUsingMultinetworkPolicyTracker = usingMultinetworkPolicyTracker; mCm = context.getSystemService(ConnectivityManager.class); mDependencies = dependencies; + mNetd = netd; + Preconditions.checkNotNull(mNetd); + Preconditions.checkArgument(!TextUtils.isEmpty(mInterfaceParams.name)); + + // In case the overylaid parameters specify an invalid configuration, set the parameters + // to the hardcoded defaults first, then set them to the values used in the steady state. + try { + setNeighborParameters(MIN_NUD_SOLICIT_NUM, MIN_NUD_SOLICIT_INTERVAL_MS); + } catch (Exception e) { + Log.e(TAG, "Failed to adjust neighbor parameters with hardcoded defaults"); + } + setNeighbourParametersForSteadyState(); mIpNeighborMonitor = new IpNeighborMonitor(h, mLog, (NeighborEvent event) -> { @@ -204,6 +235,8 @@ public class IpReachabilityMonitor { if (event.nudState == StructNdMsg.NUD_FAILED) { mLog.w("ALERT neighbor went from: " + prev + " to: " + event); handleNeighborLost(event); + } else if (event.nudState == StructNdMsg.NUD_REACHABLE) { + maybeRestoreNeighborParameters(); } }); mIpNeighborMonitor.start(); @@ -331,13 +364,29 @@ public class IpReachabilityMonitor { logNudFailed(lostProvisioning); } + private void maybeRestoreNeighborParameters() { + for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) { + if (DBG) { + Log.d(TAG, "neighbour IPv4(v6): " + entry.getKey() + " neighbour state: " + + StructNdMsg.stringForNudState(entry.getValue().nudState)); + } + if (entry.getValue().nudState != StructNdMsg.NUD_REACHABLE) return; + } + + // All neighbours in the watchlist are in REACHABLE state and connection is stable, + // restore NUD probe parameters to steadystate value. In the case where neighbours + // are responsive, this code will run before the wakelock expires. + setNeighbourParametersForSteadyState(); + } + private boolean avoidingBadLinks() { return !mUsingMultinetworkPolicyTracker || mCm.shouldAvoidBadWifi(); } public void probeAll() { - final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet()); + setNeighbourParametersPostRoaming(); + final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet()); if (!ipProbeList.isEmpty()) { // Keep the CPU awake long enough to allow all ARP/ND // probes a reasonable chance at success. See b/23197666. @@ -357,20 +406,51 @@ public class IpReachabilityMonitor { mLastProbeTimeMs = SystemClock.elapsedRealtime(); } - private static long getProbeWakeLockDuration() { - // Ideally, this would be computed by examining the values of: - // - // /proc/sys/net/ipv[46]/neigh/<ifname>/ucast_solicit - // - // and: - // - // /proc/sys/net/ipv[46]/neigh/<ifname>/retrans_time_ms - // - // For now, just make some assumptions. - final long numUnicastProbes = 3; - final long retransTimeMs = 1000; + private long getProbeWakeLockDuration() { final long gracePeriodMs = 500; - return (numUnicastProbes * retransTimeMs) + gracePeriodMs; + return (long) (mNumSolicits * mInterSolicitIntervalMs) + gracePeriodMs; + } + + private void setNeighbourParametersPostRoaming() { + setNeighborParametersFromResources(R.integer.config_nud_postroaming_solicit_num, + R.integer.config_nud_postroaming_solicit_interval); + } + + private void setNeighbourParametersForSteadyState() { + setNeighborParametersFromResources(R.integer.config_nud_steadystate_solicit_num, + R.integer.config_nud_steadystate_solicit_interval); + } + + private void setNeighborParametersFromResources(final int numResId, final int intervalResId) { + try { + final int numSolicits = mContext.getResources().getInteger(numResId); + final int interSolicitIntervalMs = mContext.getResources().getInteger(intervalResId); + setNeighborParameters(numSolicits, interSolicitIntervalMs); + } catch (Exception e) { + Log.e(TAG, "Failed to adjust neighbor parameters"); + } + } + + private void setNeighborParameters(int numSolicits, int interSolicitIntervalMs) + throws RemoteException, IllegalArgumentException { + Preconditions.checkArgument(numSolicits >= MIN_NUD_SOLICIT_NUM, + "numSolicits must be at least " + MIN_NUD_SOLICIT_NUM); + Preconditions.checkArgument(numSolicits <= MAX_NUD_SOLICIT_NUM, + "numSolicits must be at most " + MAX_NUD_SOLICIT_NUM); + Preconditions.checkArgument(interSolicitIntervalMs >= MIN_NUD_SOLICIT_INTERVAL_MS, + "interSolicitIntervalMs must be at least " + MIN_NUD_SOLICIT_INTERVAL_MS); + Preconditions.checkArgument(interSolicitIntervalMs <= MAX_NUD_SOLICIT_INTERVAL_MS, + "interSolicitIntervalMs must be at most " + MAX_NUD_SOLICIT_INTERVAL_MS); + + for (int family : new Integer[]{INetd.IPV4, INetd.IPV6}) { + mNetd.setProcSysNet(family, INetd.NEIGH, mInterfaceParams.name, "retrans_time_ms", + Integer.toString(interSolicitIntervalMs)); + mNetd.setProcSysNet(family, INetd.NEIGH, mInterfaceParams.name, "ucast_solicit", + Integer.toString(numSolicits)); + } + + mNumSolicits = numSolicits; + mInterSolicitIntervalMs = interSolicitIntervalMs; } private void logEvent(int probeType, int errorCode) { |