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