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
17package android.net.metrics;
18
19import android.annotation.IntDef;
20import android.os.Parcel;
21import android.os.Parcelable;
22import android.text.TextUtils;
23import android.util.SparseArray;
24
25import com.android.internal.util.MessageUtils;
26
27import java.lang.annotation.Retention;
28import java.lang.annotation.RetentionPolicy;
29import java.util.ArrayList;
30import java.util.BitSet;
31import java.util.List;
32
33/**
34 * An event logged when there is a change or event that requires updating the
35 * the APF program in place with a new APF program.
36 * {@hide}
37 */
38public final class ApfProgramEvent implements Parcelable {
39
40    // Bitflag constants describing what an Apf program filters.
41    // Bits are indexeds from LSB to MSB, starting at index 0.
42    public static final int FLAG_MULTICAST_FILTER_ON = 0;
43    public static final int FLAG_HAS_IPV4_ADDRESS    = 1;
44
45    /** {@hide} */
46    @IntDef(flag = true, value = {FLAG_MULTICAST_FILTER_ON, FLAG_HAS_IPV4_ADDRESS})
47    @Retention(RetentionPolicy.SOURCE)
48    public @interface Flags {}
49
50    public long lifetime;       // Maximum computed lifetime of the program in seconds
51    public long actualLifetime; // Effective program lifetime in seconds
52    public int filteredRas;     // Number of RAs filtered by the APF program
53    public int currentRas;      // Total number of current RAs at generation time
54    public int programLength;   // Length of the APF program in bytes
55    public int flags;           // Bitfield compound of FLAG_* constants
56
57    public ApfProgramEvent() {
58    }
59
60    private ApfProgramEvent(Parcel in) {
61        this.lifetime = in.readLong();
62        this.actualLifetime = in.readLong();
63        this.filteredRas = in.readInt();
64        this.currentRas = in.readInt();
65        this.programLength = in.readInt();
66        this.flags = in.readInt();
67    }
68
69    @Override
70    public void writeToParcel(Parcel out, int flags) {
71        out.writeLong(lifetime);
72        out.writeLong(actualLifetime);
73        out.writeInt(filteredRas);
74        out.writeInt(currentRas);
75        out.writeInt(programLength);
76        out.writeInt(flags);
77    }
78
79    @Override
80    public int describeContents() {
81        return 0;
82    }
83
84    @Override
85    public String toString() {
86        String lifetimeString = (lifetime < Long.MAX_VALUE) ? lifetime + "s" : "forever";
87        return String.format("ApfProgramEvent(%d/%d RAs %dB %ds/%s %s)", filteredRas, currentRas,
88                programLength, actualLifetime, lifetimeString, namesOf(flags));
89    }
90
91    public static final Parcelable.Creator<ApfProgramEvent> CREATOR
92            = new Parcelable.Creator<ApfProgramEvent>() {
93        public ApfProgramEvent createFromParcel(Parcel in) {
94            return new ApfProgramEvent(in);
95        }
96
97        public ApfProgramEvent[] newArray(int size) {
98            return new ApfProgramEvent[size];
99        }
100    };
101
102    public static @Flags int flagsFor(boolean hasIPv4, boolean multicastFilterOn) {
103        int bitfield = 0;
104        if (hasIPv4) {
105            bitfield |= (1 << FLAG_HAS_IPV4_ADDRESS);
106        }
107        if (multicastFilterOn) {
108            bitfield |= (1 << FLAG_MULTICAST_FILTER_ON);
109        }
110        return bitfield;
111    }
112
113    private static String namesOf(@Flags int bitfield) {
114        List<String> names = new ArrayList<>(Integer.bitCount(bitfield));
115        BitSet set = BitSet.valueOf(new long[]{bitfield & Integer.MAX_VALUE});
116        // Only iterate over flag bits which are set.
117        for (int bit = set.nextSetBit(0); bit >= 0; bit = set.nextSetBit(bit+1)) {
118            names.add(Decoder.constants.get(bit));
119        }
120        return TextUtils.join("|", names);
121    }
122
123    final static class Decoder {
124        static final SparseArray<String> constants =
125                MessageUtils.findMessageNames(
126                       new Class[]{ApfProgramEvent.class}, new String[]{"FLAG_"});
127    }
128}
129