Various fixes in IpReachability event logging

- fold IpReachabilityMonitor* classes into a single IpReachabilityEvent.
- only log an event for NUD_FAILED Netlink answers.
- distinguish between NUD_FAILED with or without lost of provisioning.
- do not record host ip addresses.
- record interface name instead of interface index when losing
  provisioning.

- also return an error code when probeNeighbor fails, and log this error
  code in IpReachability events.

Bug: 28204408
Change-Id: I5f0def0ab1ace7e467a0c69b3b82d07ef2252307
This commit is contained in:
Hugo Benichi
2016-04-19 09:52:39 +09:00
parent 75fe7d5d79
commit 25bf8f5d56
7 changed files with 134 additions and 263 deletions

View File

@ -26111,9 +26111,10 @@ package android.net.metrics {
field public static final int IPCE_IPMGR_PROVISIONING_FAIL = 4097; // 0x1001
field public static final int IPCE_IPMGR_PROVISIONING_OK = 4096; // 0x1000
field public static final int IPCE_IPRM_BASE = 0; // 0x0
field public static final int IPCE_IPRM_MESSAGE_RECEIVED = 1; // 0x1
field public static final int IPCE_IPRM_PROBE_RESULT = 0; // 0x0
field public static final int IPCE_IPRM_REACHABILITY_LOST = 2; // 0x2
field public static final int IPCE_IPRM_NUD_FAILED = 2; // 0x2
field public static final int IPCE_IPRM_PROBE_FAILURE = 1; // 0x1
field public static final int IPCE_IPRM_PROBE_STARTED = 0; // 0x0
field public static final int IPCE_IPRM_PROVISIONING_LOST = 3; // 0x3
field public static final int IPCE_NETMON_BASE = 2048; // 0x800
field public static final int IPCE_NETMON_CHECK_RESULT = 2049; // 0x801
field public static final int IPCE_NETMON_STATE_CHANGE = 2048; // 0x800
@ -26128,35 +26129,20 @@ package android.net.metrics {
field public final java.lang.String ifName;
}
public final class IpReachabilityMonitorLostEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
public final class IpReachabilityEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
method public int describeContents();
method public static void logEvent(java.lang.String);
method public static void logNudFailed(java.lang.String);
method public static void logProbeEvent(java.lang.String, int);
method public static void logProvisioningLost(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorLostEvent> CREATOR;
field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityEvent> CREATOR;
field public static final int NUD_FAILED = 512; // 0x200
field public static final int PROBE = 256; // 0x100
field public static final int PROVISIONING_LOST = 768; // 0x300
field public final int eventType;
field public final java.lang.String ifName;
}
public final class IpReachabilityMonitorMessageEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
method public int describeContents();
method public static void logEvent(java.lang.String, java.lang.String, int, int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorMessageEvent> CREATOR;
field public final java.lang.String destination;
field public final java.lang.String ifName;
field public final int msgType;
field public final int nudState;
}
public final class IpReachabilityMonitorProbeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
method public int describeContents();
method public static void logEvent(java.lang.String, java.lang.String, boolean);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorProbeEvent> CREATOR;
field public final java.lang.String destination;
field public final java.lang.String ifName;
field public final boolean success;
}
}
package android.net.nsd {

View File

@ -39,9 +39,10 @@ public abstract class IpConnectivityEvent {
public static final int IPCE_IPMGR_BASE = 4 * 1024;
public static final int IPCE_DNS_BASE = 5 * 1024;
public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0;
public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1;
public static final int IPCE_IPRM_REACHABILITY_LOST = IPCE_IPRM_BASE + 2;
public static final int IPCE_IPRM_PROBE_STARTED = IPCE_IPRM_BASE + 0;
public static final int IPCE_IPRM_PROBE_FAILURE = IPCE_IPRM_BASE + 1;
public static final int IPCE_IPRM_NUD_FAILED = IPCE_IPRM_BASE + 2;
public static final int IPCE_IPRM_PROVISIONING_LOST = IPCE_IPRM_BASE + 3;
public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2016 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.metrics;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* {@hide}
*/
@SystemApi
public final class IpReachabilityEvent extends IpConnectivityEvent implements Parcelable {
public static final int PROBE = 1 << 8;
public static final int NUD_FAILED = 2 << 8;
public static final int PROVISIONING_LOST = 3 << 8;
public final String ifName;
// eventType byte format (MSB to LSB):
// byte 0: unused
// byte 1: unused
// byte 2: type of event: PROBE, NUD_FAILED, PROVISIONING_LOST
// byte 3: kernel errno from RTNetlink or IpReachabilityMonitor
public final int eventType;
private IpReachabilityEvent(String ifName, int eventType) {
this.ifName = ifName;
this.eventType = eventType;
}
private IpReachabilityEvent(Parcel in) {
this.ifName = in.readString();
this.eventType = in.readInt();
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
out.writeInt(eventType);
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<IpReachabilityEvent> CREATOR
= new Parcelable.Creator<IpReachabilityEvent>() {
public IpReachabilityEvent createFromParcel(Parcel in) {
return new IpReachabilityEvent(in);
}
public IpReachabilityEvent[] newArray(int size) {
return new IpReachabilityEvent[size];
}
};
public static void logProbeEvent(String ifName, int nlErrorCode) {
final int tag = (nlErrorCode == 0) ? IPCE_IPRM_PROBE_STARTED : IPCE_IPRM_PROBE_FAILURE;
final int eventType = PROBE | (nlErrorCode & 0xFF);
logEvent(tag, new IpReachabilityEvent(ifName, eventType));
}
public static void logNudFailed(String ifName) {
logEvent(IPCE_IPRM_NUD_FAILED, new IpReachabilityEvent(ifName, NUD_FAILED));
}
public static void logProvisioningLost(String ifName) {
logEvent(IPCE_IPRM_PROVISIONING_LOST, new IpReachabilityEvent(ifName, PROVISIONING_LOST));
}
};

View File

@ -1,61 +0,0 @@
/*
* Copyright (C) 2016 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.metrics;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* {@hide}
*/
@SystemApi
public final class IpReachabilityMonitorLostEvent extends IpConnectivityEvent
implements Parcelable {
public final String ifName;
private IpReachabilityMonitorLostEvent(String ifName) {
this.ifName = ifName;
}
private IpReachabilityMonitorLostEvent(Parcel in) {
this.ifName = in.readString();
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<IpReachabilityMonitorLostEvent> CREATOR
= new Parcelable.Creator<IpReachabilityMonitorLostEvent>() {
public IpReachabilityMonitorLostEvent createFromParcel(Parcel in) {
return new IpReachabilityMonitorLostEvent(in);
}
public IpReachabilityMonitorLostEvent[] newArray(int size) {
return new IpReachabilityMonitorLostEvent[size];
}
};
public static void logEvent(String ifName) {
logEvent(IPCE_IPRM_REACHABILITY_LOST, new IpReachabilityMonitorLostEvent(ifName));
}
};

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 2016 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.metrics;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* {@hide}
*/
@SystemApi
public final class IpReachabilityMonitorMessageEvent extends IpConnectivityEvent
implements Parcelable {
public final String ifName;
public final String destination;
public final int msgType;
public final int nudState;
private IpReachabilityMonitorMessageEvent(String ifName, String destination, int msgType,
int nudState) {
this.ifName = ifName;
this.destination = destination;
this.msgType = msgType;
this.nudState = nudState;
}
private IpReachabilityMonitorMessageEvent(Parcel in) {
this.ifName = in.readString();
this.destination = in.readString();
this.msgType = in.readInt();
this.nudState = in.readInt();
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
out.writeString(destination);
out.writeInt(msgType);
out.writeInt(nudState);
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<IpReachabilityMonitorMessageEvent> CREATOR
= new Parcelable.Creator<IpReachabilityMonitorMessageEvent>() {
public IpReachabilityMonitorMessageEvent createFromParcel(Parcel in) {
return new IpReachabilityMonitorMessageEvent(in);
}
public IpReachabilityMonitorMessageEvent[] newArray(int size) {
return new IpReachabilityMonitorMessageEvent[size];
}
};
public static void logEvent(String ifName, String destination, int msgType, int nudState) {
logEvent(IPCE_IPRM_MESSAGE_RECEIVED,
new IpReachabilityMonitorMessageEvent(ifName, destination, msgType, nudState));
}
};

View File

@ -1,70 +0,0 @@
/*
* Copyright (C) 2016 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.metrics;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* {@hide}
*/
@SystemApi
public final class IpReachabilityMonitorProbeEvent extends IpConnectivityEvent
implements Parcelable {
public final String ifName;
public final String destination;
public final boolean success;
private IpReachabilityMonitorProbeEvent(String ifName, String destination, boolean success) {
this.ifName = ifName;
this.destination = destination;
this.success = success;
}
private IpReachabilityMonitorProbeEvent(Parcel in) {
this.ifName = in.readString();
this.destination = in.readString();
this.success = in.readByte() > 0 ? true : false;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
out.writeString(destination);
out.writeByte((byte)(success ? 1 : 0));
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<IpReachabilityMonitorProbeEvent> CREATOR
= new Parcelable.Creator<IpReachabilityMonitorProbeEvent>() {
public IpReachabilityMonitorProbeEvent createFromParcel(Parcel in) {
return new IpReachabilityMonitorProbeEvent(in);
}
public IpReachabilityMonitorProbeEvent[] newArray(int size) {
return new IpReachabilityMonitorProbeEvent[size];
}
};
public static void logEvent(String ifName, String destination, boolean success) {
logEvent(IPCE_IPRM_PROBE_RESULT,
new IpReachabilityMonitorProbeEvent(ifName, destination, success));
}
};

View File

@ -24,9 +24,7 @@ import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.metrics.IpReachabilityMonitorMessageEvent;
import android.net.metrics.IpReachabilityMonitorProbeEvent;
import android.net.metrics.IpReachabilityMonitorLostEvent;
import android.net.metrics.IpReachabilityEvent;
import android.net.netlink.NetlinkConstants;
import android.net.netlink.NetlinkErrorMessage;
import android.net.netlink.NetlinkMessage;
@ -168,47 +166,54 @@ public class IpReachabilityMonitor {
* Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
* for the given IP address on the specified interface index.
*
* @return true, if the request was successfully passed to the kernel; false otherwise.
* @return 0 if the request was successfully passed to the kernel; otherwise return
* a non-zero error code.
*/
public static boolean probeNeighbor(int ifIndex, InetAddress ip) {
final long IO_TIMEOUT = 300L;
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);
boolean returnValue = false;
int errno = -OsConstants.EPROTO;
try (NetlinkSocket nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE)) {
final long IO_TIMEOUT = 300L;
nlSocket.connectToKernel();
nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
final ByteBuffer bytes = nlSocket.recvMessage(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 &&
(((NetlinkErrorMessage) response).getNlMsgError() != null) &&
(((NetlinkErrorMessage) response).getNlMsgError().error == 0)) {
returnValue = true;
} else {
String errmsg;
if (bytes == null) {
errmsg = "null recvMessage";
} else if (response == null) {
bytes.position(0);
errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
} else {
(((NetlinkErrorMessage) response).getNlMsgError() != null)) {
errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
if (errno != 0) {
// TODO: consider ignoring EINVAL (-22), which appears to be
// normal when probing a neighbor for which the kernel does
// not already have / no longer has a link layer address.
Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + response.toString());
}
} else {
String errmsg;
if (response == null) {
bytes.position(0);
errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
} else {
errmsg = response.toString();
}
Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + errmsg);
}
} catch (ErrnoException | InterruptedIOException | SocketException e) {
Log.d(TAG, "Error " + msgSnippet, e);
} catch (ErrnoException e) {
Log.e(TAG, "Error " + msgSnippet, e);
errno = -e.errno;
} catch (InterruptedIOException e) {
Log.e(TAG, "Error " + msgSnippet, e);
errno = -OsConstants.ETIMEDOUT;
} catch (SocketException e) {
Log.e(TAG, "Error " + msgSnippet, e);
errno = -OsConstants.EIO;
}
IpReachabilityMonitorProbeEvent.logEvent("ifindex-" + ifIndex, ip.getHostAddress(),
returnValue);
return returnValue;
return errno;
}
public IpReachabilityMonitor(Context context, String ifName, Callback callback)
@ -354,7 +359,7 @@ public class IpReachabilityMonitor {
}
if (delta == ProvisioningChange.LOST_PROVISIONING) {
IpReachabilityMonitorLostEvent.logEvent(mInterfaceName);
IpReachabilityEvent.logProvisioningLost(mInterfaceName);
final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
Log.w(TAG, logMsg);
if (mCallback != null) {
@ -362,6 +367,8 @@ public class IpReachabilityMonitor {
// an InetAddress argument.
mCallback.notifyLost(ip, logMsg);
}
} else {
IpReachabilityEvent.logNudFailed(mInterfaceName);
}
}
@ -385,7 +392,8 @@ public class IpReachabilityMonitor {
if (!stillRunning()) {
break;
}
probeNeighbor(mInterfaceIndex, target);
final int returnValue = probeNeighbor(mInterfaceIndex, target);
IpReachabilityEvent.logProbeEvent(mInterfaceName, returnValue);
}
}
@ -523,8 +531,6 @@ public class IpReachabilityMonitor {
final short msgType = neighMsg.getHeader().nlmsg_type;
final short nudState = ndMsg.ndm_state;
IpReachabilityMonitorMessageEvent.logEvent(mInterfaceName,
destination.getHostAddress(), msgType, nudState);
final String eventMsg = "NeighborEvent{"
+ "elapsedMs=" + whenMs + ", "
+ destination.getHostAddress() + ", "