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