Loading packages/ConnectivityT/service/Android.bp +27 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ filegroup { srcs: [ "src/com/android/server/net/NetworkIdentity*.java", "src/com/android/server/net/NetworkStats*.java", "src/com/android/server/net/BpfInterfaceMapUpdater.java", "src/com/android/server/net/InterfaceMapValue.java", ], path: "src", visibility: [ Loading Loading @@ -98,3 +100,28 @@ filegroup { "//packages/modules/Connectivity:__subpackages__", ], } cc_library_shared { name: "libcom_android_net_module_util_jni", min_sdk_version: "30", cflags: [ "-Wall", "-Werror", "-Wno-unused-parameter", "-Wthread-safety", ], srcs: [ "jni/onload.cpp", ], stl: "libc++_static", static_libs: [ "libnet_utils_device_common_bpfjni", ], shared_libs: [ "liblog", "libnativehelper", ], apex_available: [ "//apex_available:platform", ], } packages/ConnectivityT/service/jni/onload.cpp 0 → 100644 +38 −0 Original line number Diff line number Diff line /* * 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. */ #include <nativehelper/JNIHelp.h> #include <log/log.h> namespace android { int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name); extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { ALOGE("GetEnv failed"); return JNI_ERR; } if (register_com_android_net_module_util_BpfMap(env, "com/android/net/module/util/BpfMap") < 0) return JNI_ERR; return JNI_VERSION_1_6; } }; packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java 0 → 100644 +139 −0 Original line number Diff line number Diff line /* * 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.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.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.BaseNetdUnsolicitedEventListener; 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.U32; /** * Monitor interface added (without removed) and right interface name and its index to bpf map. */ 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/map_netd_iface_index_name_map"; private final IBpfMap<U32, InterfaceMapValue> mBpfMap; 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; mBpfMap = 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<U32, InterfaceMapValue> getInterfaceMap() { try { return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH, BpfMap.BPF_F_RDWR, U32.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 (mBpfMap == 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 { mBpfMap.updateEntry(new U32(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)); } } } packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.net.module.util.Struct; import com.android.net.module.util.Struct.Field; import com.android.net.module.util.Struct.Type; /** * The value of bpf interface index map which is used for NetworkStatsService. */ public class InterfaceMapValue extends Struct { @Field(order = 0, type = Type.ByteArray, arraysize = 16) public final byte[] interfaceName; public InterfaceMapValue(String iface) { final byte[] ifaceArray = iface.getBytes(); interfaceName = new byte[16]; // All array bytes after the interface name, if any, must be 0. System.arraycopy(ifaceArray, 0, interfaceName, 0, ifaceArray.length); } } packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java +12 −0 Original line number Diff line number Diff line Loading @@ -357,6 +357,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final LocationPermissionChecker mLocationPermissionChecker; @NonNull private final BpfInterfaceMapUpdater mInterfaceMapUpdater; private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } Loading Loading @@ -454,6 +457,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, mNetworkStatsSubscriptionsMonitor); mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler); mInterfaceMapUpdater.start(); } /** Loading Loading @@ -508,6 +513,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public LocationPermissionChecker makeLocationPermissionChecker(final Context context) { return new LocationPermissionChecker(context); } /** Create BpfInterfaceMapUpdater to update bpf interface map. */ @NonNull public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater( @NonNull Context ctx, @NonNull Handler handler) { return new BpfInterfaceMapUpdater(ctx, handler); } } /** Loading Loading
packages/ConnectivityT/service/Android.bp +27 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ filegroup { srcs: [ "src/com/android/server/net/NetworkIdentity*.java", "src/com/android/server/net/NetworkStats*.java", "src/com/android/server/net/BpfInterfaceMapUpdater.java", "src/com/android/server/net/InterfaceMapValue.java", ], path: "src", visibility: [ Loading Loading @@ -98,3 +100,28 @@ filegroup { "//packages/modules/Connectivity:__subpackages__", ], } cc_library_shared { name: "libcom_android_net_module_util_jni", min_sdk_version: "30", cflags: [ "-Wall", "-Werror", "-Wno-unused-parameter", "-Wthread-safety", ], srcs: [ "jni/onload.cpp", ], stl: "libc++_static", static_libs: [ "libnet_utils_device_common_bpfjni", ], shared_libs: [ "liblog", "libnativehelper", ], apex_available: [ "//apex_available:platform", ], }
packages/ConnectivityT/service/jni/onload.cpp 0 → 100644 +38 −0 Original line number Diff line number Diff line /* * 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. */ #include <nativehelper/JNIHelp.h> #include <log/log.h> namespace android { int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name); extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { ALOGE("GetEnv failed"); return JNI_ERR; } if (register_com_android_net_module_util_BpfMap(env, "com/android/net/module/util/BpfMap") < 0) return JNI_ERR; return JNI_VERSION_1_6; } };
packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java 0 → 100644 +139 −0 Original line number Diff line number Diff line /* * 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.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.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.BaseNetdUnsolicitedEventListener; 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.U32; /** * Monitor interface added (without removed) and right interface name and its index to bpf map. */ 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/map_netd_iface_index_name_map"; private final IBpfMap<U32, InterfaceMapValue> mBpfMap; 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; mBpfMap = 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<U32, InterfaceMapValue> getInterfaceMap() { try { return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH, BpfMap.BPF_F_RDWR, U32.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 (mBpfMap == 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 { mBpfMap.updateEntry(new U32(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)); } } }
packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 com.android.net.module.util.Struct; import com.android.net.module.util.Struct.Field; import com.android.net.module.util.Struct.Type; /** * The value of bpf interface index map which is used for NetworkStatsService. */ public class InterfaceMapValue extends Struct { @Field(order = 0, type = Type.ByteArray, arraysize = 16) public final byte[] interfaceName; public InterfaceMapValue(String iface) { final byte[] ifaceArray = iface.getBytes(); interfaceName = new byte[16]; // All array bytes after the interface name, if any, must be 0. System.arraycopy(ifaceArray, 0, interfaceName, 0, ifaceArray.length); } }
packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java +12 −0 Original line number Diff line number Diff line Loading @@ -357,6 +357,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final LocationPermissionChecker mLocationPermissionChecker; @NonNull private final BpfInterfaceMapUpdater mInterfaceMapUpdater; private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } Loading Loading @@ -454,6 +457,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, mNetworkStatsSubscriptionsMonitor); mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler); mInterfaceMapUpdater.start(); } /** Loading Loading @@ -508,6 +513,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public LocationPermissionChecker makeLocationPermissionChecker(final Context context) { return new LocationPermissionChecker(context); } /** Create BpfInterfaceMapUpdater to update bpf interface map. */ @NonNull public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater( @NonNull Context ctx, @NonNull Handler handler) { return new BpfInterfaceMapUpdater(ctx, handler); } } /** Loading