From e6d511f7851fa6e5ba429c5c8501092f9cfcf89d Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Tue, 25 Jan 2022 11:10:42 +0800 Subject: [PATCH] Support "dumpsys connectivity trafficcontroller" Enable ConnectivityService to dump BPF maps from libtraffic_controller. Bug: 202086915 Test: adb shell dumpsys connectivity trafficcontroller Test: atest CtsNetTestCases:ConnectivityManagerTest#testDumpBpfNetMaps Test: run CTS in I021789813f116940d581e2c4a1fd357ff47bfa08 Change-Id: Ib0e935ee2b714ac61daceba6d13fa7a20f97f68f --- service/jni/com_android_server_BpfNetMaps.cpp | 12 ++++++++++ service/native/TrafficController.cpp | 4 +++- service/native/include/TrafficController.h | 2 +- .../src/com/android/server/BpfNetMaps.java | 23 +++++++++++++++++++ .../android/server/ConnectivityService.java | 16 +++++++++++++ .../net/cts/ConnectivityManagerTest.java | 13 +++++++++++ 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp index 85cfc09877..63961cb283 100644 --- a/service/jni/com_android_server_BpfNetMaps.cpp +++ b/service/jni/com_android_server_BpfNetMaps.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -186,6 +187,15 @@ static void native_setPermissionForUids(JNIEnv* env, jobject clazz, jint permiss mTc.setPermissionForUids(permission, data); } +static void native_dump(JNIEnv* env, jobject clazz, jobject javaFd, jboolean verbose) { + int fd = netjniutils::GetNativeFileDescriptor(env, javaFd); + if (fd < 0) { + jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor"); + return; + } + mTc.dump(fd, verbose); +} + /* * JNI registration. */ @@ -216,6 +226,8 @@ static const JNINativeMethod gMethods[] = { (void*)native_swapActiveStatsMap}, {"native_setPermissionForUids", "(I[I)V", (void*)native_setPermissionForUids}, + {"native_dump", "(Ljava/io/FileDescriptor;Z)V", + (void*)native_dump}, }; // clang-format on diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp index 1cbfd947b6..393ee0a4b2 100644 --- a/service/native/TrafficController.cpp +++ b/service/native/TrafficController.cpp @@ -601,8 +601,10 @@ void dumpBpfMap(const std::string& mapName, DumpWriter& dw, const std::string& h } } -void TrafficController::dump(DumpWriter& dw, bool verbose) { +void TrafficController::dump(int fd, bool verbose) { std::lock_guard guard(mMutex); + DumpWriter dw(fd); + ScopedIndent indentTop(dw); dw.println("TrafficController"); diff --git a/service/native/include/TrafficController.h b/service/native/include/TrafficController.h index 6fe117f578..79e75ace49 100644 --- a/service/native/include/TrafficController.h +++ b/service/native/include/TrafficController.h @@ -62,7 +62,7 @@ class TrafficController { netdutils::Status updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule, FirewallType type) EXCLUDES(mMutex); - void dump(netdutils::DumpWriter& dw, bool verbose) EXCLUDES(mMutex); + void dump(int fd, bool verbose) EXCLUDES(mMutex); netdutils::Status replaceRulesInMap(UidOwnerMatchType match, const std::vector& uids) EXCLUDES(mMutex); diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java index ddee275d7a..f2ca18b2cc 100644 --- a/service/src/com/android/server/BpfNetMaps.java +++ b/service/src/com/android/server/BpfNetMaps.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.system.OsConstants.EOPNOTSUPP; + import android.net.INetd; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -24,6 +26,9 @@ import android.util.Log; import com.android.modules.utils.build.SdkLevel; +import java.io.FileDescriptor; +import java.io.IOException; + /** * BpfNetMaps is responsible for providing traffic controller relevant functionality. * @@ -273,6 +278,23 @@ public class BpfNetMaps { native_setPermissionForUids(permissions, uids); } + /** + * Dump BPF maps + * + * @param fd file descriptor to output + * @throws IOException when file descriptor is invalid. + * @throws ServiceSpecificException when the method is called on an unsupported device. + */ + public void dump(final FileDescriptor fd, boolean verbose) + throws IOException, ServiceSpecificException { + if (USE_NETD) { + throw new ServiceSpecificException( + EOPNOTSUPP, "dumpsys connectivity trafficcontroller dump not available on pre-T" + + " devices, use dumpsys netd trafficcontroller instead."); + } + native_dump(fd, verbose); + } + private static native void native_init(); private native int native_addNaughtyApp(int uid); private native int native_removeNaughtyApp(int uid); @@ -285,4 +307,5 @@ public class BpfNetMaps { private native int native_removeUidInterfaceRules(int[] uids); private native int native_swapActiveStatsMap(); private native void native_setPermissionForUids(int permissions, int[] uids); + private native void native_dump(FileDescriptor fd, boolean verbose); } diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 6024a2a45f..d46ec61022 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -313,6 +313,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public static final String SHORT_ARG = "--short"; private static final String NETWORK_ARG = "networks"; private static final String REQUEST_ARG = "requests"; + private static final String TRAFFICCONTROLLER_ARG = "trafficcontroller"; private static final boolean DBG = true; private static final boolean DDBG = Log.isLoggable(TAG, Log.DEBUG); @@ -3212,6 +3213,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } else if (CollectionUtils.contains(args, REQUEST_ARG)) { dumpNetworkRequests(pw); return; + } else if (CollectionUtils.contains(args, TRAFFICCONTROLLER_ARG)) { + boolean verbose = !CollectionUtils.contains(args, SHORT_ARG); + dumpTrafficController(pw, fd, verbose); + return; } pw.print("NetworkProviders for:"); @@ -3429,6 +3434,17 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void dumpTrafficController(IndentingPrintWriter pw, final FileDescriptor fd, + boolean verbose) { + try { + mBpfNetMaps.dump(fd, verbose); + } catch (ServiceSpecificException e) { + pw.println(e.getMessage()); + } catch (IOException e) { + loge("Dump BPF maps failed, " + e); + } + } + private void dumpAllRequestInfoLogsToLogcat() { try (PrintWriter logPw = new PrintWriter(new Writer() { @Override diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index ea64252200..ac520d1d65 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -3259,6 +3259,19 @@ public class ConnectivityManagerTest { assertTrue(dumpOutput, dumpOutput.contains("Active default network")); } + @Test @IgnoreUpTo(SC_V2) + public void testDumpBpfNetMaps() throws Exception { + final String[] args = new String[] {"--short", "trafficcontroller"}; + String dumpOutput = DumpTestUtils.dumpServiceWithShellPermission( + Context.CONNECTIVITY_SERVICE, args); + assertTrue(dumpOutput, dumpOutput.contains("TrafficController")); + assertFalse(dumpOutput, dumpOutput.contains("BPF map content")); + + dumpOutput = DumpTestUtils.dumpServiceWithShellPermission( + Context.CONNECTIVITY_SERVICE, args[1]); + assertTrue(dumpOutput, dumpOutput.contains("BPF map content")); + } + private void unregisterRegisteredCallbacks() { for (NetworkCallback callback: mRegisteredCallbacks) { mCm.unregisterNetworkCallback(callback);