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