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