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:
@@ -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);
|
||||
|
||||
137
core/java/android/net/metrics/ApfProgramEvent.java
Normal file
137
core/java/android/net/metrics/ApfProgramEvent.java
Normal 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_"});
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user