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.StrictMode; 20 import android.os.SystemProperties; 21 import android.util.Log; 22 import android.util.Slog; 23 24 import dalvik.system.SocketTagger; 25 26 import java.io.FileDescriptor; 27 import java.net.SocketException; 28 29 /** 30 * Assigns tags to sockets for traffic stats. 31 */ 32 public final class NetworkManagementSocketTagger extends SocketTagger { 33 private static final String TAG = "NetworkManagementSocketTagger"; 34 private static final boolean LOGD = false; 35 36 /** 37 * {@link SystemProperties} key that indicates if {@code qtaguid} bandwidth 38 * controls have been enabled. 39 */ 40 // TODO: remove when always enabled, or once socket tagging silently fails. 41 public static final String PROP_QTAGUID_ENABLED = "net.qtaguid_enabled"; 42 43 private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() { 44 @Override 45 protected SocketTags initialValue() { 46 return new SocketTags(); 47 } 48 }; 49 install()50 public static void install() { 51 SocketTagger.set(new NetworkManagementSocketTagger()); 52 } 53 setThreadSocketStatsTag(int tag)54 public static int setThreadSocketStatsTag(int tag) { 55 final int old = threadSocketTags.get().statsTag; 56 threadSocketTags.get().statsTag = tag; 57 return old; 58 } 59 getThreadSocketStatsTag()60 public static int getThreadSocketStatsTag() { 61 return threadSocketTags.get().statsTag; 62 } 63 setThreadSocketStatsUid(int uid)64 public static int setThreadSocketStatsUid(int uid) { 65 final int old = threadSocketTags.get().statsUid; 66 threadSocketTags.get().statsUid = uid; 67 return old; 68 } 69 70 @Override tag(FileDescriptor fd)71 public void tag(FileDescriptor fd) throws SocketException { 72 final SocketTags options = threadSocketTags.get(); 73 if (LOGD) { 74 Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" 75 + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid); 76 } 77 if (options.statsTag == -1 && StrictMode.vmUntaggedSocketEnabled()) { 78 StrictMode.onUntaggedSocket(); 79 } 80 // TODO: skip tagging when options would be no-op 81 tagSocketFd(fd, options.statsTag, options.statsUid); 82 } 83 tagSocketFd(FileDescriptor fd, int tag, int uid)84 private void tagSocketFd(FileDescriptor fd, int tag, int uid) { 85 if (tag == -1 && uid == -1) return; 86 87 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 88 final int errno = native_tagSocketFd(fd, tag, uid); 89 if (errno < 0) { 90 Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " 91 + tag + ", " + 92 + uid + ") failed with errno" + errno); 93 } 94 } 95 } 96 97 @Override untag(FileDescriptor fd)98 public void untag(FileDescriptor fd) throws SocketException { 99 if (LOGD) { 100 Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); 101 } 102 unTagSocketFd(fd); 103 } 104 unTagSocketFd(FileDescriptor fd)105 private void unTagSocketFd(FileDescriptor fd) { 106 final SocketTags options = threadSocketTags.get(); 107 if (options.statsTag == -1 && options.statsUid == -1) return; 108 109 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 110 final int errno = native_untagSocketFd(fd); 111 if (errno < 0) { 112 Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); 113 } 114 } 115 } 116 117 public static class SocketTags { 118 public int statsTag = -1; 119 public int statsUid = -1; 120 } 121 setKernelCounterSet(int uid, int counterSet)122 public static void setKernelCounterSet(int uid, int counterSet) { 123 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 124 final int errno = native_setCounterSet(counterSet, uid); 125 if (errno < 0) { 126 Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno " 127 + errno); 128 } 129 } 130 } 131 resetKernelUidStats(int uid)132 public static void resetKernelUidStats(int uid) { 133 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 134 int errno = native_deleteTagData(0, uid); 135 if (errno < 0) { 136 Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno); 137 } 138 } 139 } 140 141 /** 142 * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming 143 * format like {@code 0x7fffffff00000000}. 144 */ kernelToTag(String string)145 public static int kernelToTag(String string) { 146 int length = string.length(); 147 if (length > 10) { 148 return Long.decode(string.substring(0, length - 8)).intValue(); 149 } else { 150 return 0; 151 } 152 } 153 native_tagSocketFd(FileDescriptor fd, int tag, int uid)154 private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); native_untagSocketFd(FileDescriptor fd)155 private static native int native_untagSocketFd(FileDescriptor fd); native_setCounterSet(int uid, int counterSetNum)156 private static native int native_setCounterSet(int uid, int counterSetNum); native_deleteTagData(int tag, int uid)157 private static native int native_deleteTagData(int tag, int uid); 158 } 159