From d0a17ee9d55619c423f58c3db42af4f8b8c90978 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 29 Jan 2022 21:07:33 +0900 Subject: [PATCH] Move socket tagging implementation to mainline. Currently, socket tagging is implemented in the framework. The Java code is in NetworkManagmentSocketTagger.java and the JNI is in libandroid and loaded by the general framework JNI loader. - Move the Java implementation to TrafficStats, which is the only caller of NetworkManagmentSocketTagger. This simplifies the code a bit because a number of methods can be deleted. - Move the JNI code to a new JNI library in the APEX. The library depends only on the NDK and statically links the NDK-only version of libnativehelper. Its size is only 5k on ARM and 10k on ARM64. - Temporarily make the framework depend on this library until the rest of the T connectivity code moves to the APEX. Test: atest NetworkUsageStatsTest CtsNetTestCases:TrafficStatsTest Change-Id: I050c7c515237f68b78d08987bc443f50a7949c06 --- core/jni/Android.bp | 3 +- core/jni/AndroidRuntime.cpp | 2 - ...d_server_NetworkManagementSocketTagger.cpp | 73 ---------------- packages/ConnectivityT/framework-t/Android.bp | 32 ++++++- .../jni/android_net_TrafficStats.cpp | 46 ++++++++++ .../ConnectivityT/framework-t/jni/onload.cpp | 39 +++++++++ .../src/android/net/TrafficStats.java | 86 ++++++++++++++++--- 7 files changed, 192 insertions(+), 89 deletions(-) delete mode 100644 core/jni/android_server_NetworkManagementSocketTagger.cpp create mode 100644 packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp create mode 100644 packages/ConnectivityT/framework-t/jni/onload.cpp diff --git a/core/jni/Android.bp b/core/jni/Android.bp index adcbb425d1cfa..dd2015dd7c6d0 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -195,7 +195,6 @@ cc_library_shared { "android_util_FileObserver.cpp", "android/opengl/poly_clip.cpp", // TODO: .arm "android/opengl/util.cpp", - "android_server_NetworkManagementSocketTagger.cpp", "android_ddm_DdmHandleNativeHeap.cpp", "android_backup_BackupDataInput.cpp", "android_backup_BackupDataOutput.cpp", @@ -299,6 +298,8 @@ cc_library_shared { "libdl_android", "libtimeinstate", "server_configurable_flags", + // TODO: delete when ConnectivityT moves to APEX. + "libframework-connectivity-tiramisu-jni", ], export_shared_lib_headers: [ // our headers include libnativewindow's public headers diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 0f98b74441a74..1c4107a12b747 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -164,7 +164,6 @@ extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_Hyphenator(JNIEnv *env); extern int register_android_opengl_classes(JNIEnv *env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); -extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env); extern int register_android_backup_BackupDataInput(JNIEnv *env); extern int register_android_backup_BackupDataOutput(JNIEnv *env); extern int register_android_backup_FileBackupHelperBase(JNIEnv *env); @@ -1618,7 +1617,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_media_midi), REG_JNI(register_android_opengl_classes), - REG_JNI(register_android_server_NetworkManagementSocketTagger), REG_JNI(register_android_ddm_DdmHandleNativeHeap), REG_JNI(register_android_backup_BackupDataInput), REG_JNI(register_android_backup_BackupDataOutput), diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp deleted file mode 100644 index 9734ab9b9e1d0..0000000000000 --- a/core/jni/android_server_NetworkManagementSocketTagger.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2011, 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. - */ - -#define LOG_TAG "NMST_QTagUidNative" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "jni.h" - -namespace android { - -static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor, - jint tagNum, jint uid) { - int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor); - - if (env->ExceptionCheck()) { - ALOGE("Can't get FileDescriptor num"); - return (jint)-1; - } - - int res = android_tag_socket_with_uid(userFd, tagNum, uid); - if (res < 0) { - return (jint)-errno; - } - return (jint)res; -} - -static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) { - int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor); - - if (env->ExceptionCheck()) { - ALOGE("Can't get FileDescriptor num"); - return (jint)-1; - } - - int res = android_untag_socket(userFd); - if (res < 0) { - return (jint)-errno; - } - return (jint)res; -} - -static const JNINativeMethod gQTagUidMethods[] = { - { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)tagSocketFd}, - { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)untagSocketFd}, -}; - -int register_android_server_NetworkManagementSocketTagger(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/NetworkManagementSocketTagger", gQTagUidMethods, NELEM(gQTagUidMethods)); -} - -}; diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp index 223bdcdd9c955..327b1fb2f5d8f 100644 --- a/packages/ConnectivityT/framework-t/Android.bp +++ b/packages/ConnectivityT/framework-t/Android.bp @@ -39,7 +39,6 @@ filegroup { "src/android/net/TrafficStats.java", "src/android/net/UnderlyingNetworkInfo.*", "src/android/net/netstats/**/*.*", - "src/com/android/server/NetworkManagementSocketTagger.java", ], path: "src", visibility: [ @@ -176,3 +175,34 @@ filegroup { "//packages/modules/Connectivity:__subpackages__", ], } + +cc_library_shared { + name: "libframework-connectivity-tiramisu-jni", + min_sdk_version: "30", + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + // Don't warn about S API usage even with + // min_sdk 30: the library is only loaded + // on S+ devices + "-Wno-unguarded-availability", + "-Wthread-safety", + ], + srcs: [ + "jni/android_net_TrafficStats.cpp", + "jni/onload.cpp", + ], + shared_libs: [ + "liblog", + ], + static_libs: [ + "libnativehelper_compat_libc++", + ], + stl: "none", + apex_available: [ + "com.android.tethering", + // TODO: remove when ConnectivityT moves to APEX. + "//apex_available:platform", + ], +} diff --git a/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp b/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp new file mode 100644 index 0000000000000..f3c58b112f0d3 --- /dev/null +++ b/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp @@ -0,0 +1,46 @@ +/* + * 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 +#include +#include + +namespace android { + +static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor, jint tag, jint uid) { + int fd = AFileDescriptor_getFd(env, fileDescriptor); + if (fd == -1) return -EBADF; + return android_tag_socket_with_uid(fd, tag, uid); +} + +static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) { + int fd = AFileDescriptor_getFd(env, fileDescriptor); + if (fd == -1) return -EBADF; + return android_untag_socket(fd); +} + +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*) tagSocketFd }, + { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*) untagSocketFd }, +}; + +int register_android_net_TrafficStats(JNIEnv* env) { + return jniRegisterNativeMethods(env, "android/net/TrafficStats", gMethods, NELEM(gMethods)); +} + +}; // namespace android + diff --git a/packages/ConnectivityT/framework-t/jni/onload.cpp b/packages/ConnectivityT/framework-t/jni/onload.cpp new file mode 100644 index 0000000000000..1fb42c63477e4 --- /dev/null +++ b/packages/ConnectivityT/framework-t/jni/onload.cpp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#define LOG_TAG "FrameworkConnectivityJNI" + +#include +#include + +namespace android { + +int register_android_net_TrafficStats(JNIEnv* env); + +extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); + return JNI_ERR; + } + + if (register_android_net_TrafficStats(env) < 0) return JNI_ERR; + + return JNI_VERSION_1_6; +} + +}; // namespace android + diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java index c2f0cdfb048cd..bc836d857e3ec 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java +++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java @@ -31,12 +31,9 @@ import android.media.MediaPlayer; import android.os.Binder; import android.os.Build; import android.os.RemoteException; +import android.os.StrictMode; import android.util.Log; -import com.android.server.NetworkManagementSocketTagger; - -import dalvik.system.SocketTagger; - import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramSocket; @@ -56,6 +53,10 @@ import java.net.SocketException; * use {@link NetworkStatsManager} instead. */ public class TrafficStats { + static { + System.loadLibrary("framework-connectivity-tiramisu-jni"); + } + private static final String TAG = TrafficStats.class.getSimpleName(); /** * The return value to indicate that the device does not support the statistic. @@ -232,9 +233,68 @@ public class TrafficStats { */ @SystemApi(client = MODULE_LIBRARIES) public static void attachSocketTagger() { - NetworkManagementSocketTagger.install(); + dalvik.system.SocketTagger.set(new SocketTagger()); } + private static class SocketTagger extends dalvik.system.SocketTagger { + + // TODO: set to false + private static final boolean LOGD = true; + + SocketTagger() { + } + + @Override + public void tag(FileDescriptor fd) throws SocketException { + final UidTag tagInfo = sThreadUidTag.get(); + if (LOGD) { + Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" + + Integer.toHexString(tagInfo.tag) + ", statsUid=" + tagInfo.uid); + } + if (tagInfo.tag == -1) { + StrictMode.noteUntaggedSocket(); + } + + if (tagInfo.tag == -1 && tagInfo.uid == -1) return; + final int errno = native_tagSocketFd(fd, tagInfo.tag, tagInfo.uid); + if (errno < 0) { + Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " + + tagInfo.tag + ", " + + tagInfo.uid + ") failed with errno" + errno); + } + } + + @Override + public void untag(FileDescriptor fd) throws SocketException { + if (LOGD) { + Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); + } + + final UidTag tagInfo = sThreadUidTag.get(); + if (tagInfo.tag == -1 && tagInfo.uid == -1) return; + + final int errno = native_untagSocketFd(fd); + if (errno < 0) { + Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); + } + } + } + + private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); + private static native int native_untagSocketFd(FileDescriptor fd); + + private static class UidTag { + public int tag = -1; + public int uid = -1; + } + + private static ThreadLocal sThreadUidTag = new ThreadLocal() { + @Override + protected UidTag initialValue() { + return new UidTag(); + } + }; + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. @@ -249,7 +309,7 @@ public class TrafficStats { * @see #clearThreadStatsTag() */ public static void setThreadStatsTag(int tag) { - NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); + getAndSetThreadStatsTag(tag); } /** @@ -267,7 +327,9 @@ public class TrafficStats { * restore any existing values after a nested operation is finished */ public static int getAndSetThreadStatsTag(int tag) { - return NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); + final int old = sThreadUidTag.get().tag; + sThreadUidTag.get().tag = tag; + return old; } /** @@ -327,7 +389,7 @@ public class TrafficStats { * @see #setThreadStatsTag(int) */ public static int getThreadStatsTag() { - return NetworkManagementSocketTagger.getThreadSocketStatsTag(); + return sThreadUidTag.get().tag; } /** @@ -337,7 +399,7 @@ public class TrafficStats { * @see #setThreadStatsTag(int) */ public static void clearThreadStatsTag() { - NetworkManagementSocketTagger.setThreadSocketStatsTag(-1); + sThreadUidTag.get().tag = -1; } /** @@ -357,7 +419,7 @@ public class TrafficStats { */ @SuppressLint("RequiresPermission") public static void setThreadStatsUid(int uid) { - NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); + sThreadUidTag.get().uid = uid; } /** @@ -368,7 +430,7 @@ public class TrafficStats { * @see #setThreadStatsUid(int) */ public static int getThreadStatsUid() { - return NetworkManagementSocketTagger.getThreadSocketStatsUid(); + return sThreadUidTag.get().uid; } /** @@ -395,7 +457,7 @@ public class TrafficStats { */ @SuppressLint("RequiresPermission") public static void clearThreadStatsUid() { - NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); + setThreadStatsUid(-1); } /**