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