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.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