1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server; 18 19 import android.os.SystemProperties; 20 import android.util.Log; 21 import android.util.Slog; 22 23 import dalvik.system.SocketTagger; 24 25 import java.io.FileDescriptor; 26 import java.net.SocketException; 27 28 /** 29 * Assigns tags to sockets for traffic stats. 30 */ 31 public final class NetworkManagementSocketTagger extends SocketTagger { 32 private static final String TAG = "NetworkManagementSocketTagger"; 33 private static final boolean LOGD = false; 34 35 /** 36 * {@link SystemProperties} key that indicates if {@code qtaguid} bandwidth 37 * controls have been enabled. 38 */ 39 // TODO: remove when always enabled, or once socket tagging silently fails. 40 public static final String PROP_QTAGUID_ENABLED = "net.qtaguid_enabled"; 41 42 private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() { 43 @Override 44 protected SocketTags initialValue() { 45 return new SocketTags(); 46 } 47 }; 48 49 public static void install() { 50 SocketTagger.set(new NetworkManagementSocketTagger()); 51 } 52 53 public static void setThreadSocketStatsTag(int tag) { 54 threadSocketTags.get().statsTag = tag; 55 } 56 57 public static int getThreadSocketStatsTag() { 58 return threadSocketTags.get().statsTag; 59 } 60 61 public static void setThreadSocketStatsUid(int uid) { 62 threadSocketTags.get().statsUid = uid; 63 } 64 65 @Override 66 public void tag(FileDescriptor fd) throws SocketException { 67 final SocketTags options = threadSocketTags.get(); 68 if (LOGD) { 69 Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" 70 + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid); 71 } 72 // TODO: skip tagging when options would be no-op 73 tagSocketFd(fd, options.statsTag, options.statsUid); 74 } 75 76 private void tagSocketFd(FileDescriptor fd, int tag, int uid) { 77 if (tag == -1 && uid == -1) return; 78 79 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 80 final int errno = native_tagSocketFd(fd, tag, uid); 81 if (errno < 0) { 82 Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " 83 + tag + ", " + 84 + uid + ") failed with errno" + errno); 85 } 86 } 87 } 88 89 @Override 90 public void untag(FileDescriptor fd) throws SocketException { 91 if (LOGD) { 92 Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); 93 } 94 unTagSocketFd(fd); 95 } 96 97 private void unTagSocketFd(FileDescriptor fd) { 98 final SocketTags options = threadSocketTags.get(); 99 if (options.statsTag == -1 && options.statsUid == -1) return; 100 101 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 102 final int errno = native_untagSocketFd(fd); 103 if (errno < 0) { 104 Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); 105 } 106 } 107 } 108 109 public static class SocketTags { 110 public int statsTag = -1; 111 public int statsUid = -1; 112 } 113 114 public static void setKernelCounterSet(int uid, int counterSet) { 115 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 116 final int errno = native_setCounterSet(counterSet, uid); 117 if (errno < 0) { 118 Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno " 119 + errno); 120 } 121 } 122 } 123 124 public static void resetKernelUidStats(int uid) { 125 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 126 int errno = native_deleteTagData(0, uid); 127 if (errno < 0) { 128 Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno); 129 } 130 } 131 } 132 133 /** 134 * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming 135 * format like {@code 0x7fffffff00000000}. 136 */ 137 public static int kernelToTag(String string) { 138 int length = string.length(); 139 if (length > 10) { 140 return Long.decode(string.substring(0, length - 8)).intValue(); 141 } else { 142 return 0; 143 } 144 } 145 146 private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); 147 private static native int native_untagSocketFd(FileDescriptor fd); 148 private static native int native_setCounterSet(int uid, int counterSetNum); 149 private static native int native_deleteTagData(int tag, int uid); 150 } 151