• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
install()55     public static void install() {
56         SocketTagger.set(new NetworkManagementSocketTagger());
57     }
58 
setThreadSocketStatsTag(int tag)59     public static void setThreadSocketStatsTag(int tag) {
60         threadSocketTags.get().statsTag = tag;
61     }
62 
getThreadSocketStatsTag()63     public static int getThreadSocketStatsTag() {
64         return threadSocketTags.get().statsTag;
65     }
66 
setThreadSocketStatsUid(int uid)67     public static void setThreadSocketStatsUid(int uid) {
68         threadSocketTags.get().statsUid = uid;
69     }
70 
71     @Override
tag(FileDescriptor fd)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 
tagSocketFd(FileDescriptor fd, int tag, int uid)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
untag(FileDescriptor fd)95     public void untag(FileDescriptor fd) throws SocketException {
96         if (LOGD) {
97             Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
98         }
99         unTagSocketFd(fd);
100     }
101 
unTagSocketFd(FileDescriptor fd)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 
setKernelCounterSet(int uid, int counterSet)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 
resetKernelUidStats(int uid)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      */
kernelToTag(String string)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 
native_tagSocketFd(FileDescriptor fd, int tag, int uid)141     private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid);
native_untagSocketFd(FileDescriptor fd)142     private static native int native_untagSocketFd(FileDescriptor fd);
native_setCounterSet(int uid, int counterSetNum)143     private static native int native_setCounterSet(int uid, int counterSetNum);
native_deleteTagData(int tag, int uid)144     private static native int native_deleteTagData(int tag, int uid);
145 }
146