Home | History | Annotate | Download | only in server
      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 
     50     public static void install() {
     51         SocketTagger.set(new NetworkManagementSocketTagger());
     52     }
     53 
     54     public static int setThreadSocketStatsTag(int tag) {
     55         final int old = threadSocketTags.get().statsTag;
     56         threadSocketTags.get().statsTag = tag;
     57         return old;
     58     }
     59 
     60     public static int getThreadSocketStatsTag() {
     61         return threadSocketTags.get().statsTag;
     62     }
     63 
     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
     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 
     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
     98     public void untag(FileDescriptor fd) throws SocketException {
     99         if (LOGD) {
    100             Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
    101         }
    102         unTagSocketFd(fd);
    103     }
    104 
    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 
    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 
    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      */
    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 
    154     private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid);
    155     private static native int native_untagSocketFd(FileDescriptor fd);
    156     private static native int native_setCounterSet(int uid, int counterSetNum);
    157     private static native int native_deleteTagData(int tag, int uid);
    158 }
    159