NetworkManagement SocketTagger: Migrate QTagUid support to JNI.
* Instead of javaland trying to write commands to /proc/net/xt_qtaguid/ctrl use the libcutils/qtaguid.c support via JNI. * Get rid of tagToKernel() handled by qtaguid library. Requires libcutils changes from c/132538/ Change-Id: I9de5b3fa4a596c56835024c6d376769a0eea7db1
This commit is contained in:
@ -75,30 +75,20 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
|
||||
Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x"
|
||||
+ Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid);
|
||||
}
|
||||
try {
|
||||
// TODO: skip tagging when options would be no-op
|
||||
tagSocketFd(fd, options.statsTag, options.statsUid);
|
||||
} catch (IOException e) {
|
||||
throw new SocketException("Problem tagging socket", e);
|
||||
}
|
||||
// TODO: skip tagging when options would be no-op
|
||||
tagSocketFd(fd, options.statsTag, options.statsUid);
|
||||
}
|
||||
|
||||
private void tagSocketFd(FileDescriptor fd, int tag, int uid) throws IOException {
|
||||
final int fdNum = fd.getInt$();
|
||||
if (fdNum == -1 || (tag == -1 && uid == -1)) return;
|
||||
private void tagSocketFd(FileDescriptor fd, int tag, int uid) {
|
||||
int errno;
|
||||
if (tag == -1 && uid == -1) return;
|
||||
|
||||
String cmd = "t " + fdNum;
|
||||
if (tag == -1) {
|
||||
// Case where just the uid needs adjusting. But probably the caller
|
||||
// will want to track his own name here, just in case.
|
||||
cmd += " 0";
|
||||
} else {
|
||||
cmd += " " + tagToKernel(tag);
|
||||
errno = native_tagSocketFd(fd, tag, uid);
|
||||
if (errno < 0) {
|
||||
Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", "
|
||||
+ tag + ", " +
|
||||
+ uid + ") failed with errno" + errno);
|
||||
}
|
||||
if (uid != -1) {
|
||||
cmd += " " + uid;
|
||||
}
|
||||
internalModuleCtrl(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -106,19 +96,18 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
|
||||
if (LOGD) {
|
||||
Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
|
||||
}
|
||||
try {
|
||||
unTagSocketFd(fd);
|
||||
} catch (IOException e) {
|
||||
throw new SocketException("Problem untagging socket", e);
|
||||
}
|
||||
unTagSocketFd(fd);
|
||||
}
|
||||
|
||||
private void unTagSocketFd(FileDescriptor fd) throws IOException {
|
||||
int fdNum = fd.getInt$();
|
||||
private void unTagSocketFd(FileDescriptor fd) {
|
||||
final SocketTags options = threadSocketTags.get();
|
||||
if (fdNum == -1 || (options.statsTag == -1 && options.statsUid == -1)) return;
|
||||
String cmd = "u " + fdNum;
|
||||
internalModuleCtrl(cmd);
|
||||
int errno;
|
||||
if (options.statsTag == -1 && options.statsUid == -1) return;
|
||||
|
||||
errno = native_untagSocketFd(fd);
|
||||
if (errno < 0) {
|
||||
Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SocketTags {
|
||||
@ -127,68 +116,19 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
|
||||
}
|
||||
|
||||
public static void setKernelCounterSet(int uid, int counterSet) {
|
||||
final StringBuilder command = new StringBuilder();
|
||||
command.append("s ").append(counterSet).append(" ").append(uid);
|
||||
try {
|
||||
internalModuleCtrl(command.toString());
|
||||
} catch (IOException e) {
|
||||
Slog.w(TAG, "problem changing counter set for uid " + uid + " : " + e);
|
||||
int errno = native_setCounterSet(counterSet, uid);
|
||||
if (errno < 0) {
|
||||
Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno " + errno);
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetKernelUidStats(int uid) {
|
||||
final StringBuilder command = new StringBuilder();
|
||||
command.append("d 0 ").append(uid);
|
||||
try {
|
||||
internalModuleCtrl(command.toString());
|
||||
} catch (IOException e) {
|
||||
Slog.w(TAG, "problem clearing counters for uid " + uid + " : " + e);
|
||||
int errno = native_deleteTagData(0, uid);
|
||||
if (errno < 0) {
|
||||
Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends commands to the kernel netfilter module.
|
||||
*
|
||||
* @param cmd command string for the qtaguid netfilter module. May not be null.
|
||||
* <p>Supports:
|
||||
* <ul><li>tag a socket:<br>
|
||||
* <code>t <i>sock_fd</i> <i>acct_tag</i> [<i>uid_in_case_caller_is_acting_on_behalf_of</i>]</code><br>
|
||||
* <code>*_tag</code> defaults to default_policy_tag_from_uid(uid_of_caller)<br>
|
||||
* <code>acct_tag</code> is either 0 or greater that 2^32.<br>
|
||||
* <code>uid_*</code> is only settable by privileged UIDs (DownloadManager,...)
|
||||
* </li>
|
||||
* <li>untag a socket, preserving counters:<br>
|
||||
* <code>u <i>sock_fd</i></code>
|
||||
* </li></ul>
|
||||
* <p>Notes:<br>
|
||||
* <ul><li><i>sock_fd</i> is withing the callers process space.</li>
|
||||
* <li><i>*_tag</i> are 64bit values</li></ul>
|
||||
*
|
||||
*/
|
||||
private static void internalModuleCtrl(String cmd) throws IOException {
|
||||
if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
|
||||
|
||||
// TODO: migrate to native library for tagging commands
|
||||
FileOutputStream procOut = null;
|
||||
try {
|
||||
procOut = new FileOutputStream("/proc/net/xt_qtaguid/ctrl");
|
||||
procOut.write(cmd.getBytes(Charsets.US_ASCII));
|
||||
} finally {
|
||||
IoUtils.closeQuietly(procOut);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert {@link Integer} tag to {@code /proc/} format. Assumes unsigned
|
||||
* base-10 format like {@code 2147483647}. Currently strips signed bit to
|
||||
* avoid using {@link BigInteger}.
|
||||
*/
|
||||
public static String tagToKernel(int tag) {
|
||||
// TODO: eventually write in hex, since that's what proc exports
|
||||
// TODO: migrate to direct integer instead of odd shifting
|
||||
return Long.toString((((long) tag) << 32) & 0x7FFFFFFF00000000L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming
|
||||
* format like {@code 0x7fffffff00000000}.
|
||||
@ -197,4 +137,9 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
|
||||
// TODO: migrate to direct integer instead of odd shifting
|
||||
return (int) (Long.decode(string) >> 32);
|
||||
}
|
||||
|
||||
private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid);
|
||||
private static native int native_untagSocketFd(FileDescriptor fd);
|
||||
private static native int native_setCounterSet(int uid, int counterSetNum);
|
||||
private static native int native_deleteTagData(int tag, int uid);
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ LOCAL_SRC_FILES:= \
|
||||
android_server_BluetoothService.cpp \
|
||||
android_server_BluetoothEventLoop.cpp \
|
||||
android_server_BluetoothA2dpService.cpp \
|
||||
android_server_NetworkManagementSocketTagger.cpp \
|
||||
android_server_Watchdog.cpp \
|
||||
android_ddm_DdmHandleNativeHeap.cpp \
|
||||
com_android_internal_os_ZygoteInit.cpp \
|
||||
|
@ -155,6 +155,7 @@ extern int register_android_bluetooth_BluetoothSocket(JNIEnv *env);
|
||||
extern int register_android_server_BluetoothService(JNIEnv* env);
|
||||
extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
|
||||
extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
|
||||
extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
|
||||
extern int register_android_server_Watchdog(JNIEnv* env);
|
||||
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
|
||||
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
|
||||
@ -1178,6 +1179,7 @@ static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_server_BluetoothService),
|
||||
REG_JNI(register_android_server_BluetoothEventLoop),
|
||||
REG_JNI(register_android_server_BluetoothA2dpService),
|
||||
REG_JNI(register_android_server_NetworkManagementSocketTagger),
|
||||
REG_JNI(register_android_server_Watchdog),
|
||||
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
|
||||
REG_JNI(register_android_backup_BackupDataInput),
|
||||
|
97
core/jni/android_server_NetworkManagementSocketTagger.cpp
Normal file
97
core/jni/android_server_NetworkManagementSocketTagger.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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 <utils/Log.h>
|
||||
|
||||
#include "JNIHelp.h"
|
||||
|
||||
#include "jni.h"
|
||||
#include <utils/misc.h>
|
||||
#include <cutils/qtaguid.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static jint QTagUid_tagSocketFd(JNIEnv* env, jclass,
|
||||
jobject fileDescriptor,
|
||||
jint tagNum, jint uid) {
|
||||
int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
|
||||
|
||||
if (env->ExceptionOccurred() != NULL) {
|
||||
LOGE("Can't get FileDescriptor num");
|
||||
return (jint)-1;
|
||||
}
|
||||
|
||||
int res = qtaguid_tagSocket(userFd, tagNum, uid);
|
||||
if (res < 0) {
|
||||
return (jint)-errno;
|
||||
}
|
||||
return (jint)res;
|
||||
}
|
||||
|
||||
static int QTagUid_untagSocketFd(JNIEnv* env, jclass,
|
||||
jobject fileDescriptor) {
|
||||
int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
|
||||
|
||||
if (env->ExceptionOccurred() != NULL) {
|
||||
LOGE("Can't get FileDescriptor num");
|
||||
return (jint)-1;
|
||||
}
|
||||
|
||||
int res = qtaguid_untagSocket(userFd);
|
||||
if (res < 0) {
|
||||
return (jint)-errno;
|
||||
}
|
||||
return (jint)res;
|
||||
}
|
||||
|
||||
static jint QTagUid_setCounterSet(JNIEnv* env, jclass,
|
||||
jint setNum, jint uid) {
|
||||
|
||||
int res = qtaguid_setCounterSet(setNum, uid);
|
||||
if (res < 0) {
|
||||
return (jint)-errno;
|
||||
}
|
||||
return (jint)res;
|
||||
}
|
||||
|
||||
static jint QTagUid_deleteTagData(JNIEnv* env, jclass,
|
||||
jint tagNum, jint uid) {
|
||||
|
||||
int res = qtaguid_deleteTagData(tagNum, uid);
|
||||
if (res < 0) {
|
||||
return (jint)-errno;
|
||||
}
|
||||
return (jint)res;
|
||||
}
|
||||
|
||||
static JNINativeMethod gQTagUidMethods[] = {
|
||||
{ "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)QTagUid_tagSocketFd},
|
||||
{ "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)QTagUid_untagSocketFd},
|
||||
{ "native_setCounterSet", "(II)I", (void*)QTagUid_setCounterSet},
|
||||
{ "native_deleteTagData", "(II)I", (void*)QTagUid_deleteTagData},
|
||||
};
|
||||
|
||||
int register_android_server_NetworkManagementSocketTagger(JNIEnv* env) {
|
||||
return jniRegisterNativeMethods(env, "com/android/server/NetworkManagementSocketTagger", gQTagUidMethods, NELEM(gQTagUidMethods));
|
||||
}
|
||||
|
||||
};
|
@ -21,7 +21,6 @@ import static android.net.NetworkStats.SET_FOREGROUND;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
|
||||
import static com.android.server.NetworkManagementSocketTagger.tagToKernel;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.net.NetworkStats;
|
||||
@ -144,12 +143,6 @@ public class NetworkManagementServiceTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testKernelTags() throws Exception {
|
||||
assertEquals("0", tagToKernel(0x0));
|
||||
assertEquals("214748364800", tagToKernel(0x32));
|
||||
assertEquals("9223372032559808512", tagToKernel(Integer.MAX_VALUE));
|
||||
assertEquals("0", tagToKernel(Integer.MIN_VALUE));
|
||||
assertEquals("9223369837831520256", tagToKernel(Integer.MIN_VALUE - 512));
|
||||
|
||||
assertEquals(0, kernelToTag("0x0000000000000000"));
|
||||
assertEquals(0x32, kernelToTag("0x0000003200000000"));
|
||||
assertEquals(2147483647, kernelToTag("0x7fffffff00000000"));
|
||||
|
Reference in New Issue
Block a user