Merge "[Thread] tests a single ThreadNetworkController" into main
diff --git a/service-t/jni/com_android_server_net_NetworkStatsService.cpp b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
index 48ac993..c999398 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
@@ -52,8 +52,14 @@
return nullptr;
}
+ // Find the constructor.
+ jmethodID constructorID = env->GetMethodID(gEntryClass, "<init>", "()V");
+ if (constructorID == nullptr) {
+ return nullptr;
+ }
+
// Create a new instance of the Java class
- jobject result = env->AllocObject(gEntryClass);
+ jobject result = env->NewObject(gEntryClass, constructorID);
if (result == nullptr) {
return nullptr;
}
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
index def5f88..d3e331e 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
@@ -50,6 +50,15 @@
return ifaceStatsMap;
}
+Result<IfaceValue> ifindex2name(const uint32_t ifindex) {
+ Result<IfaceValue> v = getIfaceIndexNameMap().readValue(ifindex);
+ if (v.ok()) return v;
+ IfaceValue iv = {};
+ if (!if_indextoname(ifindex, iv.name)) return v;
+ getIfaceIndexNameMap().writeValue(ifindex, iv, BPF_ANY);
+ return iv;
+}
+
void bpfRegisterIface(const char* iface) {
if (!iface) return;
if (strlen(iface) >= sizeof(IfaceValue)) return;
@@ -78,14 +87,14 @@
int bpfGetIfaceStatsInternal(const char* iface, StatsValue* stats,
const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap,
- const BpfMapRO<uint32_t, IfaceValue>& ifaceNameMap) {
+ const IfIndexToNameFunc ifindex2name) {
*stats = {};
int64_t unknownIfaceBytesTotal = 0;
const auto processIfaceStats =
- [iface, stats, &ifaceNameMap, &unknownIfaceBytesTotal](
+ [iface, stats, ifindex2name, &unknownIfaceBytesTotal](
const uint32_t& key,
const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap) -> Result<void> {
- Result<IfaceValue> ifname = ifaceNameMap.readValue(key);
+ Result<IfaceValue> ifname = ifindex2name(key);
if (!ifname.ok()) {
maybeLogUnknownIface(key, ifaceStatsMap, key, &unknownIfaceBytesTotal);
return Result<void>();
@@ -104,7 +113,7 @@
}
int bpfGetIfaceStats(const char* iface, StatsValue* stats) {
- return bpfGetIfaceStatsInternal(iface, stats, getIfaceStatsMap(), getIfaceIndexNameMap());
+ return bpfGetIfaceStatsInternal(iface, stats, getIfaceStatsMap(), ifindex2name);
}
int bpfGetIfIndexStatsInternal(uint32_t ifindex, StatsValue* stats,
@@ -138,13 +147,13 @@
int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines,
const BpfMapRO<StatsKey, StatsValue>& statsMap,
- const BpfMapRO<uint32_t, IfaceValue>& ifaceMap) {
+ const IfIndexToNameFunc ifindex2name) {
int64_t unknownIfaceBytesTotal = 0;
const auto processDetailUidStats =
- [&lines, &unknownIfaceBytesTotal, &ifaceMap](
+ [&lines, &unknownIfaceBytesTotal, &ifindex2name](
const StatsKey& key,
const BpfMapRO<StatsKey, StatsValue>& statsMap) -> Result<void> {
- Result<IfaceValue> ifname = ifaceMap.readValue(key.ifaceIndex);
+ Result<IfaceValue> ifname = ifindex2name(key.ifaceIndex);
if (!ifname.ok()) {
maybeLogUnknownIface(key.ifaceIndex, statsMap, key, &unknownIfaceBytesTotal);
return Result<void>();
@@ -212,7 +221,7 @@
// TODO: the above comment feels like it may be obsolete / out of date,
// since we no longer swap the map via netd binder rpc - though we do
// still swap it.
- int ret = parseBpfNetworkStatsDetailInternal(*lines, *inactiveStatsMap, getIfaceIndexNameMap());
+ int ret = parseBpfNetworkStatsDetailInternal(*lines, *inactiveStatsMap, ifindex2name);
if (ret) {
ALOGE("parse detail network stats failed: %s", strerror(errno));
return ret;
@@ -229,12 +238,12 @@
int parseBpfNetworkStatsDevInternal(std::vector<stats_line>& lines,
const BpfMapRO<uint32_t, StatsValue>& statsMap,
- const BpfMapRO<uint32_t, IfaceValue>& ifaceMap) {
+ const IfIndexToNameFunc ifindex2name) {
int64_t unknownIfaceBytesTotal = 0;
- const auto processDetailIfaceStats = [&lines, &unknownIfaceBytesTotal, &ifaceMap, &statsMap](
+ const auto processDetailIfaceStats = [&lines, &unknownIfaceBytesTotal, ifindex2name, &statsMap](
const uint32_t& key, const StatsValue& value,
const BpfMapRO<uint32_t, StatsValue>&) {
- Result<IfaceValue> ifname = ifaceMap.readValue(key);
+ Result<IfaceValue> ifname = ifindex2name(key);
if (!ifname.ok()) {
maybeLogUnknownIface(key, statsMap, key, &unknownIfaceBytesTotal);
return Result<void>();
@@ -259,7 +268,7 @@
}
int parseBpfNetworkStatsDev(std::vector<stats_line>* lines) {
- return parseBpfNetworkStatsDevInternal(*lines, getIfaceStatsMap(), getIfaceIndexNameMap());
+ return parseBpfNetworkStatsDevInternal(*lines, getIfaceStatsMap(), ifindex2name);
}
void groupNetworkStats(std::vector<stats_line>& lines) {
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
index 57822fc..484c166 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
@@ -77,6 +77,10 @@
BpfMap<uint32_t, IfaceValue> mFakeIfaceIndexNameMap;
BpfMap<uint32_t, StatsValue> mFakeIfaceStatsMap;
+ IfIndexToNameFunc mIfIndex2Name = [this](const uint32_t ifindex){
+ return mFakeIfaceIndexNameMap.readValue(ifindex);
+ };
+
void SetUp() {
ASSERT_EQ(0, setrlimitForTest());
@@ -228,7 +232,7 @@
populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET1, value1, mFakeStatsMap);
populateFakeStats(TEST_UID2, 0, IFACE_INDEX3, TEST_COUNTERSET1, value1, mFakeStatsMap);
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((unsigned long)3, lines.size());
}
@@ -256,16 +260,15 @@
EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
StatsValue result1 = {};
- ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME1, &result1, mFakeIfaceStatsMap,
- mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0,
+ bpfGetIfaceStatsInternal(IFACE_NAME1, &result1, mFakeIfaceStatsMap, mIfIndex2Name));
expectStatsEqual(value1, result1);
StatsValue result2 = {};
- ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME2, &result2, mFakeIfaceStatsMap,
- mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0,
+ bpfGetIfaceStatsInternal(IFACE_NAME2, &result2, mFakeIfaceStatsMap, mIfIndex2Name));
expectStatsEqual(value2, result2);
StatsValue totalResult = {};
- ASSERT_EQ(0, bpfGetIfaceStatsInternal(NULL, &totalResult, mFakeIfaceStatsMap,
- mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, bpfGetIfaceStatsInternal(NULL, &totalResult, mFakeIfaceStatsMap, mIfIndex2Name));
StatsValue totalValue = {
.rxPackets = TEST_PACKET0 * 2 + TEST_PACKET1,
.rxBytes = TEST_BYTES0 * 2 + TEST_BYTES1,
@@ -304,7 +307,7 @@
mFakeStatsMap);
populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
std::vector<stats_line> lines;
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((unsigned long)7, lines.size());
}
@@ -324,7 +327,7 @@
populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, value1, mFakeStatsMap);
populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
std::vector<stats_line> lines;
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((unsigned long)4, lines.size());
}
@@ -365,7 +368,7 @@
ASSERT_EQ(-1, unknownIfaceBytesTotal);
std::vector<stats_line> lines;
// TODO: find a way to test the total of unknown Iface Bytes go above limit.
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((unsigned long)1, lines.size());
expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines.front());
}
@@ -396,8 +399,7 @@
ifaceStatsKey = IFACE_INDEX4;
EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
std::vector<stats_line> lines;
- ASSERT_EQ(0,
- parseBpfNetworkStatsDevInternal(lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDevInternal(lines, mFakeIfaceStatsMap, mIfIndex2Name));
ASSERT_EQ((unsigned long)4, lines.size());
expectStatsLineEqual(value1, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
@@ -441,13 +443,13 @@
std::vector<stats_line> lines;
// Test empty stats.
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((size_t) 0, lines.size());
lines.clear();
// Test 1 line stats.
populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((size_t) 2, lines.size()); // TEST_TAG != 0 -> 1 entry becomes 2 lines
expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[0]);
expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[1]);
@@ -459,7 +461,7 @@
populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value2,
mFakeStatsMap);
populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((size_t) 9, lines.size());
lines.clear();
@@ -467,7 +469,7 @@
populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((size_t) 9, lines.size());
// Verify Sorted & Grouped.
@@ -492,8 +494,7 @@
ifaceStatsKey = IFACE_INDEX3;
EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
- ASSERT_EQ(0,
- parseBpfNetworkStatsDevInternal(lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDevInternal(lines, mFakeIfaceStatsMap, mIfIndex2Name));
ASSERT_EQ((size_t) 2, lines.size());
expectStatsLineEqual(value3, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
@@ -534,7 +535,7 @@
// TODO: Mutate counterSet and enlarge TEST_MAP_SIZE if overflow on counterSet is possible.
std::vector<stats_line> lines;
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mIfIndex2Name));
ASSERT_EQ((size_t) 12, lines.size());
// Uid 0 first
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
index 173dee4..59eb195 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
@@ -55,20 +55,25 @@
bool operator==(const stats_line& lhs, const stats_line& rhs);
bool operator<(const stats_line& lhs, const stats_line& rhs);
+// This mirrors BpfMap.h's:
+// Result<Value> readValue(const Key key) const
+// for a BpfMap<uint32_t, IfaceValue>
+using IfIndexToNameFunc = std::function<Result<IfaceValue>(const uint32_t)>;
+
// For test only
int bpfGetUidStatsInternal(uid_t uid, StatsValue* stats,
const BpfMapRO<uint32_t, StatsValue>& appUidStatsMap);
// For test only
int bpfGetIfaceStatsInternal(const char* iface, StatsValue* stats,
const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap,
- const BpfMapRO<uint32_t, IfaceValue>& ifaceNameMap);
+ const IfIndexToNameFunc ifindex2name);
// For test only
int bpfGetIfIndexStatsInternal(uint32_t ifindex, StatsValue* stats,
const BpfMapRO<uint32_t, StatsValue>& ifaceStatsMap);
// For test only
int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines,
const BpfMapRO<StatsKey, StatsValue>& statsMap,
- const BpfMapRO<uint32_t, IfaceValue>& ifaceMap);
+ const IfIndexToNameFunc ifindex2name);
// For test only
int cleanStatsMapInternal(const base::unique_fd& cookieTagMap, const base::unique_fd& tagStatsMap);
@@ -98,7 +103,7 @@
// For test only
int parseBpfNetworkStatsDevInternal(std::vector<stats_line>& lines,
const BpfMapRO<uint32_t, StatsValue>& statsMap,
- const BpfMapRO<uint32_t, IfaceValue>& ifaceMap);
+ const IfIndexToNameFunc ifindex2name);
void bpfRegisterIface(const char* iface);
int bpfGetUidStats(uid_t uid, StatsValue* stats);
diff --git a/service-t/src/com/android/server/net/BpfInterfaceMapHelper.java b/service-t/src/com/android/server/net/BpfInterfaceMapHelper.java
new file mode 100644
index 0000000..3c95b8e
--- /dev/null
+++ b/service-t/src/com/android/server/net/BpfInterfaceMapHelper.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.net;
+
+import android.os.Build;
+import android.system.ErrnoException;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.BpfDump;
+import com.android.net.module.util.BpfMap;
+import com.android.net.module.util.IBpfMap;
+import com.android.net.module.util.Struct.S32;
+
+/**
+ * Monitor interface added (without removed) and right interface name and its index to bpf map.
+ */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+public class BpfInterfaceMapHelper {
+ private static final String TAG = BpfInterfaceMapHelper.class.getSimpleName();
+ // This is current path but may be changed soon.
+ private static final String IFACE_INDEX_NAME_MAP_PATH =
+ "/sys/fs/bpf/netd_shared/map_netd_iface_index_name_map";
+ private final IBpfMap<S32, InterfaceMapValue> mIndexToIfaceBpfMap;
+
+ public BpfInterfaceMapHelper() {
+ this(new Dependencies());
+ }
+
+ @VisibleForTesting
+ public BpfInterfaceMapHelper(Dependencies deps) {
+ mIndexToIfaceBpfMap = deps.getInterfaceMap();
+ }
+
+ /**
+ * Dependencies of BpfInerfaceMapUpdater, for injection in tests.
+ */
+ @VisibleForTesting
+ public static class Dependencies {
+ /** Create BpfMap for updating interface and index mapping. */
+ public IBpfMap<S32, InterfaceMapValue> getInterfaceMap() {
+ try {
+ return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH,
+ S32.class, InterfaceMapValue.class);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Cannot create interface map: " + e);
+ return null;
+ }
+ }
+ }
+
+ /** get interface name by interface index from bpf map */
+ public String getIfNameByIndex(final int index) {
+ try {
+ final InterfaceMapValue value = mIndexToIfaceBpfMap.getValue(new S32(index));
+ if (value == null) {
+ Log.e(TAG, "No if name entry for index " + index);
+ return null;
+ }
+ return value.getInterfaceNameString();
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to get entry for index " + index + ": " + e);
+ return null;
+ }
+ }
+
+ /**
+ * Dump BPF map
+ *
+ * @param pw print writer
+ */
+ public void dump(final IndentingPrintWriter pw) {
+ pw.println("BPF map status:");
+ pw.increaseIndent();
+ BpfDump.dumpMapStatus(mIndexToIfaceBpfMap, pw, "IfaceIndexNameMap",
+ IFACE_INDEX_NAME_MAP_PATH);
+ pw.decreaseIndent();
+ pw.println("BPF map content:");
+ pw.increaseIndent();
+ BpfDump.dumpMap(mIndexToIfaceBpfMap, pw, "IfaceIndexNameMap",
+ (key, value) -> "ifaceIndex=" + key.val
+ + " ifaceName=" + value.getInterfaceNameString());
+ pw.decreaseIndent();
+ }
+}
diff --git a/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java b/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java
deleted file mode 100644
index 59de2c4..0000000
--- a/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.net;
-
-import android.os.Build;
-import android.content.Context;
-import android.net.INetd;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.system.ErrnoException;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-
-import androidx.annotation.RequiresApi;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
-import com.android.net.module.util.BpfDump;
-import com.android.net.module.util.BpfMap;
-import com.android.net.module.util.IBpfMap;
-import com.android.net.module.util.InterfaceParams;
-import com.android.net.module.util.Struct.S32;
-
-/**
- * Monitor interface added (without removed) and right interface name and its index to bpf map.
- */
-@RequiresApi(Build.VERSION_CODES.TIRAMISU)
-public class BpfInterfaceMapUpdater {
- private static final String TAG = BpfInterfaceMapUpdater.class.getSimpleName();
- // This is current path but may be changed soon.
- private static final String IFACE_INDEX_NAME_MAP_PATH =
- "/sys/fs/bpf/netd_shared/map_netd_iface_index_name_map";
- private final IBpfMap<S32, InterfaceMapValue> mIndexToIfaceBpfMap;
- private final INetd mNetd;
- private final Handler mHandler;
- private final Dependencies mDeps;
-
- public BpfInterfaceMapUpdater(Context ctx, Handler handler) {
- this(ctx, handler, new Dependencies());
- }
-
- @VisibleForTesting
- public BpfInterfaceMapUpdater(Context ctx, Handler handler, Dependencies deps) {
- mDeps = deps;
- mIndexToIfaceBpfMap = deps.getInterfaceMap();
- mNetd = deps.getINetd(ctx);
- mHandler = handler;
- }
-
- /**
- * Dependencies of BpfInerfaceMapUpdater, for injection in tests.
- */
- @VisibleForTesting
- public static class Dependencies {
- /** Create BpfMap for updating interface and index mapping. */
- public IBpfMap<S32, InterfaceMapValue> getInterfaceMap() {
- try {
- return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH,
- S32.class, InterfaceMapValue.class);
- } catch (ErrnoException e) {
- Log.e(TAG, "Cannot create interface map: " + e);
- return null;
- }
- }
-
- /** Get InterfaceParams for giving interface name. */
- public InterfaceParams getInterfaceParams(String ifaceName) {
- return InterfaceParams.getByName(ifaceName);
- }
-
- /** Get INetd binder object. */
- public INetd getINetd(Context ctx) {
- return INetd.Stub.asInterface((IBinder) ctx.getSystemService(Context.NETD_SERVICE));
- }
- }
-
- /**
- * Start listening interface update event.
- * Query current interface names before listening.
- */
- public void start() {
- mHandler.post(() -> {
- if (mIndexToIfaceBpfMap == null) {
- Log.wtf(TAG, "Fail to start: Null bpf map");
- return;
- }
-
- try {
- // TODO: use a NetlinkMonitor and listen for RTM_NEWLINK messages instead.
- mNetd.registerUnsolicitedEventListener(new InterfaceChangeObserver());
- } catch (RemoteException e) {
- Log.wtf(TAG, "Unable to register netd UnsolicitedEventListener, " + e);
- }
-
- final String[] ifaces;
- try {
- // TODO: use a netlink dump to get the current interface list.
- ifaces = mNetd.interfaceGetList();
- } catch (RemoteException | ServiceSpecificException e) {
- Log.wtf(TAG, "Unable to query interface names by netd, " + e);
- return;
- }
-
- for (String ifaceName : ifaces) {
- addInterface(ifaceName);
- }
- });
- }
-
- private void addInterface(String ifaceName) {
- final InterfaceParams iface = mDeps.getInterfaceParams(ifaceName);
- if (iface == null) {
- Log.e(TAG, "Unable to get InterfaceParams for " + ifaceName);
- return;
- }
-
- try {
- mIndexToIfaceBpfMap.updateEntry(new S32(iface.index), new InterfaceMapValue(ifaceName));
- } catch (ErrnoException e) {
- Log.e(TAG, "Unable to update entry for " + ifaceName + ", " + e);
- }
- }
-
- private class InterfaceChangeObserver extends BaseNetdUnsolicitedEventListener {
- @Override
- public void onInterfaceAdded(String ifName) {
- mHandler.post(() -> addInterface(ifName));
- }
- }
-
- /** get interface name by interface index from bpf map */
- public String getIfNameByIndex(final int index) {
- try {
- final InterfaceMapValue value = mIndexToIfaceBpfMap.getValue(new S32(index));
- if (value == null) {
- Log.e(TAG, "No if name entry for index " + index);
- return null;
- }
- return value.getInterfaceNameString();
- } catch (ErrnoException e) {
- Log.e(TAG, "Failed to get entry for index " + index + ": " + e);
- return null;
- }
- }
-
- /**
- * Dump BPF map
- *
- * @param pw print writer
- */
- public void dump(final IndentingPrintWriter pw) {
- pw.println("BPF map status:");
- pw.increaseIndent();
- BpfDump.dumpMapStatus(mIndexToIfaceBpfMap, pw, "IfaceIndexNameMap",
- IFACE_INDEX_NAME_MAP_PATH);
- pw.decreaseIndent();
- pw.println("BPF map content:");
- pw.increaseIndent();
- BpfDump.dumpMap(mIndexToIfaceBpfMap, pw, "IfaceIndexNameMap",
- (key, value) -> "ifaceIndex=" + key.val
- + " ifaceName=" + value.getInterfaceNameString());
- pw.decreaseIndent();
- }
-}
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 7b24315..ec10158 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -476,7 +476,7 @@
private final LocationPermissionChecker mLocationPermissionChecker;
@NonNull
- private final BpfInterfaceMapUpdater mInterfaceMapUpdater;
+ private final BpfInterfaceMapHelper mInterfaceMapHelper;
@Nullable
private final SkDestroyListener mSkDestroyListener;
@@ -628,8 +628,7 @@
mContentObserver = mDeps.makeContentObserver(mHandler, mSettings,
mNetworkStatsSubscriptionsMonitor);
mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext);
- mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler);
- mInterfaceMapUpdater.start();
+ mInterfaceMapHelper = mDeps.makeBpfInterfaceMapHelper();
mUidCounterSetMap = mDeps.getUidCounterSetMap();
mCookieTagMap = mDeps.getCookieTagMap();
mStatsMapA = mDeps.getStatsMapA();
@@ -798,11 +797,10 @@
return new LocationPermissionChecker(context);
}
- /** Create BpfInterfaceMapUpdater to update bpf interface map. */
+ /** Create BpfInterfaceMapHelper to update bpf interface map. */
@NonNull
- public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater(
- @NonNull Context ctx, @NonNull Handler handler) {
- return new BpfInterfaceMapUpdater(ctx, handler);
+ public BpfInterfaceMapHelper makeBpfInterfaceMapHelper() {
+ return new BpfInterfaceMapHelper();
}
/** Get counter sets map for each UID. */
@@ -2889,9 +2887,9 @@
}
pw.println();
- pw.println("InterfaceMapUpdater:");
+ pw.println("InterfaceMapHelper:");
pw.increaseIndent();
- mInterfaceMapUpdater.dump(pw);
+ mInterfaceMapHelper.dump(pw);
pw.decreaseIndent();
pw.println();
@@ -3038,7 +3036,7 @@
BpfDump.dumpMap(statsMap, pw, mapName,
"ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets",
(key, value) -> {
- final String ifName = mInterfaceMapUpdater.getIfNameByIndex(key.ifaceIndex);
+ final String ifName = mInterfaceMapHelper.getIfNameByIndex(key.ifaceIndex);
return key.ifaceIndex + " "
+ (ifName != null ? ifName : "unknown") + " "
+ "0x" + Long.toHexString(key.tag) + " "
@@ -3056,7 +3054,7 @@
BpfDump.dumpMap(mIfaceStatsMap, pw, "mIfaceStatsMap",
"ifaceIndex ifaceName rxBytes rxPackets txBytes txPackets",
(key, value) -> {
- final String ifName = mInterfaceMapUpdater.getIfNameByIndex(key.val);
+ final String ifName = mInterfaceMapHelper.getIfNameByIndex(key.val);
return key.val + " "
+ (ifName != null ? ifName : "unknown") + " "
+ value.rxBytes + " "
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
index 7c2be2c..f735e46 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
@@ -29,6 +29,7 @@
import static android.system.OsConstants.SO_RCVBUF;
import static android.system.OsConstants.SO_RCVTIMEO;
import static android.system.OsConstants.SO_SNDTIMEO;
+
import static com.android.net.module.util.netlink.NetlinkConstants.hexify;
import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE;
import static com.android.net.module.util.netlink.NetlinkConstants.RTNL_FAMILY_IP6MR;
@@ -49,6 +50,7 @@
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.Inet6Address;
+import java.net.InetAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -56,7 +58,6 @@
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
/**
* Utilities for netlink related class that may not be able to fit into a specific class.
@@ -177,19 +178,19 @@
}
/**
- * Send an RTM_NEWADDR message to kernel to add or update an IPv6 address.
+ * Send an RTM_NEWADDR message to kernel to add or update an IP address.
*
* @param ifIndex interface index.
- * @param ip IPv6 address to be added.
- * @param prefixlen IPv6 address prefix length.
- * @param flags IPv6 address flags.
- * @param scope IPv6 address scope.
- * @param preferred The preferred lifetime of IPv6 address.
- * @param valid The valid lifetime of IPv6 address.
+ * @param ip IP address to be added.
+ * @param prefixlen IP address prefix length.
+ * @param flags IP address flags.
+ * @param scope IP address scope.
+ * @param preferred The preferred lifetime of IP address.
+ * @param valid The valid lifetime of IP address.
*/
- public static boolean sendRtmNewAddressRequest(int ifIndex, @NonNull final Inet6Address ip,
+ public static boolean sendRtmNewAddressRequest(int ifIndex, @NonNull final InetAddress ip,
short prefixlen, int flags, byte scope, long preferred, long valid) {
- Objects.requireNonNull(ip, "IPv6 address to be added should not be null.");
+ Objects.requireNonNull(ip, "IP address to be added should not be null.");
final byte[] msg = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqNo*/, ip,
prefixlen, flags, scope, ifIndex, preferred, valid);
try {
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
index cbe0ab0..4846df7 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java
@@ -16,6 +16,7 @@
package com.android.net.module.util.netlink;
+import static com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress;
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE;
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
@@ -28,6 +29,7 @@
import com.android.net.module.util.HexDump;
+import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
@@ -48,6 +50,8 @@
*/
public class RtNetlinkAddressMessage extends NetlinkMessage {
public static final short IFA_ADDRESS = 1;
+ public static final short IFA_LOCAL = 2;
+ public static final short IFA_BROADCAST = 4;
public static final short IFA_CACHEINFO = 6;
public static final short IFA_FLAGS = 8;
@@ -71,6 +75,7 @@
mIfacacheInfo = structIfacacheInfo;
mFlags = flags;
}
+
private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) {
this(header, null, null, null, 0);
}
@@ -158,6 +163,24 @@
// still be packed to ByteBuffer even if the flag is 0.
final StructNlAttr flags = new StructNlAttr(IFA_FLAGS, mFlags);
flags.pack(byteBuffer);
+
+ // Add the required IFA_LOCAL and IFA_BROADCAST attributes for IPv4 addresses. The IFA_LOCAL
+ // attribute represents the local address, which is equivalent to IFA_ADDRESS on a normally
+ // configured broadcast interface, however, for PPP interfaces, IFA_ADDRESS indicates the
+ // destination address and the local address is provided in the IFA_LOCAL attribute. If the
+ // IFA_LOCAL attribute is not present in the RTM_NEWADDR message, the kernel replies with an
+ // error netlink message with invalid parameters. IFA_BROADCAST is also required, otherwise
+ // the broadcast on the interface is 0.0.0.0. See include/uapi/linux/if_addr.h for details.
+ // For IPv6 addresses, the IFA_ADDRESS attribute applies and introduces no ambiguity.
+ if (mIpAddress instanceof Inet4Address) {
+ final StructNlAttr localAddress = new StructNlAttr(IFA_LOCAL, mIpAddress);
+ localAddress.pack(byteBuffer);
+
+ final Inet4Address broadcast =
+ getBroadcastAddress((Inet4Address) mIpAddress, mIfaddrmsg.prefixLen);
+ final StructNlAttr broadcastAddress = new StructNlAttr(IFA_BROADCAST, broadcast);
+ broadcastAddress.pack(byteBuffer);
+ }
}
/**
@@ -184,7 +207,7 @@
0 /* tstamp */);
msg.mFlags = flags;
- final byte[] bytes = new byte[msg.getRequiredSpace()];
+ final byte[] bytes = new byte[msg.getRequiredSpace(family)];
nlmsghdr.nlmsg_len = bytes.length;
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
byteBuffer.order(ByteOrder.nativeOrder());
@@ -237,7 +260,7 @@
// RtNetlinkAddressMessage, e.g. RTM_DELADDR sent from user space to kernel to delete an
// IP address only requires IFA_ADDRESS attribute. The caller should check if these attributes
// are necessary to carry when constructing a RtNetlinkAddressMessage.
- private int getRequiredSpace() {
+ private int getRequiredSpace(int family) {
int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE;
// IFA_ADDRESS attr
spaceRequired += NetlinkConstants.alignedLengthOf(
@@ -247,6 +270,14 @@
StructNlAttr.NLA_HEADERLEN + StructIfacacheInfo.STRUCT_SIZE);
// IFA_FLAGS "u32" attr
spaceRequired += StructNlAttr.NLA_HEADERLEN + 4;
+ if (family == OsConstants.AF_INET) {
+ // IFA_LOCAL attr
+ spaceRequired += NetlinkConstants.alignedLengthOf(
+ StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length);
+ // IFA_BROADCAST attr
+ spaceRequired += NetlinkConstants.alignedLengthOf(
+ StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length);
+ }
return spaceRequired;
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
index 01126d2..1d08525 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkAddressMessageTest.java
@@ -42,6 +42,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.Inet4Address;
import java.net.Inet6Address;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -179,6 +180,57 @@
}
@Test
+ public void testCreateRtmNewAddressMessage_IPv4Address() {
+ // Hexadecimal representation of our created packet.
+ final String expectedNewAddressHex =
+ // struct nlmsghdr
+ "4c000000" // length = 76
+ + "1400" // type = 20 (RTM_NEWADDR)
+ + "0501" // flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_REPLACE
+ + "01000000" // seqno = 1
+ + "00000000" // pid = 0 (send to kernel)
+ // struct IfaddrMsg
+ + "02" // family = inet
+ + "18" // prefix len = 24
+ + "00" // flags = 0
+ + "00" // scope = RT_SCOPE_UNIVERSE
+ + "14000000" // ifindex = 20
+ // struct nlattr: IFA_ADDRESS
+ + "0800" // len
+ + "0100" // type
+ + "C0A80491" // IPv4 address = 192.168.4.145
+ // struct nlattr: IFA_CACHEINFO
+ + "1400" // len
+ + "0600" // type
+ + "C0A80000" // preferred = 43200s
+ + "C0A80000" // valid = 43200s
+ + "00000000" // cstamp
+ + "00000000" // tstamp
+ // struct nlattr: IFA_FLAGS
+ + "0800" // len
+ + "0800" // type
+ + "00000000" // flags = 0
+ // struct nlattr: IFA_LOCAL
+ + "0800" // len
+ + "0200" // type
+ + "C0A80491" // local address = 192.168.4.145
+ // struct nlattr: IFA_BROADCAST
+ + "0800" // len
+ + "0400" // type
+ + "C0A804FF"; // broadcast address = 192.168.4.255
+ final byte[] expectedNewAddress =
+ HexEncoding.decode(expectedNewAddressHex.toCharArray(), false);
+
+ final Inet4Address ipAddress =
+ (Inet4Address) InetAddresses.parseNumericAddress("192.168.4.145");
+ final byte[] bytes = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqno */,
+ ipAddress, (short) 24 /* prefix len */, 0 /* flags */,
+ (byte) RT_SCOPE_UNIVERSE /* scope */, 20 /* ifindex */,
+ (long) 0xA8C0 /* preferred */, (long) 0xA8C0 /* valid */);
+ assertArrayEquals(expectedNewAddress, bytes);
+ }
+
+ @Test
public void testCreateRtmDelAddressMessage() {
// Hexadecimal representation of our created packet.
final String expectedDelAddressHex =
diff --git a/tests/unit/java/com/android/server/net/BpfInterfaceMapHelperTest.java b/tests/unit/java/com/android/server/net/BpfInterfaceMapHelperTest.java
new file mode 100644
index 0000000..7b3bea3
--- /dev/null
+++ b/tests/unit/java/com/android/server/net/BpfInterfaceMapHelperTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.system.OsConstants.EPERM;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.spy;
+
+import android.os.Build;
+import android.system.ErrnoException;
+import android.util.IndentingPrintWriter;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
+import com.android.net.module.util.IBpfMap;
+import com.android.net.module.util.Struct.S32;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+import com.android.testutils.TestBpfMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner.class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
+public final class BpfInterfaceMapHelperTest {
+ private static final int TEST_INDEX = 1;
+ private static final int TEST_INDEX2 = 2;
+ private static final String TEST_INTERFACE_NAME = "test1";
+ private static final String TEST_INTERFACE_NAME2 = "test2";
+
+ private BaseNetdUnsolicitedEventListener mListener;
+ private BpfInterfaceMapHelper mUpdater;
+ private IBpfMap<S32, InterfaceMapValue> mBpfMap =
+ spy(new TestBpfMap<>(S32.class, InterfaceMapValue.class));
+
+ private class TestDependencies extends BpfInterfaceMapHelper.Dependencies {
+ @Override
+ public IBpfMap<S32, InterfaceMapValue> getInterfaceMap() {
+ return mBpfMap;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mUpdater = new BpfInterfaceMapHelper(new TestDependencies());
+ }
+
+ @Test
+ public void testGetIfNameByIndex() throws Exception {
+ mBpfMap.updateEntry(new S32(TEST_INDEX), new InterfaceMapValue(TEST_INTERFACE_NAME));
+ assertEquals(TEST_INTERFACE_NAME, mUpdater.getIfNameByIndex(TEST_INDEX));
+ }
+
+ @Test
+ public void testGetIfNameByIndexNoEntry() {
+ assertNull(mUpdater.getIfNameByIndex(TEST_INDEX));
+ }
+
+ @Test
+ public void testGetIfNameByIndexException() throws Exception {
+ doThrow(new ErrnoException("", EPERM)).when(mBpfMap).getValue(new S32(TEST_INDEX));
+ assertNull(mUpdater.getIfNameByIndex(TEST_INDEX));
+ }
+
+ private void assertDumpContains(final String dump, final String message) {
+ assertTrue(String.format("dump(%s) does not contain '%s'", dump, message),
+ dump.contains(message));
+ }
+
+ private String getDump() {
+ final StringWriter sw = new StringWriter();
+ mUpdater.dump(new IndentingPrintWriter(new PrintWriter(sw), " "));
+ return sw.toString();
+ }
+
+ @Test
+ public void testDump() throws ErrnoException {
+ mBpfMap.updateEntry(new S32(TEST_INDEX), new InterfaceMapValue(TEST_INTERFACE_NAME));
+ mBpfMap.updateEntry(new S32(TEST_INDEX2), new InterfaceMapValue(TEST_INTERFACE_NAME2));
+
+ final String dump = getDump();
+ assertDumpContains(dump, "IfaceIndexNameMap: OK");
+ assertDumpContains(dump, "ifaceIndex=1 ifaceName=test1");
+ assertDumpContains(dump, "ifaceIndex=2 ifaceName=test2");
+ }
+}
diff --git a/tests/unit/java/com/android/server/net/BpfInterfaceMapUpdaterTest.java b/tests/unit/java/com/android/server/net/BpfInterfaceMapUpdaterTest.java
deleted file mode 100644
index c730856..0000000
--- a/tests/unit/java/com/android/server/net/BpfInterfaceMapUpdaterTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.system.OsConstants.EPERM;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.INetd;
-import android.net.MacAddress;
-import android.os.Build;
-import android.os.Handler;
-import android.os.test.TestLooper;
-import android.system.ErrnoException;
-import android.util.IndentingPrintWriter;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
-import com.android.net.module.util.IBpfMap;
-import com.android.net.module.util.InterfaceParams;
-import com.android.net.module.util.Struct.S32;
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRunner;
-import com.android.testutils.TestBpfMap;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner.class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
-public final class BpfInterfaceMapUpdaterTest {
- private static final int TEST_INDEX = 1;
- private static final int TEST_INDEX2 = 2;
- private static final String TEST_INTERFACE_NAME = "test1";
- private static final String TEST_INTERFACE_NAME2 = "test2";
-
- private final TestLooper mLooper = new TestLooper();
- private BaseNetdUnsolicitedEventListener mListener;
- private BpfInterfaceMapUpdater mUpdater;
- private IBpfMap<S32, InterfaceMapValue> mBpfMap =
- spy(new TestBpfMap<>(S32.class, InterfaceMapValue.class));
- @Mock private INetd mNetd;
- @Mock private Context mContext;
-
- private class TestDependencies extends BpfInterfaceMapUpdater.Dependencies {
- @Override
- public IBpfMap<S32, InterfaceMapValue> getInterfaceMap() {
- return mBpfMap;
- }
-
- @Override
- public InterfaceParams getInterfaceParams(String ifaceName) {
- if (ifaceName.equals(TEST_INTERFACE_NAME)) {
- return new InterfaceParams(TEST_INTERFACE_NAME, TEST_INDEX,
- MacAddress.ALL_ZEROS_ADDRESS);
- } else if (ifaceName.equals(TEST_INTERFACE_NAME2)) {
- return new InterfaceParams(TEST_INTERFACE_NAME2, TEST_INDEX2,
- MacAddress.ALL_ZEROS_ADDRESS);
- }
-
- return null;
- }
-
- @Override
- public INetd getINetd(Context ctx) {
- return mNetd;
- }
- }
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- when(mNetd.interfaceGetList()).thenReturn(new String[] {TEST_INTERFACE_NAME});
- mUpdater = new BpfInterfaceMapUpdater(mContext, new Handler(mLooper.getLooper()),
- new TestDependencies());
- }
-
- private void verifyStartUpdater() throws Exception {
- mUpdater.start();
- mLooper.dispatchAll();
- final ArgumentCaptor<BaseNetdUnsolicitedEventListener> listenerCaptor =
- ArgumentCaptor.forClass(BaseNetdUnsolicitedEventListener.class);
- verify(mNetd).registerUnsolicitedEventListener(listenerCaptor.capture());
- mListener = listenerCaptor.getValue();
- verify(mBpfMap).updateEntry(eq(new S32(TEST_INDEX)),
- eq(new InterfaceMapValue(TEST_INTERFACE_NAME)));
- }
-
- @Test
- public void testUpdateInterfaceMap() throws Exception {
- verifyStartUpdater();
-
- mListener.onInterfaceAdded(TEST_INTERFACE_NAME2);
- mLooper.dispatchAll();
- verify(mBpfMap).updateEntry(eq(new S32(TEST_INDEX2)),
- eq(new InterfaceMapValue(TEST_INTERFACE_NAME2)));
-
- // Check that when onInterfaceRemoved is called, nothing happens.
- mListener.onInterfaceRemoved(TEST_INTERFACE_NAME);
- mLooper.dispatchAll();
- verifyNoMoreInteractions(mBpfMap);
- }
-
- @Test
- public void testGetIfNameByIndex() throws Exception {
- mBpfMap.updateEntry(new S32(TEST_INDEX), new InterfaceMapValue(TEST_INTERFACE_NAME));
- assertEquals(TEST_INTERFACE_NAME, mUpdater.getIfNameByIndex(TEST_INDEX));
- }
-
- @Test
- public void testGetIfNameByIndexNoEntry() {
- assertNull(mUpdater.getIfNameByIndex(TEST_INDEX));
- }
-
- @Test
- public void testGetIfNameByIndexException() throws Exception {
- doThrow(new ErrnoException("", EPERM)).when(mBpfMap).getValue(new S32(TEST_INDEX));
- assertNull(mUpdater.getIfNameByIndex(TEST_INDEX));
- }
-
- private void assertDumpContains(final String dump, final String message) {
- assertTrue(String.format("dump(%s) does not contain '%s'", dump, message),
- dump.contains(message));
- }
-
- private String getDump() {
- final StringWriter sw = new StringWriter();
- mUpdater.dump(new IndentingPrintWriter(new PrintWriter(sw), " "));
- return sw.toString();
- }
-
- @Test
- public void testDump() throws ErrnoException {
- mBpfMap.updateEntry(new S32(TEST_INDEX), new InterfaceMapValue(TEST_INTERFACE_NAME));
- mBpfMap.updateEntry(new S32(TEST_INDEX2), new InterfaceMapValue(TEST_INTERFACE_NAME2));
-
- final String dump = getDump();
- assertDumpContains(dump, "IfaceIndexNameMap: OK");
- assertDumpContains(dump, "ifaceIndex=1 ifaceName=test1");
- assertDumpContains(dump, "ifaceIndex=2 ifaceName=test2");
- }
-}
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index a5fee5b..3ed51bc 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -254,7 +254,7 @@
private @Mock AlarmManager mAlarmManager;
@Mock
private NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor;
- private @Mock BpfInterfaceMapUpdater mBpfInterfaceMapUpdater;
+ private @Mock BpfInterfaceMapHelper mBpfInterfaceMapHelper;
private HandlerThread mHandlerThread;
@Mock
private LocationPermissionChecker mLocationPermissionChecker;
@@ -519,9 +519,8 @@
}
@Override
- public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater(
- @NonNull Context ctx, @NonNull Handler handler) {
- return mBpfInterfaceMapUpdater;
+ public BpfInterfaceMapHelper makeBpfInterfaceMapHelper() {
+ return mBpfInterfaceMapHelper;
}
@Override
@@ -2764,13 +2763,13 @@
@Test
public void testDumpStatsMap() throws ErrnoException {
- doReturn("wlan0").when(mBpfInterfaceMapUpdater).getIfNameByIndex(10 /* index */);
+ doReturn("wlan0").when(mBpfInterfaceMapHelper).getIfNameByIndex(10 /* index */);
doTestDumpStatsMap("wlan0");
}
@Test
public void testDumpStatsMapUnknownInterface() throws ErrnoException {
- doReturn(null).when(mBpfInterfaceMapUpdater).getIfNameByIndex(10 /* index */);
+ doReturn(null).when(mBpfInterfaceMapHelper).getIfNameByIndex(10 /* index */);
doTestDumpStatsMap("unknown");
}
@@ -2785,13 +2784,13 @@
@Test
public void testDumpIfaceStatsMap() throws Exception {
- doReturn("wlan0").when(mBpfInterfaceMapUpdater).getIfNameByIndex(10 /* index */);
+ doReturn("wlan0").when(mBpfInterfaceMapHelper).getIfNameByIndex(10 /* index */);
doTestDumpIfaceStatsMap("wlan0");
}
@Test
public void testDumpIfaceStatsMapUnknownInterface() throws Exception {
- doReturn(null).when(mBpfInterfaceMapUpdater).getIfNameByIndex(10 /* index */);
+ doReturn(null).when(mBpfInterfaceMapHelper).getIfNameByIndex(10 /* index */);
doTestDumpIfaceStatsMap("unknown");
}
diff --git a/thread/scripts/make-pretty.sh b/thread/scripts/make-pretty.sh
index e4bd459..c176bfa 100755
--- a/thread/scripts/make-pretty.sh
+++ b/thread/scripts/make-pretty.sh
@@ -3,5 +3,7 @@
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
GOOGLE_JAVA_FORMAT=$SCRIPT_DIR/../../../../../prebuilts/tools/common/google-java-format/google-java-format
+ANDROID_BP_FORMAT=$SCRIPT_DIR/../../../../../prebuilts/build-tools/linux-x86/bin/bpfmt
$GOOGLE_JAVA_FORMAT --aosp -i $(find $SCRIPT_DIR/../ -name "*.java")
+$ANDROID_BP_FORMAT -w $(find $SCRIPT_DIR/../ -name "*.bp")
diff --git a/thread/tests/cts/Android.bp b/thread/tests/cts/Android.bp
index 3cf31e5..2f38bfd 100644
--- a/thread/tests/cts/Android.bp
+++ b/thread/tests/cts/Android.bp
@@ -45,7 +45,7 @@
libs: [
"android.test.base",
"android.test.runner",
- "framework-connectivity-module-api-stubs-including-flagged"
+ "framework-connectivity-module-api-stubs-including-flagged",
],
// Test coverage system runs on different devices. Need to
// compile for all architectures.
diff --git a/thread/tests/integration/Android.bp b/thread/tests/integration/Android.bp
index 405fb76..633389f 100644
--- a/thread/tests/integration/Android.bp
+++ b/thread/tests/integration/Android.bp
@@ -43,7 +43,7 @@
manifest: "AndroidManifest.xml",
defaults: [
"framework-connectivity-test-defaults",
- "ThreadNetworkIntegrationTestsDefaults"
+ "ThreadNetworkIntegrationTestsDefaults",
],
test_suites: [
"general-tests",