Merge "Refactor to IpNeighborMonitor and single-threaded semantics"
diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
index 1925c39..6cf4fa9a 100644
--- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java
+++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
@@ -19,7 +19,7 @@
import static android.system.OsConstants.*;
import android.net.NetworkUtils;
-import android.net.util.BlockingSocketReader;
+import android.net.util.PacketReader;
import android.net.util.ConnectivityPacketSummary;
import android.os.Handler;
import android.system.ErrnoException;
@@ -65,7 +65,7 @@
private final String mTag;
private final LocalLog mLog;
- private final BlockingSocketReader mPacketListener;
+ private final PacketReader mPacketListener;
private boolean mRunning;
private String mDisplayName;
@@ -101,7 +101,7 @@
mDisplayName = null;
}
- private final class PacketListener extends BlockingSocketReader {
+ private final class PacketListener extends PacketReader {
private final int mIfIndex;
private final byte mHwAddr[];
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 5c58cdb..b305b33 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -815,6 +815,15 @@
pw.println(Objects.toString(provisioningConfig, "N/A"));
pw.decreaseIndent();
+ final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
+ if (iprm != null) {
+ pw.println();
+ pw.println(mTag + " current IpReachabilityMonitor state:");
+ pw.increaseIndent();
+ iprm.dump(pw);
+ pw.decreaseIndent();
+ }
+
pw.println();
pw.println(mTag + " StateMachine dump:");
pw.increaseIndent();
@@ -1237,6 +1246,7 @@
mIpReachabilityMonitor = new IpReachabilityMonitor(
mContext,
mInterfaceName,
+ getHandler(),
mLog,
new IpReachabilityMonitor.Callback() {
@Override
diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java
new file mode 100644
index 0000000..6807334
--- /dev/null
+++ b/services/net/java/android/net/ip/IpNeighborMonitor.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import android.net.netlink.NetlinkConstants;
+import android.net.netlink.NetlinkErrorMessage;
+import android.net.netlink.NetlinkMessage;
+import android.net.netlink.NetlinkSocket;
+import android.net.netlink.RtNetlinkNeighborMessage;
+import android.net.netlink.StructNdMsg;
+import android.net.netlink.StructNlMsgHdr;
+import android.net.util.PacketReader;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+import com.android.internal.util.BitUtils;
+
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.StringJoiner;
+
+
+/**
+ * IpNeighborMonitor.
+ *
+ * Monitors the kernel rtnetlink neighbor notifications and presents to callers
+ * NeighborEvents describing each event. Callers can provide a consumer instance
+ * to both filter (e.g. by interface index and IP address) and handle the
+ * generated NeighborEvents.
+ *
+ * @hide
+ */
+public class IpNeighborMonitor extends PacketReader {
+ private static final String TAG = IpNeighborMonitor.class.getSimpleName();
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
+ * for the given IP address on the specified interface index.
+ *
+ * @return 0 if the request was successfully passed to the kernel; otherwise return
+ * a non-zero error code.
+ */
+ public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) {
+ final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
+ if (DBG) { Log.d(TAG, msgSnippet); }
+
+ final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
+ 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
+
+ try {
+ NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Error " + msgSnippet + ": " + e);
+ return -e.errno;
+ }
+
+ return 0;
+ }
+
+ public static class NeighborEvent {
+ final long elapsedMs;
+ final short msgType;
+ final int ifindex;
+ final InetAddress ip;
+ final short nudState;
+ final byte[] linkLayerAddr;
+
+ public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip,
+ short nudState, byte[] linkLayerAddr) {
+ this.elapsedMs = elapsedMs;
+ this.msgType = msgType;
+ this.ifindex = ifindex;
+ this.ip = ip;
+ this.nudState = nudState;
+ this.linkLayerAddr = linkLayerAddr;
+ }
+
+ boolean isConnected() {
+ return (msgType != NetlinkConstants.RTM_DELNEIGH) &&
+ StructNdMsg.isNudStateConnected(nudState);
+ }
+
+ boolean isValid() {
+ return (msgType != NetlinkConstants.RTM_DELNEIGH) &&
+ StructNdMsg.isNudStateValid(nudState);
+ }
+
+ @Override
+ public String toString() {
+ final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}");
+ return j.add("@" + elapsedMs)
+ .add(NetlinkConstants.stringForNlMsgType(msgType))
+ .add("if=" + ifindex)
+ .add(ip.getHostAddress())
+ .add(StructNdMsg.stringForNudState(nudState))
+ .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]")
+ .toString();
+ }
+ }
+
+ public interface NeighborEventConsumer {
+ // Every neighbor event received on the netlink socket is passed in
+ // here. Subclasses should filter for events of interest.
+ public void accept(NeighborEvent event);
+ }
+
+ private final SharedLog mLog;
+ private final NeighborEventConsumer mConsumer;
+
+ public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) {
+ super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE);
+ mLog = log.forSubComponent(TAG);
+ mConsumer = (cb != null) ? cb : (event) -> { /* discard */ };
+ }
+
+ @Override
+ protected FileDescriptor createFd() {
+ FileDescriptor fd = null;
+
+ try {
+ fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE);
+ Os.bind(fd, (SocketAddress)(new NetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH)));
+ Os.connect(fd, (SocketAddress)(new NetlinkSocketAddress(0, 0)));
+
+ if (VDBG) {
+ final NetlinkSocketAddress nlAddr = (NetlinkSocketAddress) Os.getsockname(fd);
+ Log.d(TAG, "bound to sockaddr_nl{"
+ + BitUtils.uint32(nlAddr.getPortId()) + ", "
+ + nlAddr.getGroupsMask()
+ + "}");
+ }
+ } catch (ErrnoException|SocketException e) {
+ logError("Failed to create rtnetlink socket", e);
+ IoUtils.closeQuietly(fd);
+ return null;
+ }
+
+ return fd;
+ }
+
+ @Override
+ protected void handlePacket(byte[] recvbuf, int length) {
+ final long whenMs = SystemClock.elapsedRealtime();
+
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length);
+ byteBuffer.order(ByteOrder.nativeOrder());
+
+ parseNetlinkMessageBuffer(byteBuffer, whenMs);
+ }
+
+ private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
+ while (byteBuffer.remaining() > 0) {
+ final int position = byteBuffer.position();
+ final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
+ if (nlMsg == null || nlMsg.getHeader() == null) {
+ byteBuffer.position(position);
+ mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
+ break;
+ }
+
+ final int srcPortId = nlMsg.getHeader().nlmsg_pid;
+ if (srcPortId != 0) {
+ mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId));
+ break;
+ }
+
+ if (nlMsg instanceof NetlinkErrorMessage) {
+ mLog.e("netlink error: " + nlMsg);
+ continue;
+ } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
+ mLog.i("non-rtnetlink neighbor msg: " + nlMsg);
+ continue;
+ }
+
+ evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
+ }
+ }
+
+ private void evaluateRtNetlinkNeighborMessage(
+ RtNetlinkNeighborMessage neighMsg, long whenMs) {
+ final short msgType = neighMsg.getHeader().nlmsg_type;
+ final StructNdMsg ndMsg = neighMsg.getNdHeader();
+ if (ndMsg == null) {
+ mLog.e("RtNetlinkNeighborMessage without ND message header!");
+ return;
+ }
+
+ final int ifindex = ndMsg.ndm_ifindex;
+ final InetAddress destination = neighMsg.getDestination();
+ final short nudState =
+ (msgType == NetlinkConstants.RTM_DELNEIGH)
+ ? StructNdMsg.NUD_NONE
+ : ndMsg.ndm_state;
+
+ final NeighborEvent event = new NeighborEvent(
+ whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress());
+
+ if (VDBG) {
+ Log.d(TAG, neighMsg.toString());
+ }
+ if (DBG) {
+ Log.d(TAG, event.toString());
+ }
+
+ mConsumer.accept(event);
+ }
+}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 714b35a..b31ffbb 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -22,30 +22,27 @@
import android.net.LinkProperties.ProvisioningChange;
import android.net.ProxyInfo;
import android.net.RouteInfo;
+import android.net.ip.IpNeighborMonitor.NeighborEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpReachabilityEvent;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNdaCacheInfo;
-import android.net.netlink.StructNlMsgHdr;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.SharedLog;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.system.ErrnoException;
-import android.system.NetlinkSocketAddress;
import android.system.OsConstants;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
import java.io.InterruptedIOException;
+import java.io.PrintWriter;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -134,6 +131,8 @@
* state it may be best for the link to disconnect completely and
* reconnect afresh.
*
+ * Accessing an instance of this class from multiple threads is NOT safe.
+ *
* @hide
*/
public class IpReachabilityMonitor {
@@ -169,64 +168,33 @@
}
}
- private final Object mLock = new Object();
private final String mInterfaceName;
private final int mInterfaceIndex;
+ private final IpNeighborMonitor mIpNeighborMonitor;
private final SharedLog mLog;
private final Callback mCallback;
private final Dependencies mDependencies;
private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
- private final NetlinkSocketObserver mNetlinkSocketObserver;
- private final Thread mObserverThread;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
- @GuardedBy("mLock")
private LinkProperties mLinkProperties = new LinkProperties();
- // TODO: consider a map to a private NeighborState class holding more
- // information than a single NUD state entry.
- @GuardedBy("mLock")
- private Map<InetAddress, Short> mIpWatchList = new HashMap<>();
- @GuardedBy("mLock")
- private int mIpWatchListVersion;
- private volatile boolean mRunning;
+ private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
// Time in milliseconds of the last forced probe request.
private volatile long mLastProbeTimeMs;
- /**
- * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
- * for the given IP address on the specified interface index.
- *
- * @return 0 if the request was successfully passed to the kernel; otherwise return
- * a non-zero error code.
- */
- private static int probeNeighbor(int ifIndex, InetAddress ip) {
- final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
- if (DBG) { Log.d(TAG, msgSnippet); }
-
- final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
- 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
-
- try {
- NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg);
- } catch (ErrnoException e) {
- Log.e(TAG, "Error " + msgSnippet + ": " + e);
- return -e.errno;
- }
-
- return 0;
+ public IpReachabilityMonitor(
+ Context context, String ifName, Handler h, SharedLog log, Callback callback) {
+ this(context, ifName, h, log, callback, null);
}
- public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback) {
- this(context, ifName, log, callback, null);
- }
-
- public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback,
+ public IpReachabilityMonitor(
+ Context context, String ifName, Handler h, SharedLog log, Callback callback,
MultinetworkPolicyTracker tracker) {
- this(ifName, getInterfaceIndex(ifName), log, callback, tracker,
+ this(ifName, getInterfaceIndex(ifName), h, log, callback, tracker,
Dependencies.makeDefault(context, ifName));
}
@VisibleForTesting
- IpReachabilityMonitor(String ifName, int ifIndex, SharedLog log, Callback callback,
+ IpReachabilityMonitor(String ifName, int ifIndex, Handler h, SharedLog log, Callback callback,
MultinetworkPolicyTracker tracker, Dependencies dependencies) {
mInterfaceName = ifName;
mLog = log.forSubComponent(TAG);
@@ -234,47 +202,56 @@
mMultinetworkPolicyTracker = tracker;
mInterfaceIndex = ifIndex;
mDependencies = dependencies;
- mNetlinkSocketObserver = new NetlinkSocketObserver();
- mObserverThread = new Thread(mNetlinkSocketObserver);
- mObserverThread.start();
+
+ mIpNeighborMonitor = new IpNeighborMonitor(h, mLog,
+ (NeighborEvent event) -> {
+ if (mInterfaceIndex != event.ifindex) return;
+ if (!mNeighborWatchList.containsKey(event.ip)) return;
+
+ final NeighborEvent prev = mNeighborWatchList.put(event.ip, event);
+
+ // TODO: Consider what to do with other states that are not within
+ // NeighborEvent#isValid() (i.e. NUD_NONE, NUD_INCOMPLETE).
+ if (event.nudState == StructNdMsg.NUD_FAILED) {
+ mLog.w("ALERT neighbor went from: " + prev + " to: " + event);
+ handleNeighborLost(event);
+ }
+ });
+ mIpNeighborMonitor.start();
}
public void stop() {
- mRunning = false;
+ mIpNeighborMonitor.stop();
clearLinkProperties();
- mNetlinkSocketObserver.clearNetlinkSocket();
}
- // TODO: add a public dump() method that can be called during a bug report.
+ public void dump(PrintWriter pw) {
+ DumpUtils.dumpAsync(
+ mIpNeighborMonitor.getHandler(),
+ new Dump() {
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(describeWatchList("\n"));
+ }
+ },
+ pw, "", 1000);
+ }
- private String describeWatchList() {
- final String delimiter = ", ";
- StringBuilder sb = new StringBuilder();
- synchronized (mLock) {
- sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}, ");
- sb.append("v{" + mIpWatchListVersion + "}, ");
- sb.append("ntable=[");
- boolean firstTime = true;
- for (Map.Entry<InetAddress, Short> entry : mIpWatchList.entrySet()) {
- if (firstTime) {
- firstTime = false;
- } else {
- sb.append(delimiter);
- }
- sb.append(entry.getKey().getHostAddress() + "/" +
- StructNdMsg.stringForNudState(entry.getValue()));
- }
- sb.append("]");
+ private String describeWatchList() { return describeWatchList(" "); }
+
+ private String describeWatchList(String sep) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}," + sep);
+ sb.append("ntable=[" + sep);
+ String delimiter = "";
+ for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
+ sb.append(delimiter).append(entry.getKey().getHostAddress() + "/" + entry.getValue());
+ delimiter = "," + sep;
}
+ sb.append("]");
return sb.toString();
}
- private boolean isWatching(InetAddress ip) {
- synchronized (mLock) {
- return mRunning && mIpWatchList.containsKey(ip);
- }
- }
-
private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
for (RouteInfo route : routes) {
if (!route.hasGateway() && route.matches(ip)) {
@@ -284,13 +261,6 @@
return false;
}
- private short getNeighborStateLocked(InetAddress ip) {
- if (mIpWatchList.containsKey(ip)) {
- return mIpWatchList.get(ip);
- }
- return StructNdMsg.NUD_NONE;
- }
-
public void updateLinkProperties(LinkProperties lp) {
if (!mInterfaceName.equals(lp.getInterfaceName())) {
// TODO: figure out whether / how to cope with interface changes.
@@ -299,70 +269,63 @@
return;
}
- synchronized (mLock) {
- mLinkProperties = new LinkProperties(lp);
- Map<InetAddress, Short> newIpWatchList = new HashMap<>();
+ mLinkProperties = new LinkProperties(lp);
+ Map<InetAddress, NeighborEvent> newNeighborWatchList = new HashMap<>();
- final List<RouteInfo> routes = mLinkProperties.getRoutes();
- for (RouteInfo route : routes) {
- if (route.hasGateway()) {
- InetAddress gw = route.getGateway();
- if (isOnLink(routes, gw)) {
- newIpWatchList.put(gw, getNeighborStateLocked(gw));
- }
+ final List<RouteInfo> routes = mLinkProperties.getRoutes();
+ for (RouteInfo route : routes) {
+ if (route.hasGateway()) {
+ InetAddress gw = route.getGateway();
+ if (isOnLink(routes, gw)) {
+ newNeighborWatchList.put(gw, mNeighborWatchList.getOrDefault(gw, null));
}
}
-
- for (InetAddress nameserver : lp.getDnsServers()) {
- if (isOnLink(routes, nameserver)) {
- newIpWatchList.put(nameserver, getNeighborStateLocked(nameserver));
- }
- }
-
- mIpWatchList = newIpWatchList;
- mIpWatchListVersion++;
}
+
+ for (InetAddress dns : lp.getDnsServers()) {
+ if (isOnLink(routes, dns)) {
+ newNeighborWatchList.put(dns, mNeighborWatchList.getOrDefault(dns, null));
+ }
+ }
+
+ mNeighborWatchList = newNeighborWatchList;
if (DBG) { Log.d(TAG, "watch: " + describeWatchList()); }
}
public void clearLinkProperties() {
- synchronized (mLock) {
- mLinkProperties.clear();
- mIpWatchList.clear();
- mIpWatchListVersion++;
- }
+ mLinkProperties.clear();
+ mNeighborWatchList.clear();
if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
}
- private void handleNeighborLost(String msg) {
+ private void handleNeighborLost(NeighborEvent event) {
+ final LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
+
InetAddress ip = null;
- final ProvisioningChange delta;
- synchronized (mLock) {
- LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
+ for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
+ // TODO: Consider using NeighborEvent#isValid() here; it's more
+ // strict but may interact badly if other entries are somehow in
+ // NUD_INCOMPLETE (say, during network attach).
+ if (entry.getValue().nudState != StructNdMsg.NUD_FAILED) continue;
- for (Map.Entry<InetAddress, Short> entry : mIpWatchList.entrySet()) {
- if (entry.getValue() != StructNdMsg.NUD_FAILED) {
- continue;
- }
-
- ip = entry.getKey();
- for (RouteInfo route : mLinkProperties.getRoutes()) {
- if (ip.equals(route.getGateway())) {
- whatIfLp.removeRoute(route);
- }
- }
-
- if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
- // We should do this unconditionally, but alas we cannot: b/31827713.
- whatIfLp.removeDnsServer(ip);
+ ip = entry.getKey();
+ for (RouteInfo route : mLinkProperties.getRoutes()) {
+ if (ip.equals(route.getGateway())) {
+ whatIfLp.removeRoute(route);
}
}
- delta = LinkProperties.compareProvisioning(mLinkProperties, whatIfLp);
+ if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
+ // We should do this unconditionally, but alas we cannot: b/31827713.
+ whatIfLp.removeDnsServer(ip);
+ }
}
+ final ProvisioningChange delta = LinkProperties.compareProvisioning(
+ mLinkProperties, whatIfLp);
+
if (delta == ProvisioningChange.LOST_PROVISIONING) {
- final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
+ final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
Log.w(TAG, logMsg);
if (mCallback != null) {
// TODO: remove |ip| when the callback signature no longer has
@@ -378,12 +341,9 @@
}
public void probeAll() {
- final List<InetAddress> ipProbeList;
- synchronized (mLock) {
- ipProbeList = new ArrayList<>(mIpWatchList.keySet());
- }
+ final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet());
- if (!ipProbeList.isEmpty() && mRunning) {
+ if (!ipProbeList.isEmpty()) {
// Keep the CPU awake long enough to allow all ARP/ND
// probes a reasonable chance at success. See b/23197666.
//
@@ -394,13 +354,10 @@
}
for (InetAddress target : ipProbeList) {
- if (!mRunning) {
- break;
- }
- final int returnValue = probeNeighbor(mInterfaceIndex, target);
+ final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceIndex, target);
mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)",
- target.getHostAddress(), returnValue));
- logEvent(IpReachabilityEvent.PROBE, returnValue);
+ target.getHostAddress(), rval));
+ logEvent(IpReachabilityEvent.PROBE, rval);
}
mLastProbeTimeMs = SystemClock.elapsedRealtime();
}
@@ -446,153 +403,4 @@
int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost);
mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType));
}
-
- // TODO: simplify the number of objects by making this extend Thread.
- private final class NetlinkSocketObserver implements Runnable {
- private NetlinkSocket mSocket;
-
- @Override
- public void run() {
- if (VDBG) { Log.d(TAG, "Starting observing thread."); }
- mRunning = true;
-
- try {
- setupNetlinkSocket();
- } catch (ErrnoException | SocketException e) {
- Log.e(TAG, "Failed to suitably initialize a netlink socket", e);
- mRunning = false;
- }
-
- while (mRunning) {
- final ByteBuffer byteBuffer;
- try {
- byteBuffer = recvKernelReply();
- } catch (ErrnoException e) {
- if (mRunning) { Log.w(TAG, "ErrnoException: ", e); }
- break;
- }
- final long whenMs = SystemClock.elapsedRealtime();
- if (byteBuffer == null) {
- continue;
- }
- parseNetlinkMessageBuffer(byteBuffer, whenMs);
- }
-
- clearNetlinkSocket();
-
- mRunning = false; // Not a no-op when ErrnoException happened.
- if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
- }
-
- private void clearNetlinkSocket() {
- if (mSocket != null) {
- mSocket.close();
- }
- }
-
- // TODO: Refactor the main loop to recreate the socket upon recoverable errors.
- private void setupNetlinkSocket() throws ErrnoException, SocketException {
- clearNetlinkSocket();
- mSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
-
- final NetlinkSocketAddress listenAddr = new NetlinkSocketAddress(
- 0, OsConstants.RTMGRP_NEIGH);
- mSocket.bind(listenAddr);
-
- if (VDBG) {
- final NetlinkSocketAddress nlAddr = mSocket.getLocalAddress();
- Log.d(TAG, "bound to sockaddr_nl{"
- + ((long) (nlAddr.getPortId() & 0xffffffff)) + ", "
- + nlAddr.getGroupsMask()
- + "}");
- }
- }
-
- private ByteBuffer recvKernelReply() throws ErrnoException {
- try {
- return mSocket.recvMessage(0);
- } catch (InterruptedIOException e) {
- // Interruption or other error, e.g. another thread closed our file descriptor.
- } catch (ErrnoException e) {
- if (e.errno != OsConstants.EAGAIN) {
- throw e;
- }
- }
- return null;
- }
-
- private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
- while (byteBuffer.remaining() > 0) {
- final int position = byteBuffer.position();
- final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
- if (nlMsg == null || nlMsg.getHeader() == null) {
- byteBuffer.position(position);
- Log.e(TAG, "unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
- break;
- }
-
- final int srcPortId = nlMsg.getHeader().nlmsg_pid;
- if (srcPortId != 0) {
- Log.e(TAG, "non-kernel source portId: " + ((long) (srcPortId & 0xffffffff)));
- break;
- }
-
- if (nlMsg instanceof NetlinkErrorMessage) {
- Log.e(TAG, "netlink error: " + nlMsg);
- continue;
- } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
- if (DBG) {
- Log.d(TAG, "non-rtnetlink neighbor msg: " + nlMsg);
- }
- continue;
- }
-
- evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
- }
- }
-
- private void evaluateRtNetlinkNeighborMessage(
- RtNetlinkNeighborMessage neighMsg, long whenMs) {
- final StructNdMsg ndMsg = neighMsg.getNdHeader();
- if (ndMsg == null || ndMsg.ndm_ifindex != mInterfaceIndex) {
- return;
- }
-
- final InetAddress destination = neighMsg.getDestination();
- if (!isWatching(destination)) {
- return;
- }
-
- final short msgType = neighMsg.getHeader().nlmsg_type;
- final short nudState = ndMsg.ndm_state;
- final String eventMsg = "NeighborEvent{"
- + "elapsedMs=" + whenMs + ", "
- + destination.getHostAddress() + ", "
- + "[" + NetlinkConstants.hexify(neighMsg.getLinkLayerAddress()) + "], "
- + NetlinkConstants.stringForNlMsgType(msgType) + ", "
- + StructNdMsg.stringForNudState(nudState)
- + "}";
-
- if (VDBG) {
- Log.d(TAG, neighMsg.toString());
- } else if (DBG) {
- Log.d(TAG, eventMsg);
- }
-
- synchronized (mLock) {
- if (mIpWatchList.containsKey(destination)) {
- final short value =
- (msgType == NetlinkConstants.RTM_DELNEIGH)
- ? StructNdMsg.NUD_NONE
- : nudState;
- mIpWatchList.put(destination, value);
- }
- }
-
- if (nudState == StructNdMsg.NUD_FAILED) {
- Log.w(TAG, "ALERT: " + eventMsg);
- handleNeighborLost(eventMsg);
- }
- }
- }
}
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index f5f211d..5af3c29 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -16,16 +16,24 @@
package android.net.netlink;
+import static android.system.OsConstants.AF_NETLINK;
+import static android.system.OsConstants.EIO;
+import static android.system.OsConstants.EPROTO;
+import static android.system.OsConstants.ETIMEDOUT;
+import static android.system.OsConstants.SO_RCVBUF;
+import static android.system.OsConstants.SO_RCVTIMEO;
+import static android.system.OsConstants.SO_SNDTIMEO;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOL_SOCKET;
+
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
import android.system.Os;
-import android.system.OsConstants;
import android.system.StructTimeval;
import android.util.Log;
import libcore.io.IoUtils;
import libcore.io.Libcore;
-import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
import java.net.SocketAddress;
@@ -37,28 +45,27 @@
/**
* NetlinkSocket
*
- * A small wrapper class to assist with AF_NETLINK socket operations.
+ * A small static class to assist with AF_NETLINK socket operations.
*
* @hide
*/
-public class NetlinkSocket implements Closeable {
+public class NetlinkSocket {
private static final String TAG = "NetlinkSocket";
- private static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
- private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
- final private FileDescriptor mDescriptor;
- private NetlinkSocketAddress mAddr;
- private long mLastRecvTimeoutMs;
- private long mLastSendTimeoutMs;
+ public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
+ public static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException {
final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
+ final long IO_TIMEOUT = 300L;
- try (NetlinkSocket nlSocket = new NetlinkSocket(nlProto)) {
- final long IO_TIMEOUT = 300L;
- nlSocket.connectToKernel();
- nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
- final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
+ FileDescriptor fd;
+
+ try {
+ fd = forProto(nlProto);
+ connectToKernel(fd);
+ sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
+ final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
// recvMessage() guaranteed to not return null if it did not throw.
final NetlinkMessage response = NetlinkMessage.parse(bytes);
if (response != null && response instanceof NetlinkErrorMessage &&
@@ -81,61 +88,30 @@
errmsg = response.toString();
}
Log.e(TAG, errPrefix + ", errmsg=" + errmsg);
- throw new ErrnoException(errmsg, OsConstants.EPROTO);
+ throw new ErrnoException(errmsg, EPROTO);
}
} catch (InterruptedIOException e) {
Log.e(TAG, errPrefix, e);
- throw new ErrnoException(errPrefix, OsConstants.ETIMEDOUT, e);
+ throw new ErrnoException(errPrefix, ETIMEDOUT, e);
} catch (SocketException e) {
Log.e(TAG, errPrefix, e);
- throw new ErrnoException(errPrefix, OsConstants.EIO, e);
+ throw new ErrnoException(errPrefix, EIO, e);
}
+
+ IoUtils.closeQuietly(fd);
}
- public NetlinkSocket(int nlProto) throws ErrnoException {
- mDescriptor = Os.socket(
- OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto);
-
- Os.setsockoptInt(
- mDescriptor, OsConstants.SOL_SOCKET,
- OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE);
+ public static FileDescriptor forProto(int nlProto) throws ErrnoException {
+ final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto);
+ Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE);
+ return fd;
}
- public NetlinkSocketAddress getLocalAddress() throws ErrnoException {
- return (NetlinkSocketAddress) Os.getsockname(mDescriptor);
+ public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException {
+ Os.connect(fd, (SocketAddress) (new NetlinkSocketAddress(0, 0)));
}
- public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException {
- Os.bind(mDescriptor, (SocketAddress)localAddr);
- }
-
- public void connectTo(NetlinkSocketAddress peerAddr)
- throws ErrnoException, SocketException {
- Os.connect(mDescriptor, (SocketAddress) peerAddr);
- }
-
- public void connectToKernel() throws ErrnoException, SocketException {
- connectTo(new NetlinkSocketAddress(0, 0));
- }
-
- /**
- * Wait indefinitely (or until underlying socket error) for a
- * netlink message of at most DEFAULT_RECV_BUFSIZE size.
- */
- public ByteBuffer recvMessage()
- throws ErrnoException, InterruptedIOException {
- return recvMessage(DEFAULT_RECV_BUFSIZE, 0);
- }
-
- /**
- * Wait up to |timeoutMs| (or until underlying socket error) for a
- * netlink message of at most DEFAULT_RECV_BUFSIZE size.
- */
- public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException {
- return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs);
- }
-
- private void checkTimeout(long timeoutMs) {
+ private static void checkTimeout(long timeoutMs) {
if (timeoutMs < 0) {
throw new IllegalArgumentException("Negative timeouts not permitted");
}
@@ -147,21 +123,14 @@
*
* Multi-threaded calls with different timeouts will cause unexpected results.
*/
- public ByteBuffer recvMessage(int bufsize, long timeoutMs)
+ public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
checkTimeout(timeoutMs);
- synchronized (mDescriptor) {
- if (mLastRecvTimeoutMs != timeoutMs) {
- Os.setsockoptTimeval(mDescriptor,
- OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
- StructTimeval.fromMillis(timeoutMs));
- mLastRecvTimeoutMs = timeoutMs;
- }
- }
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
- int length = Os.read(mDescriptor, byteBuffer);
+ int length = Os.read(fd, byteBuffer);
if (length == bufsize) {
Log.w(TAG, "maximum read");
}
@@ -172,39 +141,16 @@
}
/**
- * Send a message to a peer to which this socket has previously connected.
- *
- * This blocks until completion or an error occurs.
- */
- public boolean sendMessage(byte[] bytes, int offset, int count)
- throws ErrnoException, InterruptedIOException {
- return sendMessage(bytes, offset, count, 0);
- }
-
- /**
* Send a message to a peer to which this socket has previously connected,
* waiting at most |timeoutMs| milliseconds for the send to complete.
*
* Multi-threaded calls with different timeouts will cause unexpected results.
*/
- public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs)
+ public static int sendMessage(
+ FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
checkTimeout(timeoutMs);
-
- synchronized (mDescriptor) {
- if (mLastSendTimeoutMs != timeoutMs) {
- Os.setsockoptTimeval(mDescriptor,
- OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
- StructTimeval.fromMillis(timeoutMs));
- mLastSendTimeoutMs = timeoutMs;
- }
- }
-
- return (count == Os.write(mDescriptor, bytes, offset, count));
- }
-
- @Override
- public void close() {
- IoUtils.closeQuietly(mDescriptor);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
+ return Os.write(fd, bytes, offset, count);
}
}
diff --git a/services/net/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java
index b68ec0b..e34ec39 100644
--- a/services/net/java/android/net/netlink/StructNdMsg.java
+++ b/services/net/java/android/net/netlink/StructNdMsg.java
@@ -63,6 +63,11 @@
return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0);
}
+ public static boolean isNudStateValid(short nudState) {
+ return (isNudStateConnected(nudState) ||
+ ((nudState & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
+ }
+
// Neighbor Cache Entry Flags
public static byte NTF_USE = (byte) 0x01;
public static byte NTF_SELF = (byte) 0x02;
@@ -143,7 +148,7 @@
}
public boolean nudValid() {
- return (nudConnected() || ((ndm_state & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
+ return isNudStateValid(ndm_state);
}
@Override
diff --git a/services/net/java/android/net/util/BlockingSocketReader.java b/services/net/java/android/net/util/PacketReader.java
similarity index 97%
rename from services/net/java/android/net/util/BlockingSocketReader.java
rename to services/net/java/android/net/util/PacketReader.java
index 99bf469..10da2a5 100644
--- a/services/net/java/android/net/util/BlockingSocketReader.java
+++ b/services/net/java/android/net/util/PacketReader.java
@@ -67,7 +67,7 @@
*
* @hide
*/
-public abstract class BlockingSocketReader {
+public abstract class PacketReader {
private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
private static final int UNREGISTER_THIS_FD = 0;
@@ -83,11 +83,11 @@
IoUtils.closeQuietly(fd);
}
- protected BlockingSocketReader(Handler h) {
+ protected PacketReader(Handler h) {
this(h, DEFAULT_RECV_BUF_SIZE);
}
- protected BlockingSocketReader(Handler h, int recvbufsize) {
+ protected PacketReader(Handler h, int recvbufsize) {
mHandler = h;
mQueue = mHandler.getLooper().getQueue();
mPacket = new byte[Math.max(recvbufsize, DEFAULT_RECV_BUF_SIZE)];
@@ -115,6 +115,8 @@
}
}
+ public Handler getHandler() { return mHandler; }
+
public final int recvBufSize() { return mPacket.length; }
public final long numPacketsReceived() { return mPacketsReceived; }
diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
index f849689..54776db 100644
--- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
+++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
@@ -18,10 +18,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.when;
import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.Looper;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -42,14 +44,18 @@
@Mock IpReachabilityMonitor.Callback mCallback;
@Mock IpReachabilityMonitor.Dependencies mDependencies;
@Mock SharedLog mLog;
+ Handler mHandler;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mLog.forSubComponent(anyString())).thenReturn(mLog);
+ mHandler = new Handler(Looper.getMainLooper());
}
IpReachabilityMonitor makeMonitor() {
- return new IpReachabilityMonitor("fake0", 1, mLog, mCallback, null, mDependencies);
+ return new IpReachabilityMonitor(
+ "fake0", 1, mHandler, mLog, mCallback, null, mDependencies);
}
@Test
diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
index bd36bac8..11be40b 100644
--- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
@@ -16,6 +16,8 @@
package android.net.netlink;
+import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
+import static android.system.OsConstants.NETLINK_ROUTE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -28,10 +30,12 @@
import android.support.test.filters.SmallTest;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
-import android.system.OsConstants;
+import android.system.Os;
import android.util.Log;
+import libcore.io.IoUtils;
import java.io.InterruptedIOException;
+import java.io.FileDescriptor;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -46,29 +50,28 @@
@Test
public void testBasicWorkingGetNeighborsQuery() throws Exception {
- NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
- assertNotNull(s);
+ final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE);
+ assertNotNull(fd);
- s.connectToKernel();
+ NetlinkSocket.connectToKernel(fd);
- NetlinkSocketAddress localAddr = s.getLocalAddress();
+ final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd);
assertNotNull(localAddr);
assertEquals(0, localAddr.getGroupsMask());
assertTrue(0 != localAddr.getPortId());
final int TEST_SEQNO = 5;
- final byte[] request = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
- assertNotNull(request);
+ final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
+ assertNotNull(req);
final long TIMEOUT = 500;
- assertTrue(s.sendMessage(request, 0, request.length, TIMEOUT));
+ assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, TIMEOUT));
int neighMessageCount = 0;
int doneMessageCount = 0;
while (doneMessageCount == 0) {
- ByteBuffer response = null;
- response = s.recvMessage(TIMEOUT);
+ ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT);
assertNotNull(response);
assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit());
assertEquals(0, response.position());
@@ -100,30 +103,6 @@
// TODO: make sure this test passes sanely in airplane mode.
assertTrue(neighMessageCount > 0);
- s.close();
- }
-
- @Test
- public void testRepeatedCloseCallsAreQuiet() throws Exception {
- // Create a working NetlinkSocket.
- NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
- assertNotNull(s);
- s.connectToKernel();
- NetlinkSocketAddress localAddr = s.getLocalAddress();
- assertNotNull(localAddr);
- assertEquals(0, localAddr.getGroupsMask());
- assertTrue(0 != localAddr.getPortId());
- // Close once.
- s.close();
- // Test that it is closed.
- boolean expectedErrorSeen = false;
- try {
- localAddr = s.getLocalAddress();
- } catch (ErrnoException e) {
- expectedErrorSeen = true;
- }
- assertTrue(expectedErrorSeen);
- // Close once more.
- s.close();
+ IoUtils.closeQuietly(fd);
}
}
diff --git a/tests/net/java/android/net/util/BlockingSocketReaderTest.java b/tests/net/java/android/net/util/PacketReaderTest.java
similarity index 91%
rename from tests/net/java/android/net/util/BlockingSocketReaderTest.java
rename to tests/net/java/android/net/util/PacketReaderTest.java
index 29dfa4c..dced743 100644
--- a/tests/net/java/android/net/util/BlockingSocketReaderTest.java
+++ b/tests/net/java/android/net/util/PacketReaderTest.java
@@ -16,7 +16,7 @@
package android.net.util;
-import static android.net.util.BlockingSocketReader.DEFAULT_RECV_BUF_SIZE;
+import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE;
import static android.system.OsConstants.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -53,13 +53,13 @@
import libcore.io.IoBridge;
/**
- * Tests for BlockingSocketReader.
+ * Tests for PacketReader.
*
* @hide
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class BlockingSocketReaderTest {
+public class PacketReaderTest {
static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
@@ -69,9 +69,9 @@
protected byte[] mLastRecvBuf;
protected boolean mStopped;
protected HandlerThread mHandlerThread;
- protected BlockingSocketReader mReceiver;
+ protected PacketReader mReceiver;
- class UdpLoopbackReader extends BlockingSocketReader {
+ class UdpLoopbackReader extends PacketReader {
public UdpLoopbackReader(Handler h) {
super(h);
}
@@ -121,7 +121,7 @@
mLastRecvBuf = null;
mStopped = false;
- mHandlerThread = new HandlerThread(BlockingSocketReaderTest.class.getSimpleName());
+ mHandlerThread = new HandlerThread(PacketReaderTest.class.getSimpleName());
mHandlerThread.start();
}
@@ -188,8 +188,8 @@
mReceiver = null;
}
- class NullBlockingSocketReader extends BlockingSocketReader {
- public NullBlockingSocketReader(Handler h, int recvbufsize) {
+ class NullPacketReader extends PacketReader {
+ public NullPacketReader(Handler h, int recvbufsize) {
super(h, recvbufsize);
}
@@ -202,7 +202,7 @@
final Handler h = mHandlerThread.getThreadHandler();
for (int i : new int[]{-1, 0, 1, DEFAULT_RECV_BUF_SIZE-1}) {
- final BlockingSocketReader b = new NullBlockingSocketReader(h, i);
+ final PacketReader b = new NullPacketReader(h, i);
assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize());
}
}