1 /* 2 * Copyright (C) 2024 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.server; 18 19 import android.annotation.NonNull; 20 import android.net.ConnectivityManager; 21 import android.net.ConnectivityManager.NetworkCallback; 22 23 import com.android.net.module.util.GrowingIntArray; 24 25 /** 26 * A utility class to add/remove {@link NetworkCallback}s from a queue. 27 * 28 * <p>This is intended to be used as a temporary builder to create/modify callbacks stored in an int 29 * array for memory efficiency. 30 * 31 * <p>Intended usage: 32 * <pre> 33 * final CallbackQueue queue = new CallbackQueue(storedCallbacks); 34 * queue.forEach(netId, callbackId -> { [...] }); 35 * queue.addCallback(netId, callbackId); 36 * [...] 37 * storedCallbacks = queue.getMinimizedBackingArray(); 38 * </pre> 39 * 40 * <p>This class is not thread-safe. 41 */ 42 public class CallbackQueue extends GrowingIntArray { CallbackQueue(int[] initialCallbacks)43 public CallbackQueue(int[] initialCallbacks) { 44 super(initialCallbacks); 45 } 46 47 /** 48 * Get a callback int from netId and callbackId. 49 * 50 * <p>The first 16 bits of each int is the netId; the last 16 bits are the callback index. 51 */ getCallbackInt(int netId, int callbackId)52 private static int getCallbackInt(int netId, int callbackId) { 53 return (netId << 16) | (callbackId & 0xffff); 54 } 55 getNetId(int callbackInt)56 private static int getNetId(int callbackInt) { 57 return callbackInt >>> 16; 58 } 59 getCallbackId(int callbackInt)60 private static int getCallbackId(int callbackInt) { 61 return callbackInt & 0xffff; 62 } 63 64 /** 65 * A consumer interface for {@link #forEach(CallbackConsumer)}. 66 * 67 * <p>This is similar to a BiConsumer<Integer, Integer>, but avoids the boxing cost. 68 */ 69 public interface CallbackConsumer { 70 /** 71 * Method called on each callback in the queue. 72 */ accept(int netId, int callbackId)73 void accept(int netId, int callbackId); 74 } 75 76 /** 77 * Iterate over all callbacks in the queue. 78 */ forEach(@onNull CallbackConsumer consumer)79 public void forEach(@NonNull CallbackConsumer consumer) { 80 forEach(value -> { 81 final int netId = getNetId(value); 82 final int callbackId = getCallbackId(value); 83 consumer.accept(netId, callbackId); 84 }); 85 } 86 87 /** 88 * Indicates whether the queue contains a callback for the given (netId, callbackId). 89 */ hasCallback(int netId, int callbackId)90 public boolean hasCallback(int netId, int callbackId) { 91 return contains(getCallbackInt(netId, callbackId)); 92 } 93 94 /** 95 * Remove all callbacks for the given netId. 96 * 97 * @return true if at least one callback was removed. 98 */ removeCallbacksForNetId(int netId)99 public boolean removeCallbacksForNetId(int netId) { 100 return removeValues(cb -> getNetId(cb) == netId); 101 } 102 103 /** 104 * Remove all callbacks for the given netId and callbackId. 105 * @return true if at least one callback was removed. 106 */ removeCallbacks(int netId, int callbackId)107 public boolean removeCallbacks(int netId, int callbackId) { 108 final int cbInt = getCallbackInt(netId, callbackId); 109 return removeValues(cb -> cb == cbInt); 110 } 111 112 /** 113 * Add a callback at the end of the queue. 114 */ addCallback(int netId, int callbackId)115 public void addCallback(int netId, int callbackId) { 116 add(getCallbackInt(netId, callbackId)); 117 } 118 119 @Override valueToString(int item)120 protected String valueToString(int item) { 121 final int callbackId = getCallbackId(item); 122 final int netId = getNetId(item); 123 return ConnectivityManager.getCallbackName(callbackId) + "(" + netId + ")"; 124 } 125 } 126