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 getThreadSocketStatsUid()70 public static int getThreadSocketStatsUid() { 71 return threadSocketTags.get().statsUid; 72 } 73 74 @Override tag(FileDescriptor fd)75 public void tag(FileDescriptor fd) throws SocketException { 76 final SocketTags options = threadSocketTags.get(); 77 if (LOGD) { 78 Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" 79 + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid); 80 } 81 if (options.statsTag == -1 && StrictMode.vmUntaggedSocketEnabled()) { 82 StrictMode.onUntaggedSocket(); 83 } 84 // TODO: skip tagging when options would be no-op 85 tagSocketFd(fd, options.statsTag, options.statsUid); 86 } 87 tagSocketFd(FileDescriptor fd, int tag, int uid)88 private void tagSocketFd(FileDescriptor fd, int tag, int uid) { 89 if (tag == -1 && uid == -1) return; 90 91 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 92 final int errno = native_tagSocketFd(fd, tag, uid); 93 if (errno < 0) { 94 Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " 95 + tag + ", " + 96 + uid + ") failed with errno" + errno); 97 } 98 } 99 } 100 101 @Override untag(FileDescriptor fd)102 public void untag(FileDescriptor fd) throws SocketException { 103 if (LOGD) { 104 Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); 105 } 106 unTagSocketFd(fd); 107 } 108 unTagSocketFd(FileDescriptor fd)109 private void unTagSocketFd(FileDescriptor fd) { 110 final SocketTags options = threadSocketTags.get(); 111 if (options.statsTag == -1 && options.statsUid == -1) return; 112 113 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 114 final int errno = native_untagSocketFd(fd); 115 if (errno < 0) { 116 Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); 117 } 118 } 119 } 120 121 public static class SocketTags { 122 public int statsTag = -1; 123 public int statsUid = -1; 124 } 125 setKernelCounterSet(int uid, int counterSet)126 public static void setKernelCounterSet(int uid, int counterSet) { 127 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 128 final int errno = native_setCounterSet(counterSet, uid); 129 if (errno < 0) { 130 Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno " 131 + errno); 132 } 133 } 134 } 135 resetKernelUidStats(int uid)136 public static void resetKernelUidStats(int uid) { 137 if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) { 138 int errno = native_deleteTagData(0, uid); 139 if (errno < 0) { 140 Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno); 141 } 142 } 143 } 144 145 /** 146 * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming 147 * format like {@code 0x7fffffff00000000}. 148 */ kernelToTag(String string)149 public static int kernelToTag(String string) { 150 int length = string.length(); 151 if (length > 10) { 152 return Long.decode(string.substring(0, length - 8)).intValue(); 153 } else { 154 return 0; 155 } 156 } 157 native_tagSocketFd(FileDescriptor fd, int tag, int uid)158 private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); native_untagSocketFd(FileDescriptor fd)159 private static native int native_untagSocketFd(FileDescriptor fd); native_setCounterSet(int uid, int counterSetNum)160 private static native int native_setCounterSet(int uid, int counterSetNum); native_deleteTagData(int tag, int uid)161 private static native int native_deleteTagData(int tag, int uid); 162 } 163