1 /*
2  * Copyright (C) 2022 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 com.android.net.module.util;
18 
19 import android.os.Build;
20 import android.system.ErrnoException;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.RequiresApi;
24 
25  /**
26  *
27  * Generic bitmap class for use with BPF programs. Corresponds to a BpfMap
28  * array type with key->int and value->uint64_t defined in the bpf program.
29  *
30  */
31 @RequiresApi(Build.VERSION_CODES.S)
32 public class BpfBitmap {
33     private BpfMap<Struct.S32, Struct.S64> mBpfMap;
34 
35     /**
36      * Create a BpfBitmap map wrapper with "path" of filesystem.
37      *
38      * @param path The path of the BPF map.
39      */
BpfBitmap(@onNull String path)40     public BpfBitmap(@NonNull String path) throws ErrnoException {
41         mBpfMap = new BpfMap<>(path, Struct.S32.class, Struct.S64.class);
42     }
43 
44     /**
45      * Retrieves the value from BpfMap for the given key.
46      *
47      * @param key The key in the map corresponding to the value to return.
48      */
getBpfMapValue(Struct.S32 key)49     private long getBpfMapValue(Struct.S32 key) throws ErrnoException  {
50         Struct.S64 curVal = mBpfMap.getValue(key);
51         if (curVal != null) {
52             return curVal.val;
53         } else {
54             return 0;
55         }
56     }
57 
58     /**
59      * Retrieves the bit for the given index in the bitmap.
60      *
61      * @param index Position in bitmap.
62      */
get(int index)63     public boolean get(int index) throws ErrnoException  {
64         if (index < 0) return false;
65 
66         Struct.S32 key = new Struct.S32(index >> 6);
67         return ((getBpfMapValue(key) >>> (index & 63)) & 1L) != 0;
68     }
69 
70     /**
71      * Set the specified index in the bitmap.
72      *
73      * @param index Position to set in bitmap.
74      */
set(int index)75     public void set(int index) throws ErrnoException {
76         set(index, true);
77     }
78 
79     /**
80      * Unset the specified index in the bitmap.
81      *
82      * @param index Position to unset in bitmap.
83      */
unset(int index)84     public void unset(int index) throws ErrnoException {
85         set(index, false);
86     }
87 
88     /**
89      * Change the specified index in the bitmap to set value.
90      *
91      * @param index Position to unset in bitmap.
92      * @param set Boolean indicating to set or unset index.
93      */
set(int index, boolean set)94     public void set(int index, boolean set) throws ErrnoException {
95         if (index < 0) throw new IllegalArgumentException("Index out of bounds.");
96 
97         Struct.S32 key = new Struct.S32(index >> 6);
98         long mask = (1L << (index & 63));
99         long val = getBpfMapValue(key);
100         if (set) val |= mask; else val &= ~mask;
101         mBpfMap.updateEntry(key, new Struct.S64(val));
102     }
103 
104     /**
105      * Clears the map. The map may already be empty.
106      *
107      * @throws ErrnoException if updating entry to 0 fails.
108      */
clear()109     public void clear() throws ErrnoException {
110         mBpfMap.forEach((key, value) -> {
111             mBpfMap.updateEntry(key, new Struct.S64(0));
112         });
113     }
114 
115     /**
116      * Checks if all bitmap values are 0.
117      */
isEmpty()118     public boolean isEmpty() throws ErrnoException {
119         Struct.S32 key = mBpfMap.getFirstKey();
120         while (key != null) {
121             if (getBpfMapValue(key) != 0) {
122                 return false;
123             }
124             key = mBpfMap.getNextKey(key);
125         }
126         return true;
127     }
128 }
129