Log events at APF program generation

Example:
ConnectivityMetricsEvent(15:24:52.018, 0, 0): ApfProgramEvent(0/0 RAs 121B forever FLAG_MULTICAST_FILTER_ON)
ConnectivityMetricsEvent(15:24:53.036, 0, 0): ApfProgramEvent(1/1 RAs 334B 600s)
ConnectivityMetricsEvent(15:24:53.590, 0, 0): ApfProgramEvent(1/1 RAs 360B 600s FLAG_MULTICAST_FILTER_ON, FLAG_HAS_IPV4_ADDRESS)
ConnectivityMetricsEvent(15:24:58.157, 0, 0): ApfProgramEvent(1/1 RAs 294B 599s FLAG_HAS_IPV4_ADDRESS)

Bug: 28204408
Change-Id: I9c4c82861cf42eb2c7e7bf5471f05e8ff2fc560c
This commit is contained in:
Hugo Benichi
2016-06-02 11:20:27 +09:00
parent 5e055187be
commit 4fc3ee5be2
6 changed files with 169 additions and 7 deletions

View File

@@ -26018,6 +26018,19 @@ package android.net.http {
package android.net.metrics {
public final class ApfProgramEvent implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.metrics.ApfProgramEvent> CREATOR;
field public static final int FLAG_HAS_IPV4_ADDRESS = 1; // 0x1
field public static final int FLAG_MULTICAST_FILTER_ON = 0; // 0x0
field public final int currentRas;
field public final int filteredRas;
field public final int flags;
field public final long lifetime;
field public final int programLength;
}
public final class DefaultNetworkEvent implements android.os.Parcelable {
method public int describeContents();
method public static void logEvent(int, int[], int, boolean, boolean);

View File

@@ -0,0 +1,137 @@
/*
* 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;
import android.util.SparseArray;
import java.util.Arrays;
import java.util.stream.Collectors;
import com.android.internal.util.MessageUtils;
/**
* An event logged when there is a change or event that requires updating the
* the APF program in place with a new APF program.
* {@hide}
*/
@SystemApi
public final class ApfProgramEvent implements Parcelable {
// Bitflag constants describing what an Apf program filters.
// Bits are indexeds from LSB to MSB, starting at index 0.
// TODO: use @IntDef
public static final int FLAG_MULTICAST_FILTER_ON = 0;
public static final int FLAG_HAS_IPV4_ADDRESS = 1;
public final long lifetime; // Lifetime of the program in seconds
public final int filteredRas; // Number of RAs filtered by the APF program
public final int currentRas; // Total number of current RAs at generation time
public final int programLength; // Length of the APF program in bytes
public final int flags; // Bitfield compound of FLAG_* constants
/** {@hide} */
public ApfProgramEvent(
long lifetime, int filteredRas, int currentRas, int programLength, int flags) {
this.lifetime = lifetime;
this.filteredRas = filteredRas;
this.currentRas = currentRas;
this.programLength = programLength;
this.flags = flags;
}
private ApfProgramEvent(Parcel in) {
this.lifetime = in.readLong();
this.filteredRas = in.readInt();
this.currentRas = in.readInt();
this.programLength = in.readInt();
this.flags = in.readInt();
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeLong(lifetime);
out.writeInt(filteredRas);
out.writeInt(currentRas);
out.writeInt(programLength);
out.writeInt(flags);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
String lifetimeString = (lifetime < Long.MAX_VALUE) ? lifetime + "s" : "forever";
return String.format("ApfProgramEvent(%d/%d RAs %dB %s %s)",
filteredRas, currentRas, programLength, lifetimeString, namesOf(flags));
}
public static final Parcelable.Creator<ApfProgramEvent> CREATOR
= new Parcelable.Creator<ApfProgramEvent>() {
public ApfProgramEvent createFromParcel(Parcel in) {
return new ApfProgramEvent(in);
}
public ApfProgramEvent[] newArray(int size) {
return new ApfProgramEvent[size];
}
};
/** {@hide} */
public static int flagsFor(boolean hasIPv4, boolean multicastFilterOn) {
int bitfield = 0;
if (hasIPv4) {
bitfield |= (1 << FLAG_HAS_IPV4_ADDRESS);
}
if (multicastFilterOn) {
bitfield |= (1 << FLAG_MULTICAST_FILTER_ON);
}
return bitfield;
}
// TODO: consider using java.util.BitSet
private static int[] bitflagsOf(int bitfield) {
int[] flags = new int[Integer.bitCount(bitfield)];
int i = 0;
int bitflag = 0;
while (bitfield != 0) {
if ((bitfield & 1) != 0) {
flags[i++] = bitflag;
}
bitflag++;
bitfield = bitfield >>> 1;
}
return flags;
}
private static String namesOf(int bitfields) {
return Arrays.stream(bitflagsOf(bitfields))
.mapToObj(i -> Decoder.constants.get(i))
.collect(Collectors.joining(", "));
}
final static class Decoder {
static final SparseArray<String> constants =
MessageUtils.findMessageNames(
new Class[]{ApfProgramEvent.class}, new String[]{"FLAG_"});
}
}

View File

@@ -29,6 +29,7 @@ import com.android.internal.util.MessageUtils;
@SystemApi
public final class IpManagerEvent implements Parcelable {
// TODO: use @IntDef
public static final int PROVISIONING_OK = 1;
public static final int PROVISIONING_FAIL = 2;
public static final int COMPLETE_LIFECYCLE = 3;

View File

@@ -29,6 +29,7 @@ import com.android.internal.util.MessageUtils;
@SystemApi
public final class ValidationProbeEvent implements Parcelable {
// TODO: use @IntDef
public static final int PROBE_DNS = 0;
public static final int PROBE_HTTP = 1;
public static final int PROBE_HTTPS = 2;

View File

@@ -24,9 +24,12 @@ import android.net.apf.ApfGenerator;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpManager;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.IpConnectivityLog;
import android.system.ErrnoException;
import android.system.Os;
import android.system.PacketSocketAddress;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Pair;
@@ -140,7 +143,7 @@ public class ApfFilter {
// NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
private static int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
0, 1, // Hardware type: Ethernet (1)
8, 0, // Protocol type: IP (0x0800)
@@ -148,11 +151,12 @@ public class ApfFilter {
4, // Protocol size: 4
0, 1 // Opcode: request (1)
};
private static int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
private final ApfCapabilities mApfCapabilities;
private final IpManager.Callback mIpManagerCallback;
private final NetworkInterface mNetworkInterface;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
@VisibleForTesting
byte[] mHardwareAddress;
@VisibleForTesting
@@ -213,7 +217,7 @@ public class ApfFilter {
// Returns seconds since Unix Epoch.
private static long curTime() {
return System.currentTimeMillis() / 1000L;
return System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS;
}
// A class to hold information about an RA.
@@ -760,16 +764,19 @@ public class ApfFilter {
return gen;
}
/**
* Generate and install a new filter program.
*/
@GuardedBy("this")
@VisibleForTesting
void installNewProgramLocked() {
purgeExpiredRasLocked();
ArrayList<Ra> rasToFilter = new ArrayList<>();
final byte[] program;
long programMinLifetime = Long.MAX_VALUE;
try {
// Step 1: Determine how many RA filters we can fit in the program.
ApfGenerator gen = beginProgramLocked();
ArrayList<Ra> rasToFilter = new ArrayList<Ra>();
for (Ra ra : mRas) {
ra.generateFilterLocked(gen);
// Stop if we get too big.
@@ -797,6 +804,9 @@ public class ApfFilter {
hexDump("Installing filter: ", program, program.length);
}
mIpManagerCallback.installPacketFilter(program);
int flags = ApfProgramEvent.flagsFor(mIPv4Address != null, mMulticastFilter);
mMetricsLog.log(new ApfProgramEvent(
programMinLifetime, rasToFilter.size(), mRas.size(), program.length, flags));
}
// Install a new filter program if the last installed one will die soon.

View File

@@ -652,7 +652,7 @@ public class ApfTest extends AndroidTestCase {
private static final int DHCP_CLIENT_PORT = 68;
private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
private static int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
0, 1, // Hardware type: Ethernet (1)
8, 0, // Protocol type: IP (0x0800)
@@ -660,9 +660,9 @@ public class ApfTest extends AndroidTestCase {
4, // Protocol size: 4
0, 1 // Opcode: request (1)
};
private static int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
private static byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
@LargeTest
public void testApfFilterIPv4() throws Exception {