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     public static int getThreadSocketStatsUid() {
     71         return threadSocketTags.get().statsUid;
     72     }
     73 
     74     @Override
     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 
     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
    102     public void untag(FileDescriptor fd) throws SocketException {
    103         if (LOGD) {
    104             Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
    105         }
    106         unTagSocketFd(fd);
    107     }
    108 
    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 
    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 
    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      */
    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 
    158     private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid);
    159     private static native int native_untagSocketFd(FileDescriptor fd);
    160     private static native int native_setCounterSet(int uid, int counterSetNum);
    161     private static native int native_deleteTagData(int tag, int uid);
    162 }
    163