IpConn metrics: distinguish NUD_FAILED answers

This patch adds in IpReachabilityMonitor a timestamp variable set
everytime that probeAll() send NUD probe requests to RTNETLINK.
This allows to distinguish between:
  1) NUD_FAILED events resulting from such a forced NUD probe
  2) "organic" NUD_FAILED notifications from the kernel

This distinction is added to IpReachabilityEvent as a one-bit flag.

This patch also changes the formatting of ApfProgramEvent flags to use
'|' as a joining character, similarly to other flags formatting.

Bug: 21859053
Change-Id: I24c64a3f17fa283eace5bd0a05c21a90a2305359
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index 7d02291..ee09e22 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -24,21 +24,31 @@
 import com.android.internal.util.MessageUtils;
 
 /**
+ * An event recorded when IpReachabilityMonitor sends a neighbor probe or receives
+ * a neighbor probe result.
  * {@hide}
  */
 @SystemApi
 public final class IpReachabilityEvent 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;
+    // Event types.
+    /** A probe forced by IpReachabilityMonitor. */
+    public static final int PROBE                     = 1 << 8;
+    /** Neighbor unreachable after a forced probe. */
+    public static final int NUD_FAILED                = 2 << 8;
+    /** Neighbor unreachable after a forced probe, IP provisioning is also lost. */
+    public static final int PROVISIONING_LOST         = 3 << 8;
+    /** {@hide} Neighbor unreachable notification from kernel. */
+    public static final int NUD_FAILED_ORGANIC        = 4 << 8;
+    /** {@hide} Neighbor unreachable notification from kernel, IP provisioning is also lost. */
+    public static final int PROVISIONING_LOST_ORGANIC = 5 << 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
+    // byte 3: when byte 2 == PROBE, errno code from RTNetlink or IpReachabilityMonitor.
     public final int eventType;
 
     /** {@hide} */
@@ -52,11 +62,13 @@
         this.eventType = in.readInt();
     }
 
+    @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(ifName);
         out.writeInt(eventType);
     }
 
+    @Override
     public int describeContents() {
         return 0;
     }
@@ -81,10 +93,24 @@
     public static void logProvisioningLost(String ifName) {
     }
 
+    /**
+     * Returns the NUD failure event type code corresponding to the given conditions.
+     * {@hide}
+     */
+    public static int nudFailureEventType(boolean isFromProbe, boolean isProvisioningLost) {
+        if (isFromProbe) {
+            return isProvisioningLost ? PROVISIONING_LOST : NUD_FAILED;
+        } else {
+            return isProvisioningLost ? PROVISIONING_LOST_ORGANIC : NUD_FAILED_ORGANIC;
+        }
+    }
+
     @Override
     public String toString() {
-        return String.format("IpReachabilityEvent(%s, %s)", ifName,
-                Decoder.constants.get(eventType));
+        int hi = eventType & 0xff00;
+        int lo = eventType & 0x00ff;
+        String eventName = Decoder.constants.get(hi);
+        return String.format("IpReachabilityEvent(%s, %s:%02x)", ifName, eventName, lo);
     }
 
     final static class Decoder {