1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.metrics; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.annotation.TestApi; 23 import android.annotation.UnsupportedAppUsage; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.text.TextUtils; 27 import android.util.SparseArray; 28 29 import com.android.internal.util.MessageUtils; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.util.ArrayList; 34 import java.util.BitSet; 35 import java.util.List; 36 37 /** 38 * An event logged when there is a change or event that requires updating the 39 * the APF program in place with a new APF program. 40 * {@hide} 41 */ 42 @TestApi 43 @SystemApi 44 public final class ApfProgramEvent implements IpConnectivityLog.Event { 45 46 // Bitflag constants describing what an Apf program filters. 47 // Bits are indexeds from LSB to MSB, starting at index 0. 48 /** @hide */ 49 public static final int FLAG_MULTICAST_FILTER_ON = 0; 50 /** @hide */ 51 public static final int FLAG_HAS_IPV4_ADDRESS = 1; 52 53 /** {@hide} */ 54 @IntDef(flag = true, value = {FLAG_MULTICAST_FILTER_ON, FLAG_HAS_IPV4_ADDRESS}) 55 @Retention(RetentionPolicy.SOURCE) 56 public @interface Flags {} 57 58 /** @hide */ 59 @UnsupportedAppUsage 60 public final long lifetime; // Maximum computed lifetime of the program in seconds 61 /** @hide */ 62 @UnsupportedAppUsage 63 public final long actualLifetime; // Effective program lifetime in seconds 64 /** @hide */ 65 @UnsupportedAppUsage 66 public final int filteredRas; // Number of RAs filtered by the APF program 67 /** @hide */ 68 @UnsupportedAppUsage 69 public final int currentRas; // Total number of current RAs at generation time 70 /** @hide */ 71 @UnsupportedAppUsage 72 public final int programLength; // Length of the APF program in bytes 73 /** @hide */ 74 @UnsupportedAppUsage 75 public final int flags; // Bitfield compound of FLAG_* constants 76 ApfProgramEvent(long lifetime, long actualLifetime, int filteredRas, int currentRas, int programLength, int flags)77 private ApfProgramEvent(long lifetime, long actualLifetime, int filteredRas, int currentRas, 78 int programLength, int flags) { 79 this.lifetime = lifetime; 80 this.actualLifetime = actualLifetime; 81 this.filteredRas = filteredRas; 82 this.currentRas = currentRas; 83 this.programLength = programLength; 84 this.flags = flags; 85 } 86 ApfProgramEvent(Parcel in)87 private ApfProgramEvent(Parcel in) { 88 this.lifetime = in.readLong(); 89 this.actualLifetime = in.readLong(); 90 this.filteredRas = in.readInt(); 91 this.currentRas = in.readInt(); 92 this.programLength = in.readInt(); 93 this.flags = in.readInt(); 94 } 95 96 /** 97 * Utility to create an instance of {@link ApfProgramEvent}. 98 */ 99 public static final class Builder { 100 private long mLifetime; 101 private long mActualLifetime; 102 private int mFilteredRas; 103 private int mCurrentRas; 104 private int mProgramLength; 105 private int mFlags; 106 107 /** 108 * Set the maximum computed lifetime of the program in seconds. 109 */ 110 @NonNull setLifetime(long lifetime)111 public Builder setLifetime(long lifetime) { 112 mLifetime = lifetime; 113 return this; 114 } 115 116 /** 117 * Set the effective program lifetime in seconds. 118 */ 119 @NonNull setActualLifetime(long lifetime)120 public Builder setActualLifetime(long lifetime) { 121 mActualLifetime = lifetime; 122 return this; 123 } 124 125 /** 126 * Set the number of RAs filtered by the APF program. 127 */ 128 @NonNull setFilteredRas(int filteredRas)129 public Builder setFilteredRas(int filteredRas) { 130 mFilteredRas = filteredRas; 131 return this; 132 } 133 134 /** 135 * Set the total number of current RAs at generation time. 136 */ 137 @NonNull setCurrentRas(int currentRas)138 public Builder setCurrentRas(int currentRas) { 139 mCurrentRas = currentRas; 140 return this; 141 } 142 143 /** 144 * Set the length of the APF program in bytes. 145 */ 146 @NonNull setProgramLength(int programLength)147 public Builder setProgramLength(int programLength) { 148 mProgramLength = programLength; 149 return this; 150 } 151 152 /** 153 * Set the flags describing what an Apf program filters. 154 */ 155 @NonNull setFlags(boolean hasIPv4, boolean multicastFilterOn)156 public Builder setFlags(boolean hasIPv4, boolean multicastFilterOn) { 157 mFlags = flagsFor(hasIPv4, multicastFilterOn); 158 return this; 159 } 160 161 /** 162 * Build a new {@link ApfProgramEvent}. 163 */ 164 @NonNull build()165 public ApfProgramEvent build() { 166 return new ApfProgramEvent(mLifetime, mActualLifetime, mFilteredRas, mCurrentRas, 167 mProgramLength, mFlags); 168 } 169 } 170 171 /** @hide */ 172 @Override writeToParcel(Parcel out, int flags)173 public void writeToParcel(Parcel out, int flags) { 174 out.writeLong(lifetime); 175 out.writeLong(actualLifetime); 176 out.writeInt(filteredRas); 177 out.writeInt(currentRas); 178 out.writeInt(programLength); 179 out.writeInt(this.flags); 180 } 181 182 /** @hide */ 183 @Override describeContents()184 public int describeContents() { 185 return 0; 186 } 187 188 @Override toString()189 public String toString() { 190 String lifetimeString = (lifetime < Long.MAX_VALUE) ? lifetime + "s" : "forever"; 191 return String.format("ApfProgramEvent(%d/%d RAs %dB %ds/%s %s)", filteredRas, currentRas, 192 programLength, actualLifetime, lifetimeString, namesOf(flags)); 193 } 194 195 @Override equals(Object obj)196 public boolean equals(Object obj) { 197 if (obj == null || !(obj.getClass().equals(ApfProgramEvent.class))) return false; 198 final ApfProgramEvent other = (ApfProgramEvent) obj; 199 return lifetime == other.lifetime 200 && actualLifetime == other.actualLifetime 201 && filteredRas == other.filteredRas 202 && currentRas == other.currentRas 203 && programLength == other.programLength 204 && flags == other.flags; 205 } 206 207 /** @hide */ 208 public static final @android.annotation.NonNull Parcelable.Creator<ApfProgramEvent> CREATOR 209 = new Parcelable.Creator<ApfProgramEvent>() { 210 public ApfProgramEvent createFromParcel(Parcel in) { 211 return new ApfProgramEvent(in); 212 } 213 214 public ApfProgramEvent[] newArray(int size) { 215 return new ApfProgramEvent[size]; 216 } 217 }; 218 219 /** @hide */ 220 @UnsupportedAppUsage flagsFor(boolean hasIPv4, boolean multicastFilterOn)221 public static @Flags int flagsFor(boolean hasIPv4, boolean multicastFilterOn) { 222 int bitfield = 0; 223 if (hasIPv4) { 224 bitfield |= (1 << FLAG_HAS_IPV4_ADDRESS); 225 } 226 if (multicastFilterOn) { 227 bitfield |= (1 << FLAG_MULTICAST_FILTER_ON); 228 } 229 return bitfield; 230 } 231 namesOf(@lags int bitfield)232 private static String namesOf(@Flags int bitfield) { 233 List<String> names = new ArrayList<>(Integer.bitCount(bitfield)); 234 BitSet set = BitSet.valueOf(new long[]{bitfield & Integer.MAX_VALUE}); 235 // Only iterate over flag bits which are set. 236 for (int bit = set.nextSetBit(0); bit >= 0; bit = set.nextSetBit(bit+1)) { 237 names.add(Decoder.constants.get(bit)); 238 } 239 return TextUtils.join("|", names); 240 } 241 242 final static class Decoder { 243 static final SparseArray<String> constants = 244 MessageUtils.findMessageNames( 245 new Class[]{ApfProgramEvent.class}, new String[]{"FLAG_"}); 246 } 247 } 248