1 /* 2 * Copyright (C) 2025 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.connectivity; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.system.Os; 22 import android.util.ArrayMap; 23 import android.util.Log; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.server.BpfNetMaps; 27 28 import java.util.Map; 29 30 /** 31 * InterfaceTracker is responsible for providing interface mapping and tracking. 32 * @hide 33 */ 34 public class InterfaceTracker { 35 static { 36 if (BpfNetMaps.isAtLeast25Q2()) { 37 System.loadLibrary("service-connectivity"); 38 } 39 } 40 private static final String TAG = "InterfaceTracker"; 41 private final Dependencies mDeps; 42 private final Map<String, Integer> mInterfaceMap; 43 InterfaceTracker(final Context context)44 public InterfaceTracker(final Context context) { 45 this(context, new Dependencies()); 46 } 47 48 @VisibleForTesting InterfaceTracker(final Context context, final Dependencies deps)49 public InterfaceTracker(final Context context, final Dependencies deps) { 50 this.mInterfaceMap = new ArrayMap<>(); 51 this.mDeps = deps; 52 } 53 54 /** 55 * To add interface to tracking 56 * @param interfaceName name of interface added. 57 */ addInterface(@ullable final String interfaceName)58 public void addInterface(@Nullable final String interfaceName) { 59 final int interfaceIndex; 60 if (interfaceName == null) { 61 interfaceIndex = 0; 62 } else { 63 interfaceIndex = mDeps.getIfIndex(interfaceName); 64 } 65 if (interfaceIndex == 0) { 66 Log.e(TAG, "Failed to get interface index for " + interfaceName); 67 return; 68 } 69 synchronized (mInterfaceMap) { 70 mInterfaceMap.put(interfaceName, interfaceIndex); 71 } 72 } 73 74 /** 75 * To remove interface from tracking 76 * @param interfaceName name of interface removed. 77 * @return true if the value was present and now removed. 78 */ removeInterface(@ullable final String interfaceName)79 public boolean removeInterface(@Nullable final String interfaceName) { 80 if (interfaceName == null) return false; 81 synchronized (mInterfaceMap) { 82 return mInterfaceMap.remove(interfaceName) != null; 83 } 84 } 85 86 /** 87 * Get interface index from interface name. 88 * @param interfaceName name of interface 89 * @return interface index for given interface name or 0 if interface is not found. 90 */ getInterfaceIndex(@ullable final String interfaceName)91 public int getInterfaceIndex(@Nullable final String interfaceName) { 92 final int interfaceIndex; 93 if (interfaceName != null) { 94 synchronized (mInterfaceMap) { 95 interfaceIndex = mInterfaceMap.getOrDefault(interfaceName, 0); 96 } 97 } else { 98 interfaceIndex = 0; 99 } 100 return interfaceIndex; 101 } 102 103 /** 104 * Dependencies of InterfaceTracker, for injection in tests. 105 */ 106 @VisibleForTesting 107 public static class Dependencies { 108 /** 109 * Get interface index. 110 */ getIfIndex(final String ifName)111 public int getIfIndex(final String ifName) { 112 return Os.if_nametoindex(ifName); 113 } 114 115 /** 116 * Get interface name 117 */ getIfName(final int ifIndex)118 public String getIfName(final int ifIndex) { 119 return Os.if_indextoname(ifIndex); 120 } 121 122 } 123 } 124